iOS: Fetching CNContact Using Identifier? - ios

I'm having trouble refetching a CNContact using an identifier. Early on I enumerate through all contacts and do something with the phone Numbers, while storing the identifiers in an array.
Later on I'd like to fetch a specific contact using one of the stored identifiers using the following (where currentIdentifier is the identifier I stored earlier):
CNContact *currentContact = [[CNContact alloc] init];
currentContact = [self.contactStore unifiedContactWithIdentifier:currentIdentifier keysToFetch:#[[CNContactFormatter descriptorForRequiredKeysForStyle:CNContactFormatterStyleFullName]] error:&error];
However, I keep getting NULL when I log it.

Related

What type of object is returned from ObjectForID

I am trying to retrieve an object from the managed object context and edit a value or two after it has been backed up to the cloud. In particular, I want to save an id provided by the cloud server.
To get the object, I'm trying to retrieve it using its managedObjectID.
I have tried:
Contacts *object = [_managedObjectContext objectWithID:_moID];
and
Contacts *object = [self.managedObjectContext objectRegisteredForID:_moID];
where moID is the managedObject id.
I then follow this up with
object.cid = #99; //ie I set it equal to some number
In both cases, although Contacts is an NSManagedObject class, it throws a yellow warning:
'Incompatible point types initializing contacts with an expression of type NSManagedObject'.
If Instead of calling it Contacts *object, I call it NSManagedObject *object, it no longer throws the warning but then will not allow me to say object.cid as it no longer knows what a cid is. In this case it throws red error:
Property cid not found on object of type NSManagedObject.
Can anyone suggest proper object type. Thanks in advance for any suggestions.
By looking at the method definition, you'll see that returned instance type is just NSManagedObject * as the warning said. What you need to do is just to cast the type appropriately:
Contacts *object = (Contacts *)[_managedObjectContext objectWithID:_moID];
and
Contacts *object = (Contacts *)[self.managedObjectContext objectRegisteredForID:_moID];
Note, your Contacts suppose to be a subclass of NSManagedObject.

How do I "box" a PFObject inside an iOS push notification?

I want to send a PFObject directly over a push notification. I send the Parse object directly inside the push (e.g. with a custom key "arg") but I couldn't figure out how to construct a real PFObject from the received data. Received data is (obviously) an NSDictionary, with all the keys (object ID, created at, ACLs etc) available. How do I convert it to a PFObject instance?
I need a real way to construct a PFObject with the available data, so don't come with obvious solutions like "send the object ID and then fetch that object at client with Parse's methods." etc. I already know that obvious solution, but it's time/bandwidth/quota inefficient as it requires a new query, while I can have everything I need in that query anyway.
I'm looking for an automatic way, if any. I am targeting iOS 8 so maximum push payload size is also not an issue (2KB is more than enough for my case).
UPDATE: I've tried [PFObject objectWithClassName:#"MyClassName" dictionary:receivedDictionaryObject]; but no avail. It just does not work, the fields are nil even though the dictionary has all the data directly from Parse itself.
I think you can use something like this
+ (PFObject *)objectFromDictionary:(NSDictionary *)dictionaryFromPush{
PFObject *theObject = [[PFObject alloc] initWithClassName:#"MyClassName"];
for( NSString *keys in [dictionaryFromPush allKeys] )
{
[theObject setObject:[dictionaryFromPush objectForKey:keys] forKey:keys];
}
return theObject;
}
This is an untested code but im pretty sure will give you and idea of my point, to get the NSDcitionary from the Push and sent it to this method to be able to convert it to a PFObject
Hope this help

Merge two objects of same type

I have two objects:
deviceConfigInfo and deviceStatusInfo
Both contain an array of devices (so theres a third device object actually).
For each device returned in deviceConfigInfo there are these properties:
uuid
name
somethingElse
lookAnotherOne
and for deviceStatusInfo
uuid
name
somethingElse
someStatusInfo
someMoreStuff
(If you hadn't guessed, I just made up some random properties)
So back to that third object I mentioned, device, I created it with all the properties combined. Now, my question is, say the deviceStatusInfo gets updated, how can I update the device object without losing the "old" data that isn't overwritten (in this case, the lookAnotherOne property).
Does it have to be a manual process of getting the device with the matching uuid and then updating each of the properties for deviceStatusInfo or is there a quicker way of doing this? Imagine there were loads of properties.
Hopefully this makes sense. If it helps, I am using Mantle to create the objects/models.
I noticed that Mantle has the following function which I was able to use:
mergeValueForKey:fromModel:
So in my device model, I added two functions:
mergeConfigInfoKeysFromModel:
mergeStatusInfoKeysFromModel:
These functions have access to an array that contains NSString values representing the properties/keys. There is one array for the configInfo and another for statusInfo properties/keys.
I then loop through the keys and use valueForKey to check it has an actual value. If it does, I then call the mergeValueForKey:fromModel:.
Example Code:
- (void)mergeConfigInfoKeysFromModel:(MTLModel *)model
{
NSArray *configInfoKeys = #[#"uuid", #"name", #"somethingElse", #"lookAnotherOne"];
for (NSString *key in configInfoKeys) {
if ([model valueForKey:key]) {
[self mergeValueForKey:key fromModel:model];
}
}
}
All I have to do now, is call the appropriate merge function on the device object when I get an update, passing over the updated device object. Just as below:
[self.device mergeConfigInfoKeysFromModel:deviceUpdate];

How do I get a server timestamp from Firebase's iOS API?

I have an iOS app that uses Firebase and currently has a few dictionaries with keys that are NSDate objects. The obvious issue with this is that NSDate draws from the device's system time, which is not universal.
With that, what's the best way to get a server timestamp (similar to Firebase.ServerValue.TIMESTAMP for the Web API) using Firebase's iOS API so that I can sort my dictionary keys chronologically?
I'm also aware of the chronological nature of IDs generated by childByAutoID, but I can't figure out the proper way to sort these in code. While they may be returned in chronological order, any time something like allKeys is called on them, the order goes out the window.
Any help with this issue would be greatly appreciated!
Update: In Firebase 3.0 + Swift, you can use
FIRServerValue.timestamp(). In Objective-C this is [FIRServerValue timestamp].
In Swift, you can now use FirebaseServerValue.timestamp() with Firebase 2.0.3+ (before 3.0).
The equivalent for Firebase.ServerValue.TIMESTAMP in iOS is kFirebaseServerValueTimestamp. Right now, this only works for Objective-C and not Swift.
In Swift, you can create your own global timestamp with
let kFirebaseServerValueTimestamp = [".sv":"timestamp"]
and then you'll be able to use kFirebaseServerValueTimestamp in the same way.
But you can only use this as the value or priority of a node. You won't be able to set it as the key name (although, I don't believe you could in the Web API either).
In general, calling allKeys on a dictionary does not guarantee order. But if you're using childByAutoID at a node, you can get back the right order by ordering the NSArray returned by allKeys lexicographically. Something like this would work:
[ref observeEventType:FEventTypeValue withBlock:^(FDataSnapshot *snapshot) {
NSDictionary *value = snapshot.value;
NSLog(#"Unsorted allKeys: %#", value.allKeys);
NSArray *sortedAllKeys = [value.allKeys sortedArrayUsingSelector:#selector(compare:)];
NSLog(#"Sorted allKeys: %#", sortedArray);
}];
This is similar to sorting an NSArray alphabetically, but when sorting the auto-generated IDs, you do not want localized or case insensitive sort, so you use compare: instead of localizedCaseInsensitiveCompare:
Caveat: Seems like the timestamp is added AFTER your object is persisted in Firebase. This means that if you have a .Value event listener set up on the location your object is persisted to, it will be triggered TWICE. Once for the initial object being stored in the location, and again for the timestamp being added. Struggled with this issue for days :(
Helpful information for anyone else who can't figure out why their event listeners are triggering twice/multiple times!
As of Firebase 4.0 you can use ServerValue.timestamp()
for example:
let ref = Database.database().reference().child("userExample")
let values = ["fullName": "Joe Bloggs", "timestamp": ServerValue.timestamp()] as [String : Any]
ref.updateChildValues(values) { (err, ref) in
if let err = err {
print("failed to upload user data", err)
return
}
}
You can get Time Stamp using FIRServerValue.timestamp().
But, Because of FIRServerValue.timestamp() listener is called two times. Listener will be called two times.

Removing duplicates of a key value from an array of dictionaries

I am doing a Facebook API request to give me back all the names of the albums from a particular Facebook group. I get back an array of dictionaries with 3 keys/values, one of which being the key 'name' which maps to the album name, along with the keys 'id' and 'created_time'.
Only problem is that for some reason i'm getting back duplicate 'name' values of albums... but only a couple. And when i go to the Facebook page there's only one instance of that album anyway, no duplicates.
Also, their 'id' values are different, but it's only the first dictionary from the group of duplicates that has a Facebook id that actually points to valid data, the other Facebook id values just don't return anything when you perform a Facebook graph search with them, so it's the first of the duplicates that i want.
How can i remove these useless duplicate dictionaries from my array and keep the one with a valid Facebook id?? Thanks! :)
First I'd like to say that it's probably more beneficial to find a way to get a 'clean' list from faceBook as opposed to covering up problems afterwards. This might not be possible right now, but at least find out what the reason is for this behaviour or file a bug report.
Barring that, this should do the trick:
-(NSMutableArray *) groupsWithDuplicatesRemoved:(NSArray *) groups {
NSMutableArray * groupsFiltered = [[NSMutableArray alloc] init]; //This will be the array of groups you need
NSMutableArray * groupNamesEncountered = [[NSMutableArray alloc] init]; //This is an array of group names seen so far
NSString * name; //Preallocation of group name
for (NSDictionary * group in groups) { //Iterate through all groups
name =[group objectForKey:#"name"]; //Get the group name
if ([groupNamesEncountered indexOfObject: name]==NSNotFound) { //Check if this group name hasn't been encountered before
[groupNamesEncountered addObject:name]; //Now you've encountered it, so add it to the list of encountered names
[groupsFiltered addObject:group]; //And add the group to the list, as this is the first time it's encountered
}
}
return groupsFiltered;
}

Resources