How do I convert an NSString to an integer using Swift? - ios

I need to convert an NSString to an integer in Swift: Here's the current code I'm using; it doesn't work:
var variable = (NSString(data:data, encoding:NSUTF8StringEncoding))
exampeStruct.otherVariable = (variable).intValue
Variable is a normal varable, and exampleStruct is a struct elsewhere in the code with a subvariable otherVariable.
I expect it to set exampleStruct.otherVariable to an int value of the NSString, but I get the following error:
"Cannot convert the expression's type () to type Float"
How do I convert an NSString to int in Swift?

It looks to me like the problem might not be the Int conversion, but rather that the exampleStruct is expecting a Float.
If that's not the issue however (and granted, Xcode errors for Swift often seem to be more about the line number rather than about the actual problem) then something like this should work for you?
var ns:NSString = "1234"
if let i = (ns as String).toInt() {
exampleStruct.otherVariable = i
}

I know you already got your answer, but I just want to explain what (I think) might not be trivial
First, we have some NSData we want to convert to NSString, because no one guaranties the data is a valid UTF8 buffer, it return an optional
var variable = NSString(data:data, encoding:NSUTF8StringEncoding)
Which means variable: NSString?
Usually NSString is bridged to swift's String, but in this case, we use an NSString constructor - you can think about it more as a "Foundation"-like syntax that wasn't directly imported to swift (as there's no bridge for NSData)
we can still use the 'Foundation' way with NSString
if let unwrappedVariable = variable {
var number = unwrappedVariable.intValue
}
if number is a Float, but the string is a string representation of an integer
if let unwrappedVariable = variable {
var number: Float = Float(unwrappedVariable.intValue)
}
if both number and the string (representation of) are floats:
if let unwrappedVariable = variable {
var number:Float = unwrappedVariable.floatValue
}
Anyway, there's a small problem with using Foundation. For these types of conversions it has no concept of an optional value (for int, float). It will return 0 if it cannot parse a string as and integer or float. That's why it's better to use swift native String:
if let variable: String = NSString(data: data, encoding: NSUTF8StringEncoding) {
if let integer = variable.toInt() {
var integerNumber = integer
var floatNumber = Float(integer)
}
}

edit/update:
No need to use NSString when coding with Swift. You can use Swift native String(data:) initializer and then convert the string to Int:
if let variable = String(data: data, encoding: .utf8),
let integer = Int(variable) {
exampeStruct.otherVariable = integer
}
If other variable is a Float type:
if let variable = String(data: data, encoding: .utf8),
let integer = Float(variable) {
exampeStruct.otherVariable = integer
}

Related

Rounding up/down FLOATS to INTS in alphanumeric NSString

I'm stuck on this one —
I have an alphanumeric NSString. The numbers in the string contain multiple decimals and I would like to round out those numbers to integers.
The string looks like this:
VALUES: A:123.45678 B:34.55789 C:2.94567
and I'm trying to use this code:
[self log:[NSString stringWithFormat:#"VALUES: %.f\n", values.toString]];
to convert to this:
VALUES: A:123 B:35 C:3
Xcode offers this warning —
Format specifies type 'double' but the argument has type 'NSString *'
Replace '%.1f' with '%#'
I think I need a different way of "scanning" the string, identifying the numbers and doing the rounding up/down as needed, then turning that into a new string. I'm just failing miserably with every attempt.
Any help will be appreciated.
I like NSScanner for this sort of thing. Here's a Swift solution; sorry, I'm too lazy to translate it into Objective-C, which is a little more indirect:
let s = "VALUES: A:123.45678 B:34.55789 C:2.94567"
let sc = Scanner(string:s)
sc.charactersToBeSkipped = nil
var arr = [String]()
while (true) {
if let prefix = sc.scanUpToCharacters(from: .decimalDigits) {
arr.append(prefix)
} else { break }
if let num = sc.scanDouble() {
let rounded = num.rounded()
arr.append(String(Int(rounded)))
} else { break }
}
let result = arr.joined()
print(result) // "VALUES: A:123 B:35 C:3"

Swift convert Data to UnsafeMutablePointer<Int8>

I'm calling a function in an objective c class from swift.
-(char *)decrypt:(char *)crypt el:(int)el{}
when calling this function from swift, it asks for an UnsafeMutablePointer<Int8> as the value for the parameter 'crypt'
the value for the 'crypt' is comming from a server and it is a base64encoded string. So I decode that string and got a Data object.
let resultData = Data(base64Encoded: base64String)
Now I need to pass this data to the above mentioned function. I have tried to convert this Data object to a UnsafeMutablePointer<Int8>
resultData?.withUnsafeBytes { (u8Ptr: UnsafeMutablePointer<Int8>) in
let decBytes = tea?.decrypt(u8Ptr , el: el)}
But it is not compiling. Gives below error
'UnsafeMutablePointer' is not convertible to 'UnsafePointer<_>'
I don't know much about objective c. So could anyone help me to pass this parameter to objective c function.
you have to change UnsafeMutablePointer to UnsafePointer
UnsafePointer
resultData?.withUnsafeBytes {(bytes: UnsafePointer<CChar>)->Void in
//Use `bytes` inside this closure
}
UnsafeMutablePointer
var data2 = Data(capacity: 1024)
data2.withUnsafeMutableBytes({ (bytes: UnsafeMutablePointer<UInt8>) -> Void in
//Use `bytes` inside this closure
})
Edit, updated my answer for two things:
Not returning the pointer from withUnsafeBytes
Accounting for Swift 5' deprecation warning: 'withUnsafeBytes' is deprecated: use withUnsafeBytes<R>(_: (UnsafeRawBufferPointer) throws -> R) rethrows -> R instead
// buffer pointer captured is converted to byte pointer which is used in the block to decode the base64 encoded Data
encodedStringData.withUnsafeMutableBytes { (rawBufferPtr: UnsafeMutableRawBufferPointer) in
if let rawPtr = rawBufferPtr.baseAddress {
let decodedString = String(bytesNoCopy: rawPtr, length: rawBufferPtr.count, encoding: .utf8, freeWhenDone: false)
print(decodedString!)
}
}
someData.withUnsafeBytes { (bufferRawPtr: UnsafeRawBufferPointer) in
// For converting an UnsafeRawBufferPointer to its typed variant, in this case UnsafeBufferPointer<UInt8>
let bufferTypedPtr = bufferRawPtr.bindMemory(to: UInt8.self)
// Then, getting the typed UnsafePointer, in this case UnsafePointer<UInt8>
let unsafePointer = bufferTypedPtr.baseAddress!
}
Note: Swift 5 doesn't allow you to access encodedStringData from within the withUnsafeMutableBytes block! Read Swift 5 Exclusivity Enforcement for why.
Capturing the pointer outside of the block is apparently not recommended, it works but the behavior can get to be undefined in the future
Old answer:
This will help someone looking for getting to the underlying raw bytes (in a UnsafeMutablePointer<UInt8> representation) of a Data object as a variable for further use (instead of having to write all of the logic in the withUnsafeMutableBytes block).
var encodedStringData = Data(base64Encoded: "Vmlub2QgaXMgZ3JlYXQh")!
// byte pointer variable used later to decode the base64 encoded Data
let rawPtr: UnsafeMutablePointer<UInt8> = encodedStringData.withUnsafeMutableBytes { (bytePtr: UnsafeMutablePointer<UInt8>) in bytePtr }
let decodedString = String(bytesNoCopy: rawPtr, length: encodedStringData.count, encoding: .utf8, freeWhenDone: false)
print(decodedString, encodedStringData)
Solution using NSData
let data = NSData(bytes: arrayOfUInt8, length: arrayOfUInt8.count)
let pointer: UnsafeMutablePointer<Int8> = data.bytes.assumingMemoryBound(to: UInt8.self)

Hangman Program 2

I have asked a question before about this program, but it seems that not all problems are resolved. I am currently experiencing an error that states: "Cannot convert value of type 'String' to expected argument type '_Element' (aka 'Character') on the "guard let indexInWord" line:
guard let letterIndex = letters.indexOf(sender)
else { return }
let letter = letterArray[letterIndex]
guard let indexInWord = word.characters.indexOf(letter)
else {
print("no such letter in this word")
return
}
// since we have spaces between dashes, we need to calc index this way
let indexInDashedString = indexInWord * 2
var dashString = wordLabel.text
dashString[indexInDashedString] = letter
wordLabel.text = dashString
I tried converting the String 'letter' to Character but it only resulted in more errors. I was wondering how I can possibly convert String to argument type "_Element." Please help.
It is hard to treat a string like a list in swift, mostly because the String.characters is not a typical array. Running a for loop on that works, but if you are looking for a specific character given an index, it is a bit more difficult. What I like doing is adding this function to the string class.
extenstion String {
func getChars() -> [String] {
var chars:[String] = []
for char in characters {
chars.append(String(char))
}
return chars
}
}
I would use this to define a variable when you receive input, then check this instead of String.characters

Getting NSNumber from nsdictionary in swift

I have an NSDictionary which I created after parsing an XML file. It is storing some numerical value (e.g, 6757677) as a string. Now I want to read it into an NSNumber. I have tried following:
alert.versionNumber = dictRef["VersionNumber"] as! NSNumber
But I am getting following error:
Could not cast value of type '__NSCFString' (0x1081c9c50) to 'NSNumber' (0x1076abb88).
I have also tried following but getting same error:
let refID:NSNumber = dictRef["referralID"] as! NSNumber
alert.refID = refID.integerValue
These conversions were simple in Objective C but are giving me a hard time in Swift.
You need to convert the NSString into a NSNumber by taking a detour via a long long (the largest signed integer type) or double (the largest floating point type). For example:
let string : NSString = "42"
// Integer solution:
let intermediate = string.longLongValue
let number = NSNumber(longLong: intermediate)
// Floating point solution:
let intermediate2 = string.doubleValue
let number2 = NSNumber(double: intermediate2)
Note that for converting a string to its double value, you might need to use a NSNumberFormatter to correctly parse the string and handle locale-dependent differences (for example, the decimal separator is a . in the US but a , in Germany).
Try this
var num:NSNumber = NSNumber(integer:(dictRef["referralID"] as! NSString).integerValue)
let dictRef = NSDictionary(objects: ["6757677","1234567"], forKeys: ["VersionNumber", "referralID"])
if let versionNumber = dictRef.valueForKey("VersionNumber")?.integerValue {
let myNSNumber = NSNumber(integer: versionNumber)
println(myNSNumber) // 6757677
}

base64EncodedStringWithOptions in Swift fails with compile error

let dataStr = data.base64EncodedStringWithOptions(options: Encoding64CharacterLineLength)
Doesn't compile with "Use of unresolved identifier 'Encoding64CharacterLineLength'"
When I just change the param to zero with
let dataStr = data.base64EncodedStringWithOptions(options: 0)
It gives even stranger error: "Cannot convert the expression of type 'String!' to type 'String!'" I found a way to init NSString with NSData (however, I still can't get the difference between String and NSString), but I'm really curious why these two lines of code don't work.
Unless explicitly given an external name, first argument of a method in Swift is not a named argument. Therefore you should be doing: data.base64EncodedStringWithOptions(x) without the options: part.
If you actually look at the argument type, NSDataBase64EncodingOptions, you'll notice that it is a struct conforming to RawOptionSet with static variables for option constants. Therefore to use them you should do: NSDataBase64EncodingOptions.Encoding64CharacterLineLength
The NSDataBase64EncodingOptions struct (or RawOptionSet in general) is also not convertible from integer literals (like 0). But it does conform to NilLiteralConvertible so if you don't want any options you can pass nil.
Putting it together:
let dataStr = data.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding64CharacterLineLength)
or
let dataStr = data.base64EncodedStringWithOptions(nil)
Swift3.0
let dataStr = data.base64EncodedString(options: [])
For Swift 2.x use an array for options:
let dataStr = data.base64EncodedStringWithOptions([.Encoding64CharacterLineLength])
let dataStr = data.base64EncodedStringWithOptions([])
For swift 3.0+ use this ,
var dataStr = data.base64EncodedString(options: .lineLength64Characters)
Swift 3.x
let fileStream = fileData?.base64EncodedString(options: NSData.Base64EncodingOptions.init(rawValue: 0))
You don't have to put in the "options:" identifier in the argument. You DO have to specify that Encoding64CharacterLineLength is a static member of NSDataBase64EncodingOptions, like so:
var dataStr = data.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding64CharacterLineLength)
let dataStr = data.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.allZeros)
Since the default parameter value is set be an empty array…
/// Returns a Base-64 encoded string.
///
/// - parameter options: The options to use for the encoding. Default value is `[]`.
/// - returns: The Base-64 encoded string.
#inlinable public func base64EncodedString(options: Data.Base64EncodingOptions = []) -> String
you just need to call
let dataStr = data.base64EncodedString()

Resources