In my code i have an mainManagedObjectContext and a backgroundManagedObjectContext and its working great.
I moved all my save code to the backgroundManagedObjectContext and merging the differences between the contexts via NSManagedObjectContextDidSaveNotification.
Now I want to update my UI after NSManagedObjectContextDidSaveNotification. What is the best approach beside of a NSFetchedResultController to do this?
The changes in my object is visible via the debugger and I could use KVO for this, but IMHO it's a terrible idea. In my abstraction i got a Model to handle the database calls and it would be great when my Model also handling changes after merging the context.
What is the best approach to do this?
As has been pointed out, for table and collection views, the best bet is NSFetchedResultsControllerDelegate.
Another mechanism is to register for this (or your custom) notification NSNotificationCenter, e.g. for the original notification:
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(updateUI:)
name:NSManagedObjectContextDidChangeNotification
object:nil];
Best do this in viewDidAppear. Don't forget to remove the observer in viewWillDisappear. Note that following the comment I am using the change notification rather than the save notification.
In your non-table view controllers you should isolate the UI setup, similar to the boilerplate code for the fetched results controller delegate, which implements a method like configureCell:atIndexPath:. You can then simply call this setup routine when you get the notification without duplicating any code.
Related
I come from a .NET web application background and have just started iOS development. The initial design of my app focuses around the NSNotificationCenter. I was reasonably happy with this until I saw various posts explaining how reaching for the NSNotificationCentre was a common newbie mistake.
Here is a simplified version of the problem I am trying to address:
My application is trying to show a list of messages that are populated using web service calls, think Facebook messaging.
When the app is first loaded it pulls a collection of messages from the server and displays them in a table to the user. The user can add new messages (which get sent back over the API) and the app can receive Push Notifications about new messages which are added to the feed.
The messages are never persisted to disk so I'm just using POCOs for the model to keep things simple.
I have a MessageFeedController which is responsible for populating the message feed view (in a storyboard). I also have a message feed model, which stores the currently retrieved values and has various methods:
(void) loadFromServer;
(void) createMessage: (DCMMessage*) message;
(void) addMessage: (DCMMessage*) message;
(NSArray*) messages;
(int) unreadMessages;
The current implementation I have is this:
Use case 1 : Initial Load
When the view first appears the "loadFromServer" method is called. This populates the messages collection and raises an NSNotificationCenter event.
The controller observes this event, and when received it populates the tableview
Use Case 2: New Message
When a user clicks the "add" button a new view appears, they enter their message, hit send and then the view is dismissed.
This calls the createMessage method on the model, which calls the API
Once we have a response the model raises the NSNotificationCenter event
Once again the MessageFeedController listens for this event and re-populates the table
Use Case 3: Push Message
A push notification is received while the app is open, with the new message details
The AppDelegate (or some other class) will call the addMessage method on the model, to add it to the collection
Once again, assuming the MessageFeed view is open, it re-populates
In all three cases the MessageFeed view is updated. In addition to this a BadgeManager also listens to these events which has the responsibility of setting the app icon badge and the tabbar badge, in both cases the badge number relates to the number of unread messages.
It's also possible that another view is open and is listening to these events, this view holds a summary of messages so needs to know when the collection changes.
Right, thanks for sticking with me, my question is: Does this seem like a valid use of NSNotificationCentre, or have I misused it?
One concern I have is that I'm not 100% sure what will happen if the messages collection changes half-way through re-populating the message table. The only time I could see this happening is if a push notification was received about a new message. In this case would the population of the table have to finish before acting upon the NSNotification anyway?
Thanks for your help
Dan.
In other words, you're posting a notification whenever the message list is updated. That's a perfectly valid use of NSNotificationCenter.
Another option is to use Key-Value Observing.
Your controller (and anyone else) can register as an observer to the "messages" property, and will be notified whenever that property changes. On the model side, you get KVO for free; simply calling a method named setMessages: will trigger the KVO change notification. You can also trigger the notification manually, and, if so desired, the KVO notification can include which indexes of the array have been added, removed, or changed.
KVO is a standardized way to do these kinds of change notifications. It's particularly important when implementing an OS X app using Cocoa Data Binding.
NSNotificationCenter is more flexible in that you can bundle any additional info with each notification.
It's important to ensure that your messages list is only updated on the main thread, and that the messages list is never modified without also posting a corresponding change notification. Your controller should also take care to ignore these notifications whenever it is not the top-most view controller or not on screen. It's not uncommon to register for change notifications in viewWillAppear: and unregister in viewWillDisappear:.
In my opinion using a delegate protocol pattern would be a much better fit for this scenario. Consider the scenario where your "api layer" needs used across many view controllers in an application. If another developer were to be introduced to your code, they would have to hunt around for notificationcenter subscriptions instead of just following a clean 'interface' like protocol.
That being said, your code will work just fine and this is a valid use of notification center. It is just my personal preference for 'cleaner' code to use a protocol based approach. Take a look around in the iOS SDK itself and you will see scenarios where Apple themselves use protocols and use notifications. I feel it is much more easy to comprehend and use the protocols than having to dig around and determine what I must listen to for a notification.
NSNotifications run the receivers code synchronously as soon as they are posted, so a new message during repopulation would join the back of that execution queue. On the whole it seems valid to me, and it keeps a reasonable degree of separation between The view controllers and the model.
Depending on the number of classes that are likely to want to listen for the same information arriving, you may want to use a delegate pattern, maybe keeping an dictionary of delegate objects, but I personally don't feel as though this scales so well, and you also have to take care of nil-ing out delegates if a page is dealloced to avoid crashes. To sum up, your approach seems good to me.
I use sharekit with mail/twitter/facebook and I am really new to objective-c. sharekit works well and sends my images like it should.
in my app I have a screenshot function. I want the app to 'freeze' when a screenshot is taken, stopping to send any shake- or touch-event to the scene behind the sharekit-action.
in my screenshot-layer I have three buttons which call the shareItem-methods of their specified service, like
[SHKTwitter shareItem:item];
vereything works fine 'till here. but now when the sending is finished (or canceled or errored) I need the app to 'unfreeze', sharekit should tell my app that it is allowed to listen to any touch- or shake-action again.
I am sorry but I think I don't understand the concept of using the delegate here. I mean, is 'sendDidFinish' meant to be inside a delegate? and if so, how could I tell sharekit who is its delegate? or do I have to edit the send-service classes (like SHKItem or SHKFacebook) itself?
please don't downrate me for this question. I really want to get behind this mystery...
SHKTwitter inherit from SHKOAuthSharer, who inherit from SHKSharer. SHKSharer has a delegate protocol called "SharerDelegate".
So you can use an instance of SHKTwitter, then set it's delegate as :
shkTwitterInstance.shareDelegate = yourDelegateObject.
And implement the delegate method
- (void)sharerFinishedSending:(SHKSharer *)sharer;.
Try that.
EDIT (OTHER, AND MORE POPULAR, SOLUTION)
Also, you can suscribe your object to "SHKSendDidFinish" notification from SHKTwitter object.
[[NSNotificationCenter defaultCenter] addObserver:yourObject selector:#selector(theMethodthatYouWantToExecuteWhenTheNotificationIsRaised:) name:#"SHKSendDidFinish" object:shkTwitterObject];
I've got 2 view controllers, and the second view controller needs to change a label in the first view controller. One way this can be done is to make the first view controller a property so the second view controller can change it directly.
Only problem is that it's spaghetti programming ... how would one achieve this without falling for this trap?
One idea I had was to use delegate protocol to do this. Curious of opinions if any other ways.
For a simple application that does small tasks like changing a label, it isn't highly frowned upon to create a property for the view controller. As your application grows, or if you need to do a lot of label changing, it may be best to set up delegates and protocols to change them for you. It's mainly up to you: if you have a team or a large/growing app, you might want to consider using delegates and protocols because odds are you'll be using them anyway for good MVC and KVO practices.
Perhaps it's because I'm a relative Objective C noob (though by no means new to coding), but the delegation scheme almost always seems to result in some manner of elongated pasta to me -- except for the built-in systems such as the UITableViewController.
I recently need to create a system to update labels on custom tableview cells and found that it was far simpler and more understandable to use NSNotification. In the controller where the new values come into being, we post a notification:
[[NSNotificationCenter defaultCenter] postNotificationName: #"UpdatedDatesNotification" object: formattedDates];
... and in the subclass that creates the UITableViewCell containing the label, we are listening for that specific notification:
[[NSNotificationCenter defaultCenter] addObserver: self selector: #selector(updateDateDisplays:) name: #"UpdatedDatesNotification" object: nil];
... which then passes the "formattedDates" (in this case) to the method "updateDateDisplays".
I'm sure that there are some that will tell you that this is somehow wrong but I will argue that 1) it gets the job done with minimal code 2) it's easily readable and searchable and 3) it saves a heck of a lot of time which, if you're doing this for a living, is money.
I wonder what the optimal way is to respond to notifications sent out by the notification centers.
Here is an example:
I have a model which receives updates from the server.
Whenever new information is received a notification is generated and posted though the NSNotificationCenter.
There is a view controller with lots of (partially nested) subviews; depending on the type of information received I have to update a particular subview.
For me, there are currently two solutions:
The view controller becomes observer and tells a particular view to update based on the notification name. [subviewx pleaseUpdate];
Each view registers an a observer and depending on the notification name.
The downside of 1 is that the vc has to deal with all notifications although he is not really affected.
Is there any proposed way to do this? Should the responsible view controller deal with all notifications or is it ok for a UILabel, for instance, to become an observer and be somewhat independent.
Thanks for your opinion!
An interesting question - technically, both approaches produce the same result.
However, personally I'd lean towards keeping your notification handling in the view controller, because that's closer to the model-view-controller (MVC) pattern in iOS.
The other advantage of having your notification in the view controller is that you may want to reuse your views elsewhere in your app, and you don't want adverse side effects happening when views start responding to notifications they weren't intended to receive. Collating all your notifications in the view controller will also make handling them much easier - don't forget you need to remove your notification observers when you're done with the view, and having all your removeObserver statements in one place is arguably far better than spread across multiple classes.
I've been thinking about this and have read through another stackoverflow question regarding the best recommended way to communicate between view controllers. However, the question/answer for that doesn't seem to address the best approach for the reverse behavior.
i.e. to pass data from ParentController to its ModalController, we could initialize ModalController like initWithDataToProcess:.
But what if we want to do the reverse? How would I notify the previous controller about a new data?
e.g. User clicks on 'new person' button on the ParentController. I initiate a new ModalController and present the user with a person editor view via presentModalViewController:. User clicks on 'done' to add a new person. I dismissModalViewController: and UI returns to the ParentController's view.
Using a global field reference in a singleton object (app delegate or other) is bad. delegation (via formal protocol) and notifications (via NSNotificationCenter) seems overkill. Any suggestions?
It is generally cleaner to use notifications. Just add your observer like this....
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(somethingHappened:) name:#"MyNotification" object:nil];
and elsewhere in your code you'd post the notification whenever you need to.
[[NSNotificationCenter defaultCenter] postNotificationName:#"MyNotification" object:self];
In the example I'm passing self but you can pass any object you wish really and it will be fed to your somethingHappened: function
The important thing is to keep the #"MyNotification" very descriptive and unique. Adding your project name to the beginning is a good way to keep things unique...eg. #"ProjAXViewHasGotData"
A delegate is pretty much the minimum you can do. If you think it is too much of a hassle to declare a new protocol for this, just pass in the parent view controller and have the modal one call a method on it.