长时间用户,第一次发布海报,所以如果我在提出问题时出错,我很抱歉。我已经研究了几个小时了,我已经决定是时候问专家了。我也搜索了所有已经“回答”和工作的类似问题,这让我相信它们已经过时了。
我试图从稍后将在代码中使用的UITextview中获取抽头单词。例如,文本视图中有一段单词:
“最初的时间投资回报要小得多,因为他交易了公司汗水资产的前期成本,但潜在的长期支出要大得多”。
我希望能够点击一个词,例如'投资',并通过另一个功能来定义它。然而,只需点击该单词,就会导致程序崩溃,而且我没有收到轻敲的单词。
我实现了一个轻敲手势识别器:
let tap = UITapGestureRecognizer(target: self, action: #selector(tapResponse(_:)))
tap.delegate = self
tvEditor.addGestureRecognizer(tap)
然后编写了函数:2
func tapResponse(recognizer: UITapGestureRecognizer) {
let location: CGPoint = recognizer.locationInView(tvEditor)
let position: CGPoint = CGPointMake(location.x, location.y)
let tapPosition: UITextPosition = tvEditor.closestPositionToPoint(position)!
let textRange: UITextRange = tvEditor.tokenizer.rangeEnclosingPosition(tapPosition, withGranularity: UITextGranularity.Word, inDirection: 1)!
let tappedWord: String = tvEditor.textInRange(textRange)!
print("tapped word : %@", tappedWord)
}
理想情况下,这应该从Textview的抽头部分获取位置,通过获取.x&amp ;,取得位置。 .y,然后在最接近位置的位置浏览Textview,找到包含粒度位置的范围(以返回单词),并设置内容作为一个字符串,我目前只是打印到控制台。但是,在点击这个词时,我收到了这次崩溃。3
以及“致命错误:在解除控制台中的”可选值“时意外发现nil。
非常感谢任何帮助。我可能只是遗漏了一些简单的东西,或者它可能会复杂得多。
答案 0 :(得分:3)
TextView
返回的tapPosition可以为nil nil
。?
的新运算符,它告诉编译器变量可能有nil值。如果在变量名称之后没有使用?
,则表明该变量永远不会为零值。!
运算符意味着您强制编译器强制从可选变量中提取值。因此,在这种情况下,如果变量的值为nil,它将在强制时崩溃。所以,实际发生的是
let tapPosition: UITextPosition
,let textRange: UITextRange
并且let tappedWord: String
不是可选的myTextView.closestPositionToPoint(position)
的返回类型,tvEditor.textInRange(textRange)
是可选变量UITextPosition?
,String?
!
nil
,并且您强制它获取值!
导致 CRASH 你能做什么
在强制使用任何可选变量之前,请确保使用
确定它有一些值if variable != nil
{
print(variable!)
}
正确的方法是
func tapResponse(recognizer: UITapGestureRecognizer) {
let location: CGPoint = recognizer.locationInView(myTextView)
let position: CGPoint = CGPointMake(location.x, location.y)
let tapPosition: UITextPosition? = myTextView.closestPositionToPoint(position)
if tapPosition != nil {
let textRange: UITextRange? = myTextView.tokenizer.rangeEnclosingPosition(tapPosition!, withGranularity: UITextGranularity.Word, inDirection: 1)
if textRange != nil
{
let tappedWord: String? = myTextView.textInRange(textRange!)
print("tapped word : ", tappedWord)
}
}
}
答案 1 :(得分:3)
Swift 3.0答案 - 截至2016年7月1日工作
在我的ViewDidLoad() -
中我使用之前VC中的文本,因此我的变量“theText”已经被声明。我添加了一个已经注明的示例字符串。
//Create a variable of the text you wish to attribute.
let textToAttribute = theText // or "This is sample text"
// Break your string in to an array, to loop through it.
let textToAttributeArray = textToAttribute.componentsSeparatedByString(" ")
// Define a variable as an NSMutableAttributedString() so you can append to it in your loop.
let attributedText = NSMutableAttributedString()
// Create a For - In loop that goes through each word your wish to attribute.
for word in textToAttributeArray{
// Create a pending attribution variable. Add a space for linking back together so that it doesn't looklikethis.
let attributePending = NSMutableAttributedString(string: word + " ")
// Set an attribute on part of the string, with a length of the word.
let myRange = NSRange(location: 0, length: word.characters.count)
// Create a custom attribute to get the value of the word tapped
let myCustomAttribute = [ "Tapped Word:": word]
// Add the attribute to your pending attribute variable
attributePending.addAttributes(myCustomAttribute, range: myRange)
print(word)
print(attributePending)
//append 'attributePending' to your attributedText variable.
attributedText.appendAttributedString(attributePending) ///////
print(attributedText)
}
textView.attributedText = attributedText // Add your attributed text to textview.
现在我们将添加一个水龙头手势识别器来注册水龙头。
let tap = UITapGestureRecognizer(target: self, action: #selector(HandleTap(_:)))
tap.delegate = self
textView.addGestureRecognizer(tap) // add gesture recognizer to text view.
现在我们在viewDidLoad()
下声明一个函数func HandleTap(sender: UITapGestureRecognizer) {
let myTextView = sender.view as! UITextView //sender is TextView
let layoutManager = myTextView.layoutManager //Set layout manager
// location of tap in myTextView coordinates
var location = sender.locationInView(myTextView)
location.x -= myTextView.textContainerInset.left;
location.y -= myTextView.textContainerInset.top;
// character index at tap location
let characterIndex = layoutManager.characterIndexForPoint(location, inTextContainer: myTextView.textContainer, fractionOfDistanceBetweenInsertionPoints: nil)
// if index is valid then do something.
if characterIndex < myTextView.textStorage.length {
// print the character index
print("Your character is at index: \(characterIndex)") //optional character index.
// print the character at the index
let myRange = NSRange(location: characterIndex, length: 1)
let substring = (myTextView.attributedText.string as NSString).substringWithRange(myRange)
print("character at index: \(substring)")
// check if the tap location has a certain attribute
let attributeName = "Tapped Word:" //make sure this matches the name in viewDidLoad()
let attributeValue = myTextView.attributedText.attribute(attributeName, atIndex: characterIndex, effectiveRange: nil) as? String
if let value = attributeValue {
print("You tapped on \(attributeName) and the value is: \(value)")
}
}
}
答案 2 :(得分:2)
除了@AmitSingh的回答,这是更新的Swift 3.0版本:
func didTapTextView(recognizer: UITapGestureRecognizer) {
let location: CGPoint = recognizer.location(in: textView)
let position: CGPoint = CGPoint(x: location.x, y: location.y)
let tapPosition: UITextPosition? = textView.closestPosition(to: position)
if tapPosition != nil {
let textRange: UITextRange? = textView.tokenizer.rangeEnclosingPosition(tapPosition!, with: UITextGranularity.word, inDirection: 1)
if textRange != nil
{
let tappedWord: String? = textView.text(in: textRange!)
print("tapped word : ", tappedWord!)
}
}
}
其他代码与他的代码相同。
希望它有所帮助!