How to get notified when some proprerty of PFObject changed? - ios

Im using parse.com and I wonder if there is a possible approach to get notified when PFObject on parse change one of his properties. The only sollution that I see is to use Push notifications and when notification arrive a refresh the object. Is this the bes possible way or there is a better one?
Thanks.

I don't think there is a way to do this. As you suggested I would simply refresh the PFObject before using it

You could create cloud-code .beforeSave / .afterSave function, which will trigger notification to be send. However it could be very wasteful, so perhaps depending on your timing needs you may also query for objects with recent updatedAt dates every once in a while ?
Parse.Cloud.beforeSave("className", function(request, response) {
if (request.object.existed() ) {
//this is update of already existing object
//... check if change has been done and trigger new notification
}
});

Related

Realm: get notified on new insertion / update of object

I am trying out Realm.io on my Swift project. The insertion and update of objects are pretty straightforward, but here comes a problem: I am not able to catch a new object insertion/update notification.
What I want to achieve is simple, I save a list of objects in Realm. And upon app start/refresh, the app will request a new list of objects from remote server and then perform realm.add(objects, update:true) (I've set id as the object's primary key so that the same objects will not be duplicated), then the UI end of my app should be notified whenever there's a new object, or any existing objects have been updated.
I've tried using realm.addNotificationBlock(_:) but it's called every time with a RLMRealmDidChangeNotification event, even though there is no new object/update.
How do I achieve this?
Edit: code sample
public class DataStorageManager {
var token : NotificationToken?
static let sharedInstance = DataStorageManager ()
public func saveListA(list: [A]?, realm:Realm) {
self.token = realm.addNotificationBlock({ (notification, realm) -> Void in
print("database changed")
})
if list?.count > 0 {
try! realm.write {
realm.add(list!, update:true)
}
}
}
}
You should call addNotificationBlock only once and not everytime you call saveListA. So you could move it to the DataStorageManager's init method.
But you wrote that you want to update your UI whenever the list is updated, so instead of having the token inside your DataStorageManager class you could directly add the NotificationToken as a property to your UIViewController class and call addNotificationBlock in your view controller's viewDidLoad method. Then you can directly update your UI inside the notification block.
EDIT:
If you only want to update your UI when certain data gets updated you cannot use Realm's notification system (which sends a notification everytime any data is changed).
You can do one of the following
Use KVO on your Realm objects. This is described in the Realm Docs
Send your own NSNotification whenever the data is updated that needs a refresh of your UI. So in your case you can send an NSNotification everytime your list gets changed in saveListA. Then you register your view controller as an observer to that notification and update your UI whenever you receive that notification.
As I understand it, you should fetch the desired objects somewhere you want to hold them (like your data manager or view controller), getting Results object and subscribe to this Results change.
Please refer to https://realm.io/docs/swift/latest/#collection-notifications.
It doesn't matter where the object would be changed as long as you hold to that notifications token.
The downside is, currently "modifications" array always include every "touched" element, regardless of if there had been any changes at all. It is considered a bug, but no progress there since August '17.
https://github.com/realm/realm-cocoa/issues/3489
For now, I compare modifications manually after getting the notification.

UIApplication.sharedApplication.scheduledLocalNotifications is always empty

Even if I add a new local notification right before, the attribute is empty. I found a lot of post (and just one on stack overflow) - but nobody has solved this problem.
My useless is, that I want to delete a local notification. That's why I want to iterate over the array and compare the hash value of my notification to delete and the current iterator object.
The notification fires correctly.
Add notification to the array
UIApplication.sharedApplication().scheduleLocalNotification(newNotification)
Read the array
for notification in application.scheduledLocalNotifications {
if notification.hashValue == hashValue {
application.cancelLocalNotification(notification as! UILocalNotification)
NSLog("Unsheduled local notification for \(notification.alertBody!)")
}
}
Thanks for your help.
Seems I have not been first to be stucked on it..
But seems answer is much closer than I tought.
Cmd + LPM
public var scheduledLocalNotifications: [UILocalNotification]? // setter added in iOS 4.2
The property is just form of setter. And probably was never intended to get scheduled notifications
It seems that checking the UIApplication's scheduledLocalNotifications array is fairly unreliable.
Most people seem to recommend just keeping your own list as well, and querying that.
Firstly, that array will only contain notifications that are scheduled after the current date, so any that have been registered that are in the past or any that have already fired, will not be added.
For me, that was not the problem, the notificatiosn I was registering were definitely in the future, but still didn't appear in the list. The best answer I could find is:
Having similar issues right now. My guess here is that iOS does not schedule the notifications immediately but only at the end of the current run loop. I am running into these problems when setting the scheduledLocalNotifications property several times in the same run loop and changes don't seem to be updated accordingly. I think I will just keep a copy of the local notifications array myself and only set scheduledLocalNotifications and never read it.
(source)

Identifying old and new values on changed objects with NSManagedObjectContextWillSaveNotification

I am trying to track changes to objects in a core data context, tracking the name of properties that have changed along with the old and new values.
I've registered for NSManagedObjectContextWillSaveNotification to receive a notification when a save is about to occur, and can pull out the inserted/updated/deleted objects from the context... I can then see the changed values using .changedValues.
However, I am having difficulties retrieving the old values...
As an example, I have an object that tracks a position, and so one of the changes comes back with:
po [obj changedValues]
{
originX = 260;
originY = 180;
}
This gives me the new values for the properties that have changed on the object. To try and get the old values, I'm then using changedValuesForCurrentEvent, which according to the docs should return
"a dictionary containing the keys and old values of persistent
properties that have changed since the last posting of
NSManagedObjectContextObjectsDidChangeNotification"
However, when I try this, it is coming back empty...:
po [obj changedValuesForCurrentEvent]
{
}
How can I capture the old and new values?
You're mixing up your notifications. NSManagedObjectContextObjectsDidChangeNotification gets called any time you change values on a managed object, even though you haven't saved changes yet. NSManagedObjectContextWillSaveNotification gets called later on when you save. So the sequence is:
You change some attributes --> NSManagedObjectContextObjectsDidChangeNotification is posted, and you can use changedValuesForCurrentEvent to see what changed.
Later, you save changes. NSManagedObjectContextWillSaveNotification is posted. You can call changedValuesForCurrentEvent, but it's not helpful because it returns changes since the last did-change notification. There are no changes since the last did-change notification. If there were, you would have received another one. That method is documented to be useful on a did-change notification, not on a will-save notification.
If you want the old values and you want to get them when the will-save notification is posted, you have a couple of options:
Listen for NSManagedObjectContextObjectsDidChangeNotification. Cache information about changes in some collection object (probably NSDictionary). Then when NSManagedObjectContextWillSaveNotification happens, look up those changes, process them, and clear the change cache. OR...
When you get NSManagedObjectContextWillSaveNotification, create a second local managed object context. Since this is a will save notification, you can still fetch the old values. So, fetch each object that's getting saved and compare the before and after values to see what's different.
Although this question is 4 years old, Eddie's answer was very helpful. I made a little change to his answer. All the credits goes to him.
object.setValuesForKeys(object.committedValues(forKeys: object.changedValues().map { $0.key }))
I know this question is old, but there is a better way than the accepted answer. You can access the previous values via committedValues(forKeys:) in combination with changedValues(). There is no need to handle NSManagedObjectContextObjectsDidChangeNotification or to create another managed object context.
Here is some sample code that I use:
// For some reason, the Swift compiler chokes on the type of object.changedValues().keys.
// It should be of type [String], but it complains that it is of type `Dictionary<String, Any>.Keys`
// which is useless. Ah, the joys of Apple programming...
// Work around that like so:
var changedKeys = [String]()
for (key, _) in object.changedValues() {
changedKeys.append(key)
}
let oldData = object.committedValues(forKeys: changedKeys)
Sounds like you should call "changedValuesForCurrentEvent" only when you receive your "NSManagedObjectContextWillSaveNotification" notification.
And if "changedValuesForCurrentEvent" still returns a null dictionary or object, check to see if the notification had anything useful in it's "userInfo" dictionary itself. It also may be that there has not been a NSManagedObjectContextObjectsDidChangeNotification" posted, like you posted from the docs up there.

iOS NSManagedObjectContext - is it possible to get or send a notification when all changes is saved?

I use Core Data - and I have registered and is listening for NSManagedObjectContextDidSaveNotification:s I have a collection of data (from JSON), that I want to save, and after all objects is saved, I would like to get some kind of notification. It currently seems like this notification is sent after every object is saved. Is there some kind of built in solution for getting my desired notification? If not, how could/should I do it?
There's no built-in notification that gets posted after you've saved a specific batch of objects. Core Data really has no idea how many objects are in your collection, so it has no way to know that you've reached the end of it.
You'll get NSManagedObjectContextDidSaveNotification every time you call save: on the managed object context. You could just wait to save until you've handled all of the objects, which would mean just one NSManagedObjectContextDidSaveNotification.
A better solution is to post your own notification when you know that you've finished the collection. Define a string constant called something like JSONUpdatesCompleteNotification, and post a notification with that name after your last save: call.
NSString *JSONUpdatesCompleteNotification = #"JSONUpdatesCompleteNotification";
Then later, when you know you're done,
[[NSNotificationCenter defaultCenter] postNotificationName:JSONUpdatesCompleteNotification object:self];
Make sure you observe this notification anywhere you need to know about it, and you're done.

NSNotification if data changes

Let's assume that I have a program that parses a RSS feed.
I have a method that runs in a thread which keeps checking for updates. If updates is found a NSNotification is created. Is this a stupid implementation?
And is it possible to pass custom parameters within a NSNotification, such as the elementId that was updated.
Sounds like a good plan to me. Yes, you can pass user data.
See NSNotification's notificationWithName:object:userInfo:. The userInfo is an NSDictionary so you can pass whatever you like around.

Resources