Другим случаем, когда NullReferenceExceptions
может случиться, является (неправильное) использование оператора as
:
class Book {
public string Name { get; set; }
}
class Car { }
Car mycar = new Car();
Book mybook = mycar as Book; // Incompatible conversion --> mybook = null
Console.WriteLine(mybook.Name); // NullReferenceException
Здесь Book
и Car
являются несовместимыми типами; a Car
не может быть преобразован / передан в Book
. Когда этот сбой завершается неудачно, as
возвращает null
. Используя mybook
после этого, вы вызываете NullReferenceException
.
В общем случае вы должны использовать cast или as
, как показано ниже:
Если вы ожидаете преобразования типа в всегда преуспевает (т. е. вы знаете, какой объект должен быть впереди времени), тогда вы должны использовать cast:
ComicBook cb = (ComicBook)specificBook;
Если вы не уверены в типе, но хотите попробовать , чтобы использовать его как определенный тип, затем используйте as
:
ComicBook cb = specificBook as ComicBook;
if (cb != null) {
// ...
}
Обновление: из ios10 ,
- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange interaction:(UITextItemInteraction)interaction;
Из ios7 и позже UITextView
имеет метод делегирования:
- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange *NS_DEPRECATED_IOS(7_0, 10_0, "Use textView:shouldInteractWithURL:inRange:forInteractionType: instead");*
, чтобы перехватить клики по ссылкам. И это лучший способ сделать это.
Для ios6 и ранее хорошим способом сделать это является подклассификация UIApplication
и перезапись -(BOOL)openURL:(NSURL *)url
@interface MyApplication : UIApplication {
}
@end
@implementation MyApplication
-(BOOL)openURL:(NSURL *)url{
if ([self.delegate openURL:url])
return YES;
else
return [super openURL:url];
}
@end
Вам нужно будет реализовать openURL:
в вашем делегате.
Теперь, чтобы запустить приложение с вашим новым подклассом UIApplication
, найдите файл main.m в своем проекте. В этом маленьком файле, который загружает ваше приложение, обычно есть эта строка:
int retVal = UIApplicationMain(argc, argv, nil, nil);
Третий параметр - это имя класса для вашего приложения. Итак, заменив эту строку на:
int retVal = UIApplicationMain(argc, argv, @"MyApplication", nil);
Это сделало трюк для меня.
application:handleOpenURL:
вызывается, когда другое приложение открывает ваше приложение, открывая URL-адрес с помощью схемы, поддерживаемой вашим приложением. Это не называется, когда ваше приложение начинает открывать URL.
Я думаю, что единственный способ сделать то, что хочет Владимир, - это использовать UIWebView вместо UITextView. Сделайте свой контроллер представления UIWebViewDelegate, установите делегат UIWebView на контроллер представления, а в контроллере представления реализуйте webView:shouldStartLoadWithRequest:navigationType:
, чтобы открыть [request URL]
в представлении вместо того, чтобы выйти из приложения и открыть его в Mobile Safari.
Быстрая версия:
Ваша стандартная настройка UITextView должна выглядеть примерно так: не забудьте делегат и dataDetectorTypes.
var textView = UITextView(x: 10, y: 10, width: CardWidth - 20, height: placeholderHeight) //This is my custom initializer
textView.text = "dsfadsaf www.google.com"
textView.selectable = true
textView.dataDetectorTypes = UIDataDetectorTypes.Link
textView.delegate = self
addSubview(textView)
После окончания вашего класса добавьте эту часть:
class myVC: UIViewController {
//viewdidload and other stuff here
}
extension MainCard: UITextViewDelegate {
func textView(textView: UITextView, shouldInteractWithURL URL: NSURL, inRange characterRange: NSRange) -> Bool {
//Do your stuff over here
var webViewController = SVModalWebViewController(URL: URL)
view.presentViewController(webViewController, animated: true, completion: nil)
return false
}
}
С Swift 3 и i0S 10 самый простой способ взаимодействия с номерами телефонов, URL-адресами или адресами в UITextView
- использовать UIDataDetectorTypes
. В приведенном ниже коде показано, как отображать номер телефона в UITextView
, чтобы пользователь мог взаимодействовать с ним.
import UIKit
class ViewController: UIViewController {
// Link this outlet to a UITextView in your Storyboard
@IBOutlet weak var textView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
textView.text = "+33687654321"
textView.isUserInteractionEnabled = true // default: true
textView.isEditable = false // default: true
textView.isSelectable = true // default: true
textView.dataDetectorTypes = [.phoneNumber]
}
}
С помощью этого кода при нажатии на номер телефона UIAlertController
будет pop.
В качестве альтернативы вы можете использовать NSAttributedString
:
import UIKit
class ViewController: UIViewController {
// Link this outlet to a UITextView in your Storyboard
@IBOutlet weak var textView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
let phoneUrl = NSURL(string: "tel:+33687654321")! // "telprompt://+33687654321" also works
let attributes = [NSLinkAttributeName: phoneUrl]
let attributedString = NSAttributedString(string: "phone number", attributes: attributes)
textView.attributedText = attributedString
textView.isUserInteractionEnabled = true // default: true
textView.isEditable = false // default: true
textView.isSelectable = true // default: true
}
}
С помощью этого кода при нажатии на атрибут строка, появится UIAlertController
.
Однако вы можете выполнить некоторые пользовательские действия вместо того, чтобы всплывать UIAlertController
, когда вы нажимаете на номер телефона. Или вы можете захотеть, чтобы UIAlertController
всплывал и выполнял ваше собственное действие в одно и то же время.
В обоих случаях вам нужно будет сделать ваш UIViewController
совместимым с UITextViewDelegate
протоколом и реализовать textView(_:shouldInteractWith:in:interaction:)
. Код ниже показывает, как это сделать.
import UIKit
class ViewController: UIViewController, UITextViewDelegate {
// Link this outlet to a UITextView in your Storyboard
@IBOutlet weak var textView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
textView.delegate = self
textView.text = "+33687654321"
textView.isUserInteractionEnabled = true
textView.isEditable = false
textView.isSelectable = true
textView.dataDetectorTypes = [.phoneNumber]
}
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
/* perform your own custom actions here */
print(URL)
return false // return true if you still want UIAlertController to pop up
}
}
С помощью этого кода при нажатии на номер телефона не появится UIAlertController
, и вместо этого вы получите следующую распечатку в консоли:
tel: +33687654321
blockquote>
Swift 4:
1) Создайте следующий класс (подклассифицированный UITextView):
import Foundation
protocol QuickDetectLinkTextViewDelegate: class {
func tappedLink()
}
class QuickDetectLinkTextView: UITextView {
var linkDetectDelegate: QuickDetectLinkTextViewDelegate?
override init(frame: CGRect, textContainer: NSTextContainer?) {
super.init(frame: frame, textContainer: textContainer)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
let glyphIndex: Int? = layoutManager.glyphIndex(for: point, in: textContainer, fractionOfDistanceThroughGlyph: nil)
let index: Int? = layoutManager.characterIndexForGlyph(at: glyphIndex ?? 0)
if let characterIndex = index {
if characterIndex < textStorage.length {
if textStorage.attribute(NSLinkAttributeName, at: characterIndex, effectiveRange: nil) != nil {
linkDetectDelegate?.tappedLink()
return self
}
}
}
return nil
}
}
2) Где бы вы не настроили текстовое представление, сделайте следующее:
//init, viewDidLoad, etc
textView.linkDetectDelegate = self
//outlet
@IBOutlet weak var textView: QuickDetectLinkTextView!
//change ClassName to your class
extension ClassName: QuickDetectLinkTextViewDelegate {
func tappedLink() {
print("Tapped link, do something")
}
}
Если вы используете раскадровку, убедитесь, что ваше текстовое изображение выглядит так: инспектор прав:
Voila! Теперь вы сразу же получаете ссылку, а не когда URL должен использовать метод URL-адреса
Не знаете, как вы могли бы перехватить обнаруженную ссылку на данные или какую функцию вам нужно выполнить. Но вы можете использовать метод didFeginEditing TextField для запуска теста / сканирования через текстовое поле, если вы знаете, что вы ищете ... как сравнение текстовых строк, которые соответствуют формату ### - ### - ####, или начать с "www." чтобы захватить эти поля, но вам нужно написать небольшой код, чтобы обнюхать строку текстовых полей, пересоздать то, что вам нужно, а затем извлечь его для использования вашей функции. Я не думаю, что это было бы так сложно, как только вы сузили именно то, что вы хотели, а затем сосредоточили внимание на том, что ваш оператор if () фильтрует до очень специфического соответствия шаблону того, что вам нужно.
Из-за этого подразумевается, что пользователь коснется текстового поля, чтобы активировать didBeginEditing (). Если это не тот тип взаимодействия с пользователем, который вы искали, вы могли бы просто использовать триггерный таймер, который начинается с ViewDidAppear () или другого на основе потребности и проходит через строку текстовых полей, а затем в конце вы пробегаете строку текстового поля методы, которые вы создали, вы просто отключите Таймер.
У меня динамический контент в текстовом представлении, который может содержать ссылку. Функция shouldInteractWithURL вызывается только тогда, когда пользователь долго нажимает на ссылку, но не нажимает на ссылку. Переадресуйте, если какой-либо приятель ссылается на него.
Ниже приведен код снайпера.
UITextView *ltextView = [[UITextView alloc] init];
[ltextView setScrollEnabled:YES];
[ltextView setDataDetectorTypes:UIDataDetectorTypeLink];
ltextView.selectable = YES;
[ltextView setEditable:NO];
ltextView.userInteractionEnabled = YES;
ltextView.delegate = (id)self;
ltextView.delaysContentTouches = NO;
[self.view addsubview:ltextview];
- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange{
[self.mActionDelegate userClickedOnImageLinkFromWebview:URL];
NSLog(@"urls is :- %@",URL);
return FALSE;
}
Вышеупомянутый метод делегата не получает вызов по крану.
С уважением, Рохит Янкар
В iOS 7 или более поздней версии
Вы можете использовать следующий делегат UITextView. Метод:
- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange
Текстовое представление вызывает этот метод, если пользователь нажимает или долго нажимает на URL ссылка. Реализация этого метода является необязательной. По умолчанию текстовое представление открывает приложение, ответственное за обработку URL-типа и передает ему URL-адрес. Вы можете использовать этот метод для запуска альтернативного действия, такого как отображение веб-контента по URL-адресу в веб-представлении в текущем приложении.
Важно:
Ссылки в текстовые представления интерактивны только в том случае, если текстовое представление выбирается, но не редактируется. То есть, если значение UITextView выбираемого свойства равно YES, а свойство isEditable равно NO.
blockquote>
UIWebView
, если хотите сделать ссылку на другой текст i>, а не сам URL. Тег <a>
по-прежнему остается лучшим способом в этом случае.
– Matt Quiros
27 February 2014 в 09:56
Для Swift 3
textView.delegate = self
extension MyTextView: UITextViewDelegate
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange) -> Bool {
GCITracking.sharedInstance.track(externalLink: URL)
return true
}
}
или если цель равна> = IOS 10
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool
Я сам этого не пробовал, но вы можете попробовать реализовать метод application:handleOpenURL:
в делетете приложения - похоже, что все запросы openURL
проходят через этот обратный вызов.
UIApplication
и заменить реализацию openURL. Хотя таким образом сложно (но не невозможно) ссылаться на первоначальную реализацию. – mxcl 6 December 2010 в 14:01