Accessing recipients, body etc in an MFMailComposeViewController - objective-c

I'm currently working on persisting the UI state of my iPhone app across launches, but it's proving to be a bit of an issue in one of my controllers - a sub-classed MFMailComposeViewController.
Essentially, I need to store (on app exit) the current To/CC/BCC lists, the subject, and the body so I can set the view up again after a relaunch. Unfortunately, Apple seems to have only provided setter methods for this data (e.g. setToRecipients:).
No doubt there's some private getters in there somewhere, but I'd rather not risk getting bounced by the App Store approvers...
Any thoughts/suggestions?

The best bet is to use controller.view, and search for all UILabels in the subview hierarchy.
(Also, there aren't private getters for MFMailComposeViewController. Those setters only delegates the message to its internal implementation class.)

Related

Best Practices When Using CoreBluetooth Framework

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.

Is this a valid use of NSNotificationCenter

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.

Using `valueForKey` to access view in UIBarButtonItem, private API violation?

Since UIBarButtonItem doesn't subclass UIView, it's impossible to get at the normal characteristics like its frame.
One way to do this is [barButtonItem valueForKey:#"view"]
This works perfectly, and allows you to add a GestureRecognizer (for instance) to the underlying UIView.
However, is this a private UIKit API violation?
This is not private in terms of immediate rejection upon validation, but it's private enough to be considered fragile (that is, new iOS version can break your existing app in the app store that's using the code).
I can say, that a similar code (fetching backgroundView ivar of UIToolbar via KVC) has passed app store validation and is being used in production.
In case of possible bad things, you must wrap the method in #try { ... } #catch, so that you intercept KVC possibly failing in newer iOS release.
Five Pieces of Evidence for "It's Not Private"
It's a property that you can get to in other ways. Try this and one of those views is, in fact, the _view ivar of the UIBarButtonItem in question. This indicates that access to this UIView is not prohibited itself, though the KVO way in might be questionable (but I doubt it).
NSArray *array = self.toolBar.subviews;
for (UIView *view in array) {
view.backgroundColor = UIColor.greenColor;
}
They actually trigger the KVO for this property. ivars do not have to trigger the KVO API, right?
#Farcaller mentions a similar case which is for sale in the App Store. Since he/she answered within the first 20 minutes of the question being up there, it's reasonable (but not safe!) to assume that there might be thousands of apps in the App Store that do this.
This UIView gets subbed out each time the button is pressed, so you cannot just, for example, set a gesture recognizer on it and be done. You can, however, keep setting the same gesture recognizer every time the view gets replaced. To me, this is actually more evidence that it's not a private API thing, but rather you have to be very careful when using it (and use KVO to make sure you have the latest one).
My app is for sale in the App Store and does this.

Application Delegate Usage

I'm fairly new to Objective-C and cocoa programming, so I don't really understand the concept of App Delegates.
When we create a cocoa application, do we store our code (Methods, actions, outlets) in the App Delegate files or do we create a new file that will act as a controller and code from there. Right now, I put all of my code in those two files, but from what I read, your goal is to try to make your App Delegate files as slim as possible.
My question is: What's the usage of the app delegate files?
Talking about applicationDidFinishLaunching::
It's just your application entry point. Normally you only create the window and your first ViewController, or your Tabbar - your main starting interface class - here.
All the other delegate methods of the NSApplicationDelegate have other functions of course. Most of them are the point, where you react on the state of the app. Opened / Closed / Backgrounded / Reopened etc.
But you should probably have a look at the programming tutorials in the iPhone documentation. There is a lot of information on how to structure your objc projects. E.g. look here: Start Developing iOS Apps Today
Or if your looking for OSX Apps, look here:
1) Your First Mac App
2) Mac App Programming Guide
There is also a bunch of Sample code.
The App Delegate is a handler location to handle events that occur on the application. Things like open and close. It also hangs around the whole time the application is executing and you can grab the singleton instance at any point by doing [[NSApplication sharedApplication] delegate].
This comes in handy for handing objects between controllers and serving as a router for events. You can also store some data on the delegate if you need to modify/have access to it in different parts of the code.
This all works well for simple applications, but as things become more complex, you need to have some division of responsibilities. The AppDelegate should really only be responsible for actions that occur on the application itself, not on another view or a controller. Putting all/most of your code in the AppDeligate is certainly bad practice and will lead to horrible code as things get more complex and need to be maintained.

Hacking UINavigationBar / Apple approval

Here is a screenshot from Evernote. It appears to have (but i might be wrong) a custom UINavigationBar as well as a custom UITabBar.
A quick glance at the apps on my phone shows i could use a screenshot of Instagram, Path, DailyBooth, ...
From the docs:-
Because managing the navigation bar is
the responsibility of the navigation
controller, direct modification of the
navigation bar itself is considered
off limits for the most part.
Does Apple regard this kind of thing as grounds for AppStore refusal?
There's a distinction between "custom" navigation bars and using private methods.
Apple prevent you from directly modifying the navigation bar by make a lot of the required methods private or properties read-only. If you were to modify a read-only property or use a private undocumented method your application would be rejected (Apple automatically analyse code upon submission to detect for this sort of thing).
However, there's nothing to stop you from implementing your own UINavigationBar equivalent, or customising it using publicly available SDK methods. The issue then becomes whether your application strays too far from the Human Interface Guidelines: although to be honest, Apple are generally fairly flexible on that.
Whilst I wouldn't necessarily recommend this, I've worked on one app where we rolled our own navigation controller because we had some animation and transition requirements that we couldn't achieve with Apple's own class. As long as you're not calling anything untoward or drastically going against the HIGs, you're generally fine.