ABAddressBook in Swift 2 fails - swift

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.

Related

Convert an array of dictionaries into a set Swift 4

I have an array of dictionaries ([[Double:Double]]) which I want to convert into a Set of dictionaries. My goal is to use the .symmetricDifference to find the differences between two arrays (both are of type [[Double:Double]]). How can I do this?
I found this on hackingwithswift.com and tried to use it but I am getting this error:
Type '[[Double : Double]]' does not conform to protocol 'Hashable'
I have also tried this code...
let array1:[[Double:Double]] = [[4.5:3.678], [6.7:9.2867], [7.3: 8.7564]]
let array2:[[Double:Double]] = [[4.5:3.678], [6.7:9.2867]]
let array3 = Set<[[Double:Double]]>(array1).symmetricDifference(Set(array2)) //On this line I get the error above.
You don't want a Set of [[Double:Double]]. You want a Set of [Double:Double], because those are the objects in the array and you want them to be the objects in the Set.
Thus the right thing will happen if you simply say
let array1:[[Double:Double]] = [[4.5:3.678], [6.7:9.2867], [7.3: 8.7564]]
let set1 = Set(array1)
and so on.
This might require you to update to a newer version of Swift. It works in Swift 4.2.

Variable used within its own initial value Swift 3

I try to convert my code to swift 3 an I have spent hours on the following error:
Type 'Any' has no subscript members
Here's was my original code:
let data: AnyObject = user.object(forKey: "profilePicture")![0]
I looked at the answers here but I'm still stuck. (I do programming as a hobby, I'm not a pro :/)
I've try that:
let object = object.object(forKey: "profilePicture") as? NSDictionary
let data: AnyObject = object![0] as AnyObject
But now I get this error:
Variable used within its own initial value
Second issue: Use always a different variable name as the method name, basically use more descriptive names than object anyway.
First issue: Tell the compiler the type of the value for profilePicture, apparently an array.
if let profilePictures = user["profilePicture"] as? [[String:Any]], !profilePictures.isEmpty {
let data = profilePictures[0]
}
However, the array might contain Data objects, if so use
if let profilePictures = user["profilePicture"] as? [Data], !profilePictures.isEmpty {
let data = profilePictures[0]
}
Or – what the key implies – the value for profilePicture is a single object, who knows (but you ...)
And finally, as always, don't use NSArray / NSDictionary in Swift.

Value type of "Any" has no member 'objectforKey' Swift 3 conversion

I am currently facing this problem (Value type of "Any" has no member 'objectforKey') due to swift 3 upgrade. Anybody knows why?
Here is my line of code that have the error
let bookName:String = (accounts[indexPath.row] as AnyObject).objectForKey("bookName") as! String
*accounts is an array.
Okay basically it is the .objectForKey needs to be change as the following:
let bookName:String = (accounts[indexPath.row] as AnyObject).object(forKey:"bookName") as! String
As always, do not use NS(Mutable)Array / NS(Mutable)Dictionary in Swift. Both types lack type information and return Any which is the most unspecified type in Swift.
Declare accounts as Swift Array
var accounts = [[String:Any]]()
Then you can write
let bookName = accounts[indexPath.row]["bookName"] as! String
Another Dont: Do not annotate types that the compiler can infer.

Ambiguous use of a subscript when accessing a 2-dimensional array bridged from Obj-C

This code which ran perfectly in Xcode 7.0 now complains with a error : Ambiguous use of a subscript in Xcode 7.3.1 on the second line.
let ar = sender.draggingPasteboard().propertyListForType("ABLinkedPeopleUIDsPboardType") as! NSArray?
let uniqueID = ar![0][0] as! String
I understand that the NSArray on its own is now considered bad practice, but what do I need to do to get this to compile and run?
NSArray is a single-dimensioned array, but you're trying to use it as a two-dimensional array. I can't see how this would ever compile.
You need to translate into Swift types immediately so you can continue programming in Swift, not go adrift in a sea of force-unwrapped Optionals.
How about:
if let ar = sender.draggingPasteboard().propertyListForType("ABLinkedPeopleUIDsPboardType") as? [[String]] {
// I'm assuming you're expecting to get back a two-dimensional array of Strings, or in the Obj-C realm, an NSArray of NSArrays of NSStrings
let uniqueID = ar[0][0]
}
else {
print("Property List for ABLinkedetc. is not a 2D String Array!")
}
Hayden's link is the correct general discussion but if you're new to bridging Obj C to Swift it may be difficult to apply in your particular case.

Swift Dictionary

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]]