Discoverability is a CloudKit feature that lets you:
- Fetch the user’s First Name and Last Name from their iCloud account.
- Fetch the user’s friends First Name and Last name from the user’s address book.
Now, Figure 1 and 2 shows outputs you will see on the simulator’s screen, once we’ve implemented above tasks in the MainViewController.swift class file.
With that said, click the MainViewControllers.swift file to load it in the standard code editor. Next, enter these statements above the viewDidLoad() function:
let container = CKContainer.defaultContainer() var friendsList = [String]() var userName = String() let emojiBullet = " ➢ "
Next, enter this statement in the viewDidAppear() function:
textView.text = "Hello user!"
Next, enter this code in the executeCodeButton() function:
@IBAction func executeCodeButtonClicked() {
textView.text = "Hello user!"
self.container.statusForApplicationPermission(.PermissionUserDiscoverability, completionHandler: {
(status, error) in
if error != nil {
NSOperationQueue.mainQueue().addOperationWithBlock {
self.textView.text = "Cloud Error\n\(error.localizedDescription)"
}
} else {
if status == .InitialState {
self.requestPermissionToBeDiscovered()
} else if status == .Granted {
self.fetchUserName({ (appUserName) -> Void in
self.userName = appUserName
self.fetchAndDisplayUserContacts()
})
}
}
})
}
Code you entered in the executeCodeButton() function perform these tasks:
- Find out whether the user already granted the app permission to access her personal information. This is done by calling the statusForApplicationPermission() function on the container. The function returns either an error or an applicationPermissionStatus (status for short).
- If the status contain the value InitialState, the app ask the user for permission to access her personal information. In other words, the app request permission to be discovered. The user will see the dialog view shown in Figure 1 above, on her screen.
- The app fetch the user’s personal information and her friends’ personal information, and display them in the textView-see Figure 2 above; only if the user granted the app permission to access her personal information. She does this by clicking the OK button on the dialog view.
Now, here’s the code to implement the user defined functions called in the executeCodeButton() function.
func requestPermissionToBeDiscovered() {
self.container.requestApplicationPermission(.PermissionUserDiscoverability, completionHandler: {(status, error) in
if error != nil {
// Update the textView on the main thread
NSOperationQueue.mainQueue().addOperationWithBlock {
self.textView.text = "Cloud Error\n\(error.localizedDescription)"
}
} else if status == .Granted {
// The user granted the app permission to be discovered
self.fetchUserName({ (appUserName) -> Void in
self.userName = appUserName
})
}
})
}
func fetchUserName(completionHandler: (appUserName: String) -> Void) {
// Get the app user's recordID
self.container.fetchUserRecordIDWithCompletionHandler {
(recordId, error) in
if error != nil {
// Update the textView on the main thread
NSOperationQueue.mainQueue().addOperationWithBlock {
self.textView.text = "Cloud Error\n\(error.localizedDescription)"
}
}
// Use the recordID to fetch the user information from the CloudKit container
self.container.discoverUserInfoWithUserRecordID(recordId) { (userRecord, fetchError) in
if fetchError != nil {
// Update the textView on the main thread
NSOperationQueue.mainQueue().addOperationWithBlock {
self.textView.text = "Cloud Error\n\(error.localizedDescription)"
}
} else {
// Put the user's full name in a string variable
let fullName = userRecord.firstName + " " + userRecord.lastName
// Return the user's fullName to the caller of this function
completionHandler(appUserName: fullName)
}
}
}
}
func fetchAndDisplayUserContacts() {
self.container.discoverAllContactUserInfosWithCompletionHandler( {userContacts, error in
if error != nil {
// Update the textView on the main thread
NSOperationQueue.mainQueue().addOperationWithBlock {
self.textView.text = "Cloud Error\n\(error.localizedDescription)"
}
} else {
var friendName = String()
for contact in userContacts as! [CKDiscoveredUserInfo] {
// Add the user's friend name in the friendsList array
self.friendsList.append(self.emojiBullet+contact.firstName + " " + contact.lastName)
}
// Convert elements in the friendsList array to a string
let stringFriendsList = "\n".join(self.friendsList)
// Put the textView value in a variable
let totalContacts = "\n\(userContacts.count) contacts came back\n."
// On the main thread, display the user's friends names in the textView
NSOperationQueue.mainQueue().addOperationWithBlock {
self.textView.text = "Hey \(self.userName)!\n\nHere is a list of your friends who are using this app and agreed to be discovered:\n\n\(stringFriendsList)"
}
}
})
}
When you finish implementing above functions in the mainViewController.swift file, run the app in the iPhone 6 Simulator. You will see the message, “Hello user!” in the text view. Click the Execute Code button and you will see the dialogue shown in Figure 1, on the simulator’s screen. Click the OK button and you will see this output in the textView.
As you can see no names appear in the textView. That’s because the user’s friends did not install the app on their devices and agreed to be discovered. So add some fake friends names in the friendsList array.
override func viewDidLoad() {
...
friendsList.append("\(emojiBullet)Mary Edwards")
friendsList.append("\(emojiBullet)Oleg Zakala")
friendsList.append("\(emojiBullet)Amand Marshall")
friendsList.append("\(emojiBullet)Jason Alexander")
}
Now, run the app in the simulator and click the Execute Code button. This time, you will see output shown in Figure 2, on the simulator’s screen.


