Swift Dictionary - swift

I'm trying to do this:
var myBeacons: [NSUUID: [Int]] = [NSUUID(UUIDString:"74278BDA-B644-4520-8F0C-720EAF059935"): [1,1]]
but I get the following error:
'[NSUUID: [Int]]' is not convertible to '[NSUUID: [Int]]'
If I do:
var myBeacons2: [String: [Int]] = ["74278BDA-B644-4520-8F0C-720EAF059935": [1,1]]
It works
Did I miss something or does it look like bug ? (I'm using Xcode 7 beta)

Since not every String is a valid UUID the initialiser can fail. Thus the initialiser returns an Optional<NSUUID>. This to encourage code safety.
Depending on your needs you might check that you supplied a valid String for an UUID as follow:
let givenString = "74278BDA-B644-4520-8F0C-720EAF059935"
var myBeacons: [NSUUID: [Int]] = [:]
if let uuid = NSUUID(UUIDString: givenString) {
// Here we are sure that the uuid is valid
myBeacons[uuid] = [1, 1]
}

As Martin points out, NSUUID(UUIDString:) returns an optional. You need to unwrap it:
var myBeacons: = [
NSUUID(UUIDString:"74278BDA-B644-4520-8F0C-720EAF059935")!: [1,1]]
(Note the exclamation point after the call to the NSUUID initializer.)
I tested that under Xcode 6.3.2 and it works. I Haven't tested it under Xcode 7 though.
Edit:
In fact it would be better to use optional binding as outlined in #MatteoPiombo's answer. You should accept his answer since it gives you the most robust solution. (I'm voting for his answer. It's the best answer so far)

convenience init?(UUIDString string: String) returns an optional, try unwrap it as follow:
var myBeacons: [NSUUID: [Int]] = [NSUUID(UUIDString:"74278BDA-B644-4520-8F0C-720EAF059935")!: [1,1]]

Related

Swift 3 cast UITextField to Int

I'm receiving a compiler error and I'm not really sure why. I'm sure there is a simple answer for this. I have a core data attribute I'm trying to assign before saving. In my Core Data Property file it's defined as this:
#NSManaged public var age: Int32
I am using a UIPicker to select it and put it into an inputView. That works fine, so ageTextField: UITextField! holds the value. As I try to assign this to the CoreData object just before saving I get the following
person.age = ageTextField.text -> Cannot assign String? to Int32.
Ok, I understand that, so I cast it
person.age = Int(ageTextField.text) -> Value of Optional String not unwrapped...
Ok, I get that, so I unwrapped it, it asks to unwrap again and I agree:
person.age = Int(ageTextField.text!)! -> Type of expression is ambiguous without more context
I'm not sure what is wrong here, just looking over some old Swift 2 code of mine and this worked. This is my first code with Swift 3 though.
That compiler error is obscure at best and misleading at worst. Change your cast to Int32:
person.age = Int32(ageTextField.text!)!
Also: unless you are absolutely sure that the user will always enter a valid number into the textfield, use optional binding instead of force unwrap:
if let text = ageTextField.text,
let age = Int32(text)
{
person.age = age
}
The immediate issue is the use of the wrong type. Use Int32, not Int. But even once that is fixed, you have lots of other issues.
You should safely unwrap the text and then the attempt to convert the string to an integer.
if let text = ageTextField.text, let num = Int32(text) {
person.age = num
}
The use of all of those ! will cause a crash if the text is nil or it contains a value that isn't a valid number. Always use safe unwrapping.
Just make sure to unwrap the optional before convert. Make your code safe.

Swift 2.2 Optional Type autocorrection

Swift 2.1 code which worked without any problem:
let userDetail = response["params"]?["users"]
I updated to Xcode 7.3 which runs Swift 2.2. And it's start to complain on same above line.
It complains like:
Value of optional type AnyObject? not unwrapped; did you mean to use '!' or '?' ?
When I auto corrected xcode suggestion it is giving me following code as a corrected one:
let userDetail = response["params"]?!["users"]
Here response is of type AnyObject?
I dont want to forcefully unwrap an optional here.
Does anybody know what's the problem here? And what has changed about optionals in Swift 2.2 which is giving me this error.
For a dictionary [K: V], the return type of the subscript is V?, and thus in your case the return type of response["params"] is AnyObject?? since V == AnyObject?. To recover an AnyObject to need to unwrap twice:
// swift 2.2 only:
// v
let userDetail = response["params"]??["users"]
// note: the type of userDetail is still `AnyObject??`
I'm not sure what is changed in Swift 2.2, maybe the check becomes stricter.
Update: In Swift 3 the type of userDetail becomes Any?? and you can't chain further subscripts. In fact Swift 3's JSONSerialization is changed to return Any instead of AnyObject, so you can't even write response["params"]. Consider using dedicated JSON packages like SwiftyJSON instead.
Swift 2.2 is more restrictive about key/index subscription of AnyObject returned from a dictionary key.
You could use a chained optional binding checking against the expected type,
if let userDetail = response["params"] as? [String:AnyObject], users = userDetail["users"] as? Whatever {}

ABAddressBook in Swift 2 fails

In Xcode7/Swift 2, the call
ABAddressBookCopyArrayOfAllPeople(addressBook)?.takeRetainedValue()
returns a non-null CFArrayRef, but when I cast it "as? NSArray" or "as? [ABRecordRef]" (which used to work) I now get nil. I understand that we should move to the Contacts framework, but the old way should still work for a while. What's up?
Correct syntax for Swift 2 requires you to string two casts in a row:
let rawCFArrayRef =
ABAddressBookCopyArrayOfAllPeople(addressBook)?.takeRetainedValue()
let swiftArray = rawCFArrayRef as? NSArray? as? [ABRecordRef]
Note that the ? on NSArray? is crucial.

Syntax to create Dictionary in Swift

As far as I know there are two ways to create an empty dictionary in swift
var randomDict = [Int:Int]()
or
var randomDict = Dictionary<Int, Int>()
Is there any difference between these? Both versions seems to work just the same.
No, both are same.
From Apple's Book on Swift:
The type of a Swift dictionary is written in full as Dictionary<Key, Value>
You can also write the type of a dictionary in shorthand form as [Key: Value]. Although the two forms are functionally identical, the shorthand form is preferred.
So
var randomDict = [Int:Int]()
and
var randomDict = Dictionary<Int, Int>()
both calls the initializer which creates an empty dictionary and are basically the same in different form.
A third way you could do it is:
var randomDict:[Int:Int] = [:]
They're all equivalent as far as the code goes. I prefer one of the shorthand versions.

Having problems trying to call substringWithRange on a String optional

I'm trying to call substringWithRange on an option String but after multiple experiments am still not able to get it to compile:
var mdn:String?
var subscriber = CTSubscriber()
var carrierToken = subscriber.carrierToken
mdn = NSString(data:carrierToken, encoding:NSUTF8StringEncoding)
let range:NSRange = NSRange(location: 0, length: 10)
if mdn
{
let subString = mdn!.substringWithRange(range)
}
This will result in the compilation error saying the value of the optional NSString is not unwrapped.
I thought it already was unwrapped due to the !.
If I remove ! then I get an error saying String? does not have a member named substringWithRange.
Replace
var mdn:String?
with
var mdn:NSString?
You are using the var to store a NSString so you should give it the correct type. Although String and NSString are mutually assignable, it's not the same type.
String doesn't have the substringWithRange method.
I think this might actually be a compiler bug. I would report it to Apple and see how they come back.
However, the proper approach to unwrapping an optional for use if you need to gain some information from it. (Like obtaining a substring, in your example) is:
if let theMdn = mdn {
let subString = theMdn.substringWithRange(range)
}
That way your codeblock will only be executed if the unwrapping was successful.
Edit: Sulthan's answer might be more accurate. However I still think if you can unwrap the optional in a let block, you should be able to do it manually.