Segmentation Fault 11 when running Swift app - ios

I have just updated to the newest Xcode 6.3 beta and I am receiving an error that I can't figure out the solution to.
When I run my app, I am getting the error: Command failed due to signal: Segmentation Fault 11. I had a look through the full error message and I have taken the parts out that I think are relevant:
(unresolved_dot_expr type='#lvalue String!' location=/Filename/FifthViewController.swift:423:19 range=[/Filename/FifthViewController.swift:423:9 - line:423:19] field 'text'
(declref_expr type='UITextField' location=/Filename/FifthViewController.swift:423:9 range=[/Filename/FifthViewController.swift:423:9 - line:423:9] decl=AffordIt.(file).FifthViewController.func decl.textField#/Filename/FifthViewController.swift:418:34 specialized=yes))
And
While emitting SIL for 'textFieldDidChangeValue' at /Filename/FifthViewController.swift:418:5
Anyone have any ideas? Obviously I've replaced the full path with 'Filename'. This is the code related to the error:
textField.addTarget(self, action: "textFieldDidChangeValue:", forControlEvents: UIControlEvents.EditingChanged)
func textFieldDidChangeValue(textField: UITextField) {
//Automatic formatting for transaction value text field. Target is added above.
var text = textField.text.stringByReplacingOccurrencesOfString(currencyFormatter.currencySymbol!, withString: "").stringByReplacingOccurrencesOfString(currencyFormatter.groupingSeparator, withString: "").stringByReplacingOccurrencesOfString(currencyFormatter.decimalSeparator!, withString: "").stringByReplacingOccurrencesOfString(" ", withString: "") // There is a special character here. This line is critical for european/other currencies.
println(textField.text)
textField.text = currencyFormatter.stringFromNumber((text as NSString).doubleValue / 100.0)
currencyDouble = (text as NSString).doubleValue / 100.0
valueEnter.alpha = 1
}
Here is the initialisation of currencyFormatter:
let currencyFormatter = NSNumberFormatter()
currencyFormatter.numberStyle = NSNumberFormatterStyle.CurrencyStyle
if let currencyCode = NSLocale.currentLocale().objectForKey(NSLocaleCurrencyCode) as? String {
currencyFormatter.currencyCode = currencyCode
}

It seems, the problem is in this line:
textField.text = currencyFormatter.stringFromNumber((text as NSString).doubleValue / 100.0)
It must be a compiler bug. The workarounds I found are:
// Explicitly cast as `NSNumber`
textField.text = currencyFormatter.stringFromNumber((text as NSString).doubleValue / 100.0 as NSNumber)
// or explicitly construct `NSNumber` from `Double`
textField.text = currencyFormatter.stringFromNumber(NSNumber(double: (text as NSString).doubleValue / 100.0))
// or prepare `Double` outside
let doubleVal = (text as NSString).doubleValue / 100.0
textField.text = currencyFormatter.stringFromNumber(doubleVal)
// or convert `String` to `Double` without casting to `NSString`.
textField.text = currencyFormatter.stringFromNumber( atof(text) / 100.0)
The minimum code that reproduces this problem would be:
let str = "42"
let a:NSNumber = (str as NSString).doubleValue / 100.0
Swift 1.1/Xcode 6.1.1 compiles it successfully, but Swift 1.2/Xcode 6.3 Beta2 crashes.

This might be a long shot, but how is your currencyFormatter declared? Is it marked with an ! and not intialised? I used the following code to test for a faulty declaration and it behaved rather strangely in my Swift iOS Playground:
var myTextField = UITextField()
var currencyFormatter : NSNumberFormatter! // Possible offender! Not initiliased, and forcefully unwrapped!!!
func myFunc(textField: UITextField) {
//Automatic formatting for transaction value text field. Target is added above.
var text : String = textField.text // Error: Execution was interrupted, reason: EXC_BAD_INSTRUCTION
//if currencyFormatter != nil {
text = textField.text
.stringByReplacingOccurrencesOfString(currencyFormatter.currencySymbol!, withString: "")
.stringByReplacingOccurrencesOfString(currencyFormatter.groupingSeparator, withString: "")
.stringByReplacingOccurrencesOfString(currencyFormatter.decimalSeparator!, withString: "")
.stringByReplacingOccurrencesOfString(" ", withString: "") // There is a special character here. This line is critical for european/other currencies.
println("original: \(textField.text), after replacing: \(text)")
textField.text = currencyFormatter.stringFromNumber((text as NSString).doubleValue / 100.0)
println("new: \(textField.text)")
// currencyDouble = (text as NSString).doubleValue / 100.0
// valueEnter.alpha = 1
// } else {
// println("No currencyFormatter")
// }
}
//currencyFormatter = NSNumberFormatter()
// Uncomment line above, and the playground failed on second line in myFunc()
myTextField.text = "$123.000,00"
myFunc(myTextField)
myTextField.text
If this is your case as well, you need to look into the missing initialisation of the currencyFormatter, and also uncomment the if statements from my code excerpt to avoid it crashing everything. If uncommenting, you'll also see if this is the actual error case for you as there is an else clause stating that the currencyFormatter actually is nil.
The reason for me looking into this case, was to see if you had a problem with unwrapping of currencyFormatter.currencySymbol! and currencyFormatter.decimalSeparator!, but testing revealed they could be nil without casing any other issue than text == "".
You might also want to look into the NSNumberFormatter.numberFromString() method, see following:
var currencyFormatter = NSNumberFormatter()
currencyFormatter.numberStyle = NSNumberFormatterStyle.CurrencyStyle
if let numberStr = currencyFormatter.stringFromNumber(NSNumber(double: 123567.45)) {
if let number = currencyFormatter.numberFromString(numberStr) {
println("numberStr = \(numberStr) vs number = \( number )")
}
}
which outputs numberStr = $123,567.45 vs number = 123567.45 after converting back and forth.

I had the same problem here and it was not related to the code itself. all of them disappeared after upgrading to Xcode 6.3 beta 2 released by Apple two days ago. give it a try

Related

iOS speech to text conversion in number format

Currently I'm using default iOS speech to text conversion without adding any code for it. When the user says 'five', it is displayed as 'five' or '5'. But, I need it to be converted as '5' always. Is there anything I can do with SFSpeechRecognizer or any other way to achieve this?
This can get you started, but it is not able to handle mixed strings that contain a number AND a non-number. Ideally, you would need to process each word as it comes through, but then that has potential effects for combined numbers (thirty four) for example.
let fiveString = "five"
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .spellOut
print(numberFormatter.number(from: fiveString)?.stringValue) // 5
let combinedString = "five dogs"
print(numberFormatter.number(from: combinedString)?.stringValue) // nil
let cString = "five hundred"
print(numberFormatter.number(from: cString)?.stringValue) // 500
let dString = "five hundred and thirty-seven"
print(numberFormatter.number(from: dString)?.stringValue) // 537
You could try to build a simple string extention like so:
extension String {
var byWords: [String] {
var byWords:[String] = []
enumerateSubstrings(in: startIndex..<endIndex, options: .byWords) {
guard let word = $0 else { return }
byWords.append(word)
}
return byWords
}
func wordsToNumbers() -> String {
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .spellOut
let formattedString = self.byWords.map {
return numberFormatter.number(from: $0)?.stringValue ?? $0
}
return formattedString.joined(separator: " ")
}
}
This is a untested (not run / performance not checked) example

Formatter issue when language changed in device

I'm trying to get float number from amount string with out currency symbol like "100.00". Its working properly in English language. When language changed to German in device, its behaviour is getting changed. How can I achieve float value with out affecting by language change in device.
func getFloatNumberFromString(_ str: String) -> Float {
guard let number = NumberFormatter().number(from: str) else {
return 0.0
}
return number.floatValue
}
another piece of below code to deal with it:
func removeFormatAmount() -> Double {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
return formatter.number(from: self) as! Double? ?? 0
}
When I use second method then the output is coming as 0.
Please let me know what am I missing or suggest me to deal with it.
Thanks in advance
In many European countries the decimal separator is a comma rather than a dot.
You could set the Locale of the formatter to a fixed value.
func float(from str: String) -> Float {
let formatter = NumberFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
guard let number = formatter.number(from: str) else {
return 0.0
}
return number.floatValue
}
PS: I changed the signature to fit the Swift 3+ style
Did you try to cast directly? Like this.
let floatString = "12.34"
let number = Double(floatString) ?? 0.0

Search and extract substring in Swift 3

Relatively new to Swift programming.
I get an dictionary from which I need to get the user name (first and last name) and display it in table view cell along with other data.
On iPhone 5 and below as the screen width is only 320, the requirement is to just display the first name and first character of the last name.
E.g: "Howard Mark" to "Howard M"
I am sure that there is an elegant way to extract the required string.
struct ScreenSize
{
static let SCREEN_WIDTH = UIScreen.main.bounds.size.width
static let SCREEN_HEIGHT = UIScreen.main.bounds.size.height
static let SCREEN_MAX_LENGTH = max(ScreenSize.SCREEN_WIDTH, ScreenSize.SCREEN_HEIGHT)
static let SCREEN_MIN_LENGTH = min(ScreenSize.SCREEN_WIDTH, ScreenSize.SCREEN_HEIGHT)
}
struct DeviceType
{
static let IS_IPHONE_5_OR_LESS = (UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.SCREEN_MAX_LENGTH <= 568.0)
}
func functionCall (referralData:[String: Any?])
{
var myMutableString = NSMutableAttributedString()
if var nameString = referralData[KEY_FULL_NAME]
{
if DeviceType.IS_IPHONE_5_OR_LESS
{
var a = nameString as? NSString
var arr = a?.components(separatedBy: " ")
let newStr = arr?[0] as? String
nameString = newStr
if((arr?.count)! > 1)
{
if let secondString = arr?[1]
{
let newStr2 = newStr as? NSString
let secondChar = newStr2?.character(at: 0)
let stringchar:String! = String(secondChar!)
nameString = "\(newStr!) \(stringchar)"
}
}
print("iPhone 5 or less")
}
else
{
print("Greater than iPhone 5")
}
}
}
I don't think anyone should be thinking in Swift 3 any more. Here's a Swift 4 example:
var name = "Veeblefetzer Rumplestiltskin"
if let r = name.range(of: " ", options: .backwards, range: name.startIndex..<name.endIndex) {
name = String(name[name.startIndex..<name.index(r.upperBound, offsetBy: 1)])
}
name // "Veeblefetzer R"
maybe like this?
let fullName = "Dominik Pich"
var parts = fullName.components(separatedBy: " ")
if parts.count > 0,
let lastNameInitial = parts.last?.prefix(1) {
parts[parts.count-1] = String(lastNameInitial)
}
let truncatedName = parts.joined(separator: " ")
//use
print("fullName: \(fullName)")
print("truncatedName: \(truncatedName)")
I'd wrap it in a nice String extension - e.g. a computed property truncateLast
The most helpful answer I've found when using Swift's built in substring command is here: https://stackoverflow.com/a/39677331/5495979
Although, using the substring command still requires you to first obtain a range or an index, so it still requires a couple commands to implement.
So Using my preferred method from the SO answer referenced above I would just grab the index of the first character and use the substring command and cast it to a string:
let index = secondString.index(secondString.startIndex, offsetBy: 0)
let stringChar = String(secondString.substring(to: index))
I also wanted to let you know that there appears to be a logic error in your code when obtaining the first letter of the last name. You unwrap what should be the last name in your string components array with if let secondString = arr?[1] but then don't assign the unwrapped string stored in secondString to newStr2 before parsing newStr2 for the first character in the string. As it appears now when you parse the first character of the string with let secondChar = newStr2?.character(at: 0) you will actually be parsing the first character from the first name (since when assigning newStr2 with let newStr2 = newStr as? NSString you are actually assigning the fist entry from the array of name strings since newStr is only assinged with let newStr = arr?[0] as? String)

Decimal number in text field

I'm trying to get a decimal number from a text field. It only can be a decimal number but if I enter something like 'o,5', than the bullets will spawn a lot faster than every 0.5 second.
My code:
#IBAction func enemyBulletDelayClick(_ sender: AnyObject) {
dismissKeyboard()
let correctNumber = enemyBulletDelayText.text?.replacingOccurrences(of: ",", with: ".")
enemyBulletDelay = Double(correctNumber!)!
enemyBulletDelayText.text = ""
}
(I'm converting each ',' to a '.' for the decimal numbers.)
Otherwise it would give me an error.
I tried to use this code and it worked!
Code:
let formatter = NumberFormatter()
formatter.numberStyle = NumberFormatter.Style.decimal
enemySpawnDelay = (formatter.number(from: enemySpawnDelayText.text!)?.doubleValue)!
If you have a ? you need to unwrap, not put !
There are a bunch of ways to remove . afterwards. Pick whatever you want. This is more focused on the process of what you're doing and then you can decide on using NSNumberFormatter or whatever you want to do.
guard let enemyBulletDelayString = enemyBulletDelayText.text? else {
//put whatever you want to do here if this check doesn't pass
return
}
let numberFormatter = NumberFormatter()
formatter.numberStyle = numberFormatter.Style.decimal
if let formattedNumber = numberFormatter.number(from: enemyBulletDelayString) {
enemySpawnDelay = formattedNumber.doubleValue
} else {
numberFormatter.decimalSeparator = ","
if let formattedNumber = numberFormatter.number(from: enemyBulletDelayString) {
enemySpawnDelay = formattedNumber.doubleValue
}
}
This should work with what you want to do.

Swift - Textview Identify Tapped Word Not Working

Long time user, first time poster, so my apologies if I make any errors in presenting my question. I have been working on this for hours and I've decided it is time to ask the experts. I have also searched through every similar question that has been "answered" and work, which leads me to believe they are outdated.
I am attempting to grab the tapped word from a UITextview that would be used later in the code. For example, there is a paragraph of words in the text view:
"The initial return on time investment is much smaller, due to him trading his upfront cost for sweat-equity in the company, but the potential long-term payout is much greater".
I would want to be able to tap on a word, e.g. 'investment', and run it through another function to define it. However simply tapping the word, crashes the program, and I do not receive the word tapped.
I implemented a tap gesture recognizer:
let tap = UITapGestureRecognizer(target: self, action: #selector(tapResponse(_:)))
tap.delegate = self
tvEditor.addGestureRecognizer(tap)
and then wrote the function: 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)
}
Ideally, this should take the location from the tapped part of the Textview, take the position by taking the .x & .y, and then looking through the Textview at the point closest to the position, finding the Range enclosing the position with granularity (to return the word), and setting the contents as a String, which I am currently just printing to the console. However, on tapping the word, I receive this crash.3
along with "fatal error: unexpectedly found nil while unwrapping an Optional value" in the console.
Any help would be greatly appreciated. I may just be missing something simple, or it could be much more complicated.
Whenever the tapped received at the blank spaces between the words, tapPosition returned by the TextView can be nil nil.
Swift has new operator called optional ? which tells the compiler that the variable may have nil value. If you do not use ? after the variable name indicates that the variable can never have nil value.
In Swift, using ! operator means you are forcing the compiler to forcefully extract the value from the optional variable. So, in that case, if the value of the variable is nil, it will crash on forcing.
So, what is actually happening is
You are creating the variable let tapPosition: UITextPosition, let textRange: UITextRange and let tappedWord: String are not optional
return type of the method myTextView.closestPositionToPoint(position), tvEditor.textInRange(textRange) are optional variable UITextPosition?, String?
Assigning a value of optional variable to non optional variable requires !
The method is returning nil and you are forcing it to get the value ! lead to CRASH
What you can do
Before forcing any optional variable, just be sure that it has some value using
if variable != nil
{
print(variable!)
}
Correct method would be as
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)
}
}
}
Swift 3.0 Answer - Working as of July 1st, 2016
In my ViewDidLoad() -
I use text from a previous VC, so my variable "theText" is already declared. I included a sample string that has been noted out.
//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.
Now we will add a tap gesture recognizer to register taps.
let tap = UITapGestureRecognizer(target: self, action: #selector(HandleTap(_:)))
tap.delegate = self
textView.addGestureRecognizer(tap) // add gesture recognizer to text view.
Now we declare a function under the 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)")
}
}
}
In addition to #AmitSingh answer, this is updated Swift 3.0 version:
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!)
}
}
}
The other code is the same as his.
Hope it helps!

Resources