Initialization methods for PFObject Subclass Objects that are Generated by Parse - ios

This is tagged with iOS, but I'm sure it could be useful for the other Parse SDKs as well. As you may know, Parse added the ability to create native PFObject subclasses to the iOS SDK not too long ago. This is a great addition for a number of reasons. Firstly, it allows compiler to check your code by creating dynamic properties for object attributes:
myObject[#"myAttribute"] is converted to myObject.myAttribute
Secondly, and more important to this question, custom subclasses can have added functionality. For example, say I have created an alarm app that stores Alarm objects on the Parse cloud. In my custom subclass, I can override the + (instancetype)object, - (void)saveEventually, and - (void)deleteEventually methods so that the alarm object can schedule/update/remove a UILocalNotification for itself upon creation, modification, or deletion.
Here's where things get complicated and my actual question comes in. Say a user creates an alarm on one device (which uploads it to the cloud), and then syncs it automatically to another device. The second device obviously updates it's contents in the background with PFQuery's - (BFTask *)findObjectsInBackground and then calls - (BFTask *)fetchIfNecessaryInBackground on each object to ensure that all of its substance is on the device. My question is: What method(s), if any, gets called when a PFObject subclass is found/fetched from the Parse cloud database? For that matter, what about objects initialized from the local datastore?
Like I mentioned, overriding various methods works perfectly for objects that are created and managed on the device, but I am baffled as to how one would run custom code from within a new object that just arrived in memory from the local or remote datastore. Any thoughts or suggestions on how to handle this would be much appreciated. The Parse documentation does not cover such a case, so it may not even be best practice, but it seems to me that it should be. Anyway, thank you for your time and your insights.

As for most subclasses of NSObject, the way to go is probably to override the -init method.
However, as you mentioned in your last paragraph, such practice is undocumented and you should probably avoid it. The way PFObjects work makes it possible to have multiple instances of the same object in memory (multiple PFObjects with the same objectId). And you do not control when or why these objects are created, so relying on code executed when they are initialized is probably a bad idea. If you have been using Core Data, note that Parse really handles things in a different way, so the best practices are different.
For example, I'm not saying this is the case, but what if a copy of each object is created before it is saved ? Of what if the object is created twice when making a query with the 'cache then network' policy ? Even if you make it work, you would still end up with something that could break with every update of the Framework.
I think you should bundle you initialization code in a method of your own that you would call yourself on objects when you receive them from a query or from the local datastore. Overriding is a good design and practice in object oriented programming, but there are some exceptions and I think this is one of them.

Related

Should I use a singleton location manager in Swift?

Context:
My app needs the user's current location in several unrelated view controllers and, as of now, I'm creating a CLLocationManager in each of these controllers and requesting the current location over and over.
However, it doesn't look right to me. It's duplicated code and inneficient.
I've seen several references on the internet mentioning a singleton location manager. And I also heard to avoid singletons as much as possible.
Question:
Should I create a singleton class that manages the location? If not, what other solution would you suggest to avoid this duplicated code?
And I also heard to avoid singletons as much as possible
The above statement is correct in case that some dealoocated cycle of the app run needs that data so after it finishes the singleton becomes a problem from memory perspective as it stays alive all the app life cycle , in your case ( all vcs inside the app needs the location ) is the best fit for a singleton to avoid the duplication - less-efficient code and high memory issues
Needless to say 90% of apple classes uses singletons e.x
URLSession.shared
NSNotificationCenter.default
UNUserNotificationCenter.current
UserDefaults.standard
FileManager.default
There is no hard and fast rule. Apple is quite clear that it's fine to instantiate more than one location manager. However, if you do that, you might confuse yourself, because each will need a delegate, each will need its own settings, and so forth. Thus, you are right to be wary of that approach.
It is a standard strategy to pick an instance that persists throughout the life of your app — your app delegate, or your root view controller, for example — and initialize an instance property with a location manager. There is no reason whatever to add the Singleton pattern to the mix; you simply make one once and keep hold of it.
Patterns are not evil. It depends on the user. They are solutions for a specific problems. It depends on how you see your problem and what you want to achieve.
In your case, you need a location manager instance through out your app and you use it in multiple places, so you need a wrapper manager. If you only need one configuration, then it makes sense to use singleton.
Apple is recommending to have a strong reference of the manager as long as you need it. CLLocationManager - Apple Documentation
Create an instance of the CLLocationManager class and store a strong reference to it somewhere in your app.
Keeping a strong reference to the location manager object is required until all tasks involving that object are complete. Because most location manager tasks run asynchronously, storing your location manager in a local variable is insufficient.
If you create a singleton location manager it has to do things differently than other singletons. You can't use the normal delegate pattern for it to inform other objects about the location updates and errors because the normal delegate pattern is a one-to-one relationship. You have to use multiple delegates (the singleton has an array of interested objects and it sends the same message, e.g. location update, to each one). Here's another question about why that's difficult to use:
Multiple Delegates in iOS
You can get around that with notifications but personally I think that's a bad pattern (it decouples things too much and makes it hard to follow paths of responsibility).
The singleton also has to keep track of whether any of its interested objects asked it to stop or start. If they've all asked it to stop then it should power down the updates. If just one wants updates it has to power them back up. Search for all the people building frameworks just to do the same task with the network indicator to see how much trouble this is.
If there's an error with requesting location you have to save that error and when (some later time) an object wants location, you have to retransmit the error. So really you want to have all interested objects connected and listening from the start to avoid that scenario.
I'm sure I could think of more hairy cases that you'd have to deal with.
The in-between option is to create a location manager class with your special setup, error checking and so on, and instantiate one of those whenever you need it. Use the delegate pattern to get messages from it (most will just be passing the messages along directly).

What is an the function of AppDelegate and Context in swift?

I just started working with core data in iOS app dev using swift. The first two things that I encountered are: 1. AppDelegate 2. NSManagedObjectContext.
I understand that 'AppDelegate.swift' file is a source file just like the 'ViewController.swift'. But in all the tutorials it was referred as 'something which will be used later'. Perhaps, now is the time to get familiar with it. Could you kindly tell me what exactly it does?
What does an object of type 'NSManagedObjectContext' do? What is its function? Could you please put its function in simpler words?
Thanks in advance.
Have a look at the following figure for visual understanding of Key objects in an iOS app:
Role of AppDelegate:
The app delegate is the heart of your app code. It handles app initialization, state transitions, and many high-level app events. This object is also the only one guaranteed to be present in every app, so it is often used to set up the app’s initial data structures.
AppDelegate is used for the whole app, you can use it to manage the app life cycle, on the other hand, ViewController is used for a single view. you can use it to manage life cycle of a view. One app can have multiple views. but only one AppDelegate.
Role of NSManagedObjectContext:
The NSManagedObjectContext is a fundamental concept of Core Data.It is like transaction in a relational data. You can fetch objects, you can create objects , update and delete them, save them back to the persistent store, etc. Basically for all the core data operations, you will need to interact with NSManagedObjectContext.
UIApplicationDelegate is an interface between device (the iOS system) and your application. You will i.e. handle push notifications in this class
Context is more complicated. Generally all object that comes from CoreData has some context which is responsible for sync all object in this context. So if you fetch object A and in some other point of code you will fetch again this object (lets call it A2) and both are fetched in the same context then A == A2 is always true. But that's just the tip of the iceberg.

Frequently Accessed Objects/Classes

Within my Swift application, there are two classes that I interact with in almost 75% of the app. One is a set of settings called UserSettings, and the other is called Job. These both are stored in sqllite.
Most of the time it's just reading values already set, and on one areas it also writes. It seems strange to have to keep reinstantiating my settings and job services to communicate with my database to get back to me the same object i'm accessing across the board.
In a case like this, the options to me see to be either
constantly reading/writing to the database, or
do some sort of singleton accessed throughout the entire app.
I'm not sure how much Swift changes anything in terms of arriving at an answer to this question, but I wanted to seek the help of Stack Overflow. How do I set an object that I can access throughout the entire app? Or is it not ideal and instead I need to get it from my db every time?
Thanks so much.
I recommend you to read how core data works, I know you are managing your own store, but the architecture works fine. As a summary you can create a "context object"(this could be your singleton) who interacts with your store (sqlite) creating managed objects, you will work with this objects who are associated with the "context object", and when ever you need to save the changes, you ask the "context object" to write all the managed objects in the store.
Your managed objects need to be only a copy of the "context object" objects, so when you ask to "save" data to the "context object" you only copy back this managed objects. This will help with save multithread coding. (Your context object should work on a serialized queue).
Again this is just a summary, you should read how core data works to get a better picture.
Edit:
Read this blog: http://www.objc.io/issue-4/core-data-overview.html
The difference is that you only need one store and one context object.

Incremental Saving

I have an app with a lot of data (including NSMutableArrays, NSNumbers, various custom classes) that uses NSCoding protocol presently. However, I would like to implement an incremental saving system, to save time during the "saving process". The loading time is not important.
Is there any existing container that checks its members for "dirty" and only updates those values when writing to file; or better yet, a protocol that can be implemented to do the same; or any other simple, available way of doing this?
For large amount of data its better to change data model to Core Data. Otherwise, you may want to save changes after specific events, or, bad solution is to use NSTimer, to save all data every time you want to.

Updating a flag when an attribute changes

As part of my syncing solution, I use a sync status for all objects of a certain class. Whenever specific (not all) attributes of that object change, I want to update the status.
I am considering four approaches:
Manually setting the status in code wherever I change
something that needs to synced. This is the most obvious, but also
the most laborious and error-prone (I'll need to remember to also add the sync status update any time I add new functionality).
Track it using a core data notification (e.g. willSave or
NSManagedObjectContextObjectsDidChangeNotification). This seems the most appropriate at first glance -
I simply sign up for the notifications in my AppDelegate and update
the status each time. But will it be possible to examine the changes
and only update the sync status when an attribute I care about is
updated? Also, won't setting
the sync_status itself also fires this notification, leading me into an endless loop? How would I address this?
Custom setters on the attributes I care about. I have had
trouble trying to get this working before, and eventually decided
to try to leave the standard core data getters/setters alone. But I
would delve back in if it is the best fit.
KVO. I've not used this pattern before, but it might be easiest to
just sign up for notifications of attribute changes for those I care
about and set the flag there. But where would I do this? I need
to monitor every object of the class, so would it be possible to start observing an
attribute's KVO notifications in that same object's awakeFromInsert?
I.e., whenever an object is created, immediately have that same
object listen for changes to attributeA and set it's own sync_status
when it fires?
Which of these approaches will serve me best? Perhaps I am missing some other ideas?
Manually setting the status code
Probably a bad idea, for exactly the reason you describe. You'll need to do this in all kinds of cases. You might not always be the developer on the app. One day you or someone else will forget it. Even if you don't, you get extra code all over the place that could be centralized.
Track it using a core data notification [...] Also, won't setting the sync_status itself also fires this notification, leading me into an endless loop?
It depends how you do it. Listening for NSManagedObjectContextDidSaveNotification could work, if you use a secondary NSManagedObjectContext. That way you can set the sync flag, save changes, and avoid looping because you're saving on a different context that you're not observing.
Using NSManagedObjectContextObjectsDidChangeNotification could also work. That will be posted when object properties are changed but a save is not actually in progress yet. Inspect the userInfo dictionary to see if anything you care about has changed, and if so, set your sync_status flag. Setting the flag would trigger a new notification, but it will be one you don't care about, so you break the loop. Using a separate context would also prevent looping here.
Custom setters on the attributes I care about.
Definitely workable, though depending on how many attributes you care about, you could end up with a lot of accessors just to update sync status. Of the four you mention, this is the one I would use.
A related but simpler approach would be to override willSave on your managed object classes. That will get called just before a save. Implement it to
Look through [self changedValues] for attributes that trigger syncing.
Set the sync flag if you find any of them.
This way you only have one custom method per entity, no matter how many attributes end up triggering the sync flag.
KVO
Should work, but is probably less intuitive to get working right than custom setters.
When I had to do something like this, I put the sync information outside of my data store. I'd listen for NSManagedObjectContextDidSaveNotification, and in the observer method I would:
Look through userInfo to see what had changed
Get the NSManagedObjectID for each object that would need to sync
Convert the object IDs to NSStrings and add those to a list saved in a separate file.
On a successful sync I'd clear out the object ID list.
The thinking was mainly that a sync flag is more metadata than actual model data, so I kept it out of the model. If you prefer to keep it in the model, I'd go with overriding willSave.

Resources