I am using RestKit in my app for all web/network calls. On launch, in the AppDelegate, I start updating the user's location. By the time the user approves the app to use the location (on first launch), the app would have moved to the RootViewController and started the RestKit HTTP call. The HTTP call requires the user's location, and therefore, will fail.
What are some ways around that? How can I work with Core Location while utilizing RestKit's concurrency?
I am aware that the way the app is structured (update UI upon web service retrieval) is very dangerous. I am trying to avoid as much refactors as I can (management orders). What are ways around this?
Do not ask for location on AppDelegate.
Instead navigate to RootController and in ViewDidLoad, call startUpdatingLocation & immediately pop up a view with processing image like UIActivityIndicator.
Upon getting the location successfully, a protocol method is fired, remove the pop up view here and send the RestKit Call with acquired coordinates.
Related
Lately I have been playing around with the bluetooth framework and grew a strong enough knowledge to start building an application. The only problem is that all the examples I found and all the practice I have made consist in putting the core bluetooth core code inside the same file as the UIView with which the user is interacting.
I would like my future application to have multiple views in which the BLE scan occurs on the background. I initially thought about creating an object with a name similar to bleDeviceFinder and pass this object through each view. However, after thinking about it I realised that if I want something to happen in the current view I need the function didDiscoverPeripheral to have direct access to the UIView objects which it is supposed to affect.
I know it is probably a stupid question, what would be the best way to do so? I was thinking maybe to set and alert and subscribe every view to that alert; is this a good solution?
A quasi singleton BTLEManager that you pass around in the app. It sends NSNotifications for events like discovery, and your ViewControllers observe these notifications. The truth (i.e. list of discovered devices) stays in BTLEManager. Once a viewController has received such a notification it asks the BTLEManager for the list of current devices and then the viewController changes your views accordingly. The Views should never talk to the BTLEManager directly.
That's how I would do it.
I'm using both NSWorkspaceDidActivateApplicationNotification and NSWorkspaceDidLaunchApplicationNotification notifications to know which app the user is interacting with.
The problem is that, if an application is just opened and still launching, I first receive a activate notification, and soon afterwards a launch notification.
Is there any way to know within the activate method that the app is still launching and not yet ready for use? (Still bouncing in the dock)
I see that the ichat sample project by apple does not use the above approach and instead only listens to launch notifications. It then uses kAXApplicationActivatedNotification to add an AXObserver to the app. Is this the preferred way? (And also NSRunningApplications to add an observer to all already loaded apps).
I wanted to keep using just plain simple NSNotifications because I think it may be less memory intensive. (No need to keep an observer around for each and every app loaded).
check the NSRunningApplication object passed in the userinfo of the NSWorkspaceDidActivateApplicationNotification
NSRunningApplication *app = [note.userInfo objectForKey:NSWorkspaceApplicationKey];
if(app.isFinishedLaunching)
NSLog(#"up");
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.
In iOS one can purportedly use the CLLocationManager's startMonitoringForRegion: method to register a delegate to respond to the device moving into a specific geographic region, even when the app isn't launched. From the CLLocationManager Class Reference:
In iOS, the regions you register with the location manager persist between launches of your application. If a region crossing occurs while your iOS app is not running, the system automatically wakes it up (or relaunches it) in the background so that it can process the event. When relaunched, all of the regions you configured previously are made available in the monitoredRegions property of any location manager objects you create.
I assume if the app is relaunched, iOS doesn't actually bring it to the foreground. I couldn't find any good samples illustrating where startMonitoringForRegion fits into an overall application, so my questions are:
Does one have to register the delegate for startMonitoringForRegion from somewhere specific? I'm guessing it can't be plonked in a view controller if we're launching the app without bringing it into the foreground. Can someone give an example with some context around it?
If we decide we do want to bring the app into the foreground as a result of entering the region, how would we do so?
When is startMonitoringForRegion registered with the OS and when is it unregistered? Does the user have to have launched the app at least once (even if it's since been killed) for the initial registration to take place? What about if the user powers off the device? Will our handler be registered the next time the device is powered on, or will the user have to launch the app at least once again?
Does one have to register the delegate for startMonitoringForRegion from somewhere specific? I'm guessing it can't be plonked in a view controller if we're launching the app without bringing it into the foreground.
False. A view controller object still does exists if it's allocated-initialized, even if its contents are not presented.
If we decide we do want to bring the app into the foreground as a result of entering the region, how would we do so?
Not possible using public APIs (I'm not sure whether an app in the background can use - [UIApplication openURL:] with its own URL scheme to bring itself into the background, but I doubt it); however you may be able to use the SpringBoardServices framework to launch your app:
SBSLaunchApplicationWithIdentifier(CFSTR("com.mycompany.theBestiPhoneAppEver"), false);
When is startMonitoringForRegion registered with the OS and when is it unregistered? Does the user have to have launched the app at least once (even if it's since been killed) for the initial registration to take place?
If the user never runs your application, code inside will never be run, so it won't get registered.
What about if the user powers off the device? Will our handler be registered the next time the device is powered on, or will the user have to launch the app at least once again?
Now that's a good question. I don't know it off the top of my head, nor did I find an answer in the documentation (probably you haven't found that either), so I'd say you just better try it yourself to be sure.
I have subclassed RMMessageComposeViewController : MFMessageComposeViewController. The extra functionality that I'm aiming for is for the MFMessageComposeViewController to be able by itself to present a new message compose controller (over itself).
So I should from one RMMessageComposeViewController instance present a new one. The message result from the new instance should be sent to the parent (or "old" one). So I suppose I need to set the parent message compose controller as the delegate when I'm creating the child ("new" one).
Could someone please help me think this out, what instance variables I need to add (parents, children?) How to setup the child message compose controller?
From the docs:
The message composition interface itself is not customizable and must not be modified by your application. In addition, after presenting the interface, your application is unable to make further changes to the SMS content.
What you're trying to do there is explicitly not supported because of security concerns: It would make it easy for an application to forge messages. While you can probably push a view on top of it, I suspect your app would get rejected from the App Store for doing it.
I wouldn't be surprised if MFMessageComposeViewController prevents an application from creating more than one instance at a time, though I haven't confirmed this.