问题
Disclaimer: I'm an iOS noob.
I created a view based app using Xcode's template that uploads pictures to a website. Xcode created AppDelegate.m (& .h) and ViewController.m as well as a storyboard for me automatically. The app is launched from a website using a URL schema, and I use that information in my view controller. I have two questions:
1) Is this a good way to pass query strings from my AppDelegate to the view controller?
I have a NSDictionary property in my AppDelegate called queryStrings which stores the query strings. Then in viewWillAppear in my view controller I use the following code to access it:
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSDictionary *queryStrings = appDelegate.queryStrings;
wtID = [queryStrings valueForKey:@"wtID"];
2) When the app is already launched but in background and the user opens the app again via a url on the webpage (with different query string), I have implemented openURL in the AppDelegate which populates my queryStrings property in the AppDelegate. Problem is: the view controller's viewWillAppear method is never called so the above code isn't executed. How do I get the query string data to the view controller? How does the view controller know the app just became active?
NOTE: Because the project was created using the "view-based app" template in Xcode, the only property my AppDelegate has is the window property. I can't tell where in code that my view controller is ever even referenced by the AppDelegate... It's never set as the rootViewController or anything in the code anyway... I guess it's just some IB magic that I can't see.
In case it helps, here's my AppDelegate.h:
#import <UIKit/UIKit.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@property (strong, nonatomic) NSDictionary *queryStrings;
@end
and here's my didFinishLoadingWithOptions, openURL, and my helper method: parseQueryString:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
[[JMC sharedInstance] configureJiraConnect:@"https://cmsmech.atlassian.net/" projectKey:@"WTUPLOAD" apiKey:@"7fc060e1-a795-4135-89c6-a7e8e64c4b13"];
if ([launchOptions objectForKey:UIApplicationLaunchOptionsURLKey] != nil) {
NSURL *url = [launchOptions objectForKey: UIApplicationLaunchOptionsURLKey];
NSLog(@"url received: %@", url);
NSLog(@"query string: %@", [url query]);
NSLog(@"host: %@", [url host]);
NSLog(@"url path: %@", [url path]);
queryStrings = [self parseQueryString:[url query]];
NSLog(@"query dictionary: %@", queryStrings);
}
else {
queryStrings = [self parseQueryString:@"wtID=nil"];
}
return YES;
}
-(BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
NSLog(@"openURL executed");
if (!url)
return NO;
NSLog(@"query string: %@", [url query]);
queryStrings = [self parseQueryString:[url query]];
mainViewController.wtID = [queryStrings valueForKey:@"wtID"];
return YES;
}
-(NSDictionary *)parseQueryString:(NSString *)query
{
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] initWithCapacity:6];
NSArray *pairs = [query componentsSeparatedByString:@"&"];
for (NSString *pair in pairs)
{
NSArray *elements = [pair componentsSeparatedByString:@"="];
NSString *key = [[elements objectAtIndex:0] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *val = [[elements objectAtIndex:1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
[dictionary setObject:val forKey:key];
}
return dictionary;
}
Thanks in advance!
回答1:
So, storyboards are starting to get on my nerves, and I'm not even building your app! :)
As I have stated in your other question (of which this is a duplicate, but hey), the lack of the reference to the view controller is due to storyboards. viewDidAppear and viewWillAppear get called when the view is added to the hierarchy. Going to and from the background and foreground doesn't qualify as being added to the hierarchy. Luckily, your app sends notifications that correspond to the methods in the AppDelegate. Simply register as an observer of the UIApplicationWillEnterForegroundNotification notification. Then you can update your UI in the method that gets fired as a result of receiving that notification!
EDIT: Adding the link to the duplicated question for good measure: How do I access my viewController from my appDelegate? iOS
回答2:
Hm, so why there is no UIViewController
declared in your AppDelegate
?
UPDATE
When you created a new project, you should have smth like this in your AppDelegate
:
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@property (strong, nonatomic) UIViewController *viewController;
@end
//
#import "ViewController.h"
@implementation AppDelegate
@synthesize window, viewController;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.viewController = [[ViewController alloc] init];
[self.window setRootViewController:self.viewController];
[self.window makeKeyAndVisible];
return YES;
}
//...
@end
来源:https://stackoverflow.com/questions/10017305/viewwillappear-is-not-called-in-my-view-controller-when-the-app-becomes-active