开发者

What is the simplest way to design an iOS static library that provides its own modal UI?

I'm designing an iOS static library that will be used by other developers. This library needs to provide its own modal UI. I'm looking for the simplest way to design the interface between the application and this library to accomplish this. I only need to support iOS 4.0 and above.

Rough architecture

My static library has a very simple API with one class. The application's AppDelegate instantiates this one class and sets itself as a delegate so it can receive notifications. When the application wants the library to show its UI it calls a single method, and then when the library is done with its work it sends a notification through one of the delegate protocol's methods.

I can see two ways to accomplish this.

Option 1

When the application wants the library to show its UI, The AppDelegate passes in self.window, and the library sets its own root view controller, effectively taking full ownership of the UI. When the UI is finished, it notifies the AppDelegate, which then sets its own root view controller o开发者_C百科n the window, taking back ownership of the UI.

Option 2

The library exposes a view controller, which the app can push onto whatever view stack it likes. The app is also responsible for removing the view controller when the library notifies it that the UI is finished.

Issues

With option 1, there may be problems changing root view controllers while in the middle of running an application. With option 2, there may be problems providing a view controller that can work in an arbitrary context (as a full-window view controller, as a sub-view of a UINavigationController, etc).

Another problem with both options is the other UIApplicationDelegate notifications that the AppDelegate may receive, such as applicationWillResignActive: and applicationDidBecomeActive:. The library may need to handle notifications like that to properly maintain its UI. Must the AppDelegate pass each of these to the library when its UI is active?

Is there a better option 3 that I haven't thought of?


Have you considered designing your API to accept a UIViewController:

- (void)presentFromViewController:(UIViewController *)presentingViewController
                         animated:(BOOL)animated
{
    [presentingViewController presentModalViewController:myViewController
                                                animated:animated];
}

That way, your library has full control over how the modal UI is presented, and can also call -dismissViewControllerAnimated: itself rather than relying on the delegate to do so.

Don't bother to pass around -applicationWillResignActive: etc. Simply register for the underlying notifications UIApplicationWillResignActiveNotification etc. in your library class.


Here's how I do it: In your static library create your UIViewController and all the content views that you need programmatically (since you can't easily make Frameworks on iOS you can't easily bundle resources):

UIViewController *controller = [[[UIViewController alloc] initWithNibName: nil bundle: nil] autorelease];
UIView *containerView = [[[UIView alloc] initWithFrame: [UIScreen mainScreen].applicationFrame] autorelease];
containerView.backgroundColor = [UIColor darkGrayColor];

UIWebView *webView = [[[UIWebView alloc] initWithFrame: containerView.bounds] autorelease];
webView.delegate = self;

// ... some other code to setup custom things

[containerView addSubview: webView];

// ... some other code to setup custom things, spinner etc.

then display it with

[[UIApplication sharedApplication].keyWindow.rootViewController presentModalViewController: myViewController animated: YES];

This is cut and pasted from a working static library that's been embedded into two different iOS applications and seems to work well in both. There may be edge cases that this doesn't cover, but I haven't hit them yet :)


Use blocks instead of a delegate. Your view should call a provided dismissBlock stored in a property when it's done, and the caller can do what it needs to do from that block. Have data you need to pass back? Make it an argument of the block or put it in a property of an object accessible from your view controller, as appropriate.

If you have state that needs storing in response to an event, document that and provide a way to save off that info into some data and restore the UI from a block of data. The caller can handle that as they wish.

Precisely how the UI is displayed modally should be up to the client application, but by providing that the UI must indeed be displayed modally, you limit its environment enough that you shouldn't have to worry too much about the host environment.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜