I'm currently trying to get the path of a file from a drag and drop operation inside of a custom view, and then pass that path to my app delegate. I'm currently using the following:
- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
{
NSPasteboard *pb = [sender draggingPasteboard];
NSString *type = [pb availableTypeFromArray:[NSArray arrayWithObject:NSFilenamesPboardType]];
NSArray *array = [[pb stringForType:type] propertyList];
//access the app delegate
NSApplication *myApplication;
myApplication = [NSApplication sharedApplication];
[myApplication uploadFiles:array];
return NO;
}
However, I keep getting a message that says that my app delegate doesn't respond to the "uploadFiles" method. It is declared inside of my app delegate. Am I accessing the NSApplication in the correct manner?
Thanks.
I believe the problem is that you're referring to the application but not its delegate. This should work:
Mac
[(YourAppDelegate *)[[NSApplication sharedApplication] delegate] uploadFiles:array]
replacing YourAppDelegate with your actual app delegate name, and being certain to #import it.
Related
I am working on my first Cocoa Mac OS X program and wondering the best approach to showing the windows.
I have my AppController / MainMenu.xib as the main launch window but have the MainMenu.xib window unchecked for Visible At Launch. I do this because on application load I am checking to see if they are logged in. If not I want to display the Login.xib window instead of the MainMenu.xib. Once logged in, I would open the MainMenu.xib window and close the LoginController I have this in the - (void)applicationDidFinishLaunching:(NSNotification *)aNotification method.
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
NSLog(#"app delegate");
[[NSUserDefaults standardUserDefaults] registerDefaults:[NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"Defaults" ofType:#"plist"]]];
BOOL didAuth = NO;
GTMOAuth2Authentication *auth = [GTMClasses authForService];
if (auth) {
didAuth = [GTMOAuth2WindowController authorizeFromKeychainForName:kKeychainName authentication:auth];
}
if (didAuth) {
[[DataClass sharedInstance] setIsSignedIn:YES];
NSLog(#"Already signed in %#", auth);
NSLog(#"Window: %#", self.window);
// SHOW MainMenu.xib here
} else {
NSLog(#"Not signed in %#", auth);
loginController = [[LoginController alloc] initWithWindowNibName:#"Login" owner:self];
[[loginController window] makeKeyAndOrderFront:self];
}
}
I see that AppController's awakeFromNib gets called before the applicationDidFinishLoadingWithOptions. Would it be best to put that code in my awakeFromNib?
If not, what is the best way to open the MainMenu.xib window from the AppDelegate?
If you have a better approach, what would it be?
PS: AppController is a subclass of NSObject so I don't have access to windowDidLoad or windowWillLoad
awakeFromNib is the first method to get executed.
You can also use alloc or init methods.
You can put your login authentication codes there, without any problem.
You must have seen the application life-cycle, how and when what methods get loaded.
I'm using custom URL schemes to open my app, then get the link and run in a method. But I can't really run the method.
For example, I can't load web views or change labels or text fields. So how do I load web views and change labels?
AppDelegate.m:
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
if (!url) { return NO; }
NSString *URLopen= [[url host] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
ViewController *vc = [[ViewController alloc]init];
vc.URLschemeLink = URLopen;
[vc URLscheme];
return YES;
}
ViewController.h:
#interface ViewController : UIViewController<MFMailComposeViewControllerDelegate> {
NSString *URLschemeLink;
}
-(void)URLscheme;
#end
ViewController.m:
#implementation ViewController
#synthesize URLschemeLink;
-(void)URLscheme {
//for example:
label.text = #"Hello"; //nothing will happen
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.google.com"]]]; //Nothing will happen
NSLog ("Method Works Perfect"); //will happen
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:#"Title:"
message:[NSString stringWithFormat:#"%#", URLSchemeLink]
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
//UIAlertView will work perfectly and show the URLschemeLink from AppDelegate.
}
ok How to load the label/webview anyway?
i tested to pass a bool named runURLscheme (=true) from app delegate.
then i wrote in ViewDidLoad:
if(runURLscheme==true) {
[self URLScheme];
}
but this will not work, it will not run the URLscheme method.
How can i load the labels/webviews anyway?
The main views associated with view controllers are generally lazy loaded. Just because the view controller is initialised, it doesn't mean it's loaded its main view yet. Your views are only safe to access once viewDidLoad has been called.
Generally speaking, this pattern works well:
Store your data independently of any views that display it.
When your custom URL scheme runs, update this data.
Have a method on your view controller that updates its views from this data.
Call this method from viewDidLoad.
If there's a chance this data will be updated after your views have already been loaded (e.g. if you are receiving data from the network), then use notifications or KVO to call your view updating method again.
I made a book for children. Every page is a ViewController. In the beginning, I did all the switching of the ViewControllers in the AppDelegate, but after having troubles with AutoRotation i did all the switching in another ViewController called ViewControllerSwitch.
Before, the code was like this. In the AppDelegate:
- (void)goToNextPage3 {
self.view3 = [[[ViewController3 alloc] init] autorelease];
view3.view.frame = CGRectMake(769, 0, 768, 1024);
[window addSubview:view3.view];
[UIView …SomeAnimationStuff...];
[UIView setAnimationDidStopSelector:#selector(animationDidStop3:finished:context:)];
}
- (void)animationDidStop3:(NSString *)animationID finished:(NSNumber *)finished context: (void *)context {
[self.view1a.view removeFromSuperview];
self.view1a = nil;
}
And here is the code from one of my view controllers ("pages") called ViewController1a:
- (void)buttonClicked {
MyBookAppDelegate* next2 =(MyBookAppDelegate *) [[UIApplication sharedApplication] delegate];
[next2 goToNextPage3];
}
This worked like a charm.
Now all my switching is in ViewControllerSwitch. How should I change the code in ViewController1a to access goToNextPage3?
I tried this:
- (void)buttonClicked {
ViewControllerSwitch* next2 = (ViewControllerSwitch *) [[UIApplication sharedApplication] delegate];
[next2 goToNextPage3];
}
It gives me a SIGABRT at [next2 goToNextPage3].
Any ideas?
Update:
i am still trying, so now i did this:
in my Viewcontroller1a.h:
#import <UIKit/UIKit.h>
#import "ViewControllerSwitch.h"
#class ViewController2;
#class ViewControllerSwitch;
#protocol ViewController1Delegate;
#interface ViewController1a : UIViewController
{
id<ViewController1aDelegate>myDelegate;
}
#property(nonatomic, assign)id<ViewController1Delegate>myDelegate;
#end
#protocol ViewController1Delegate
-(void)goToNextPageV;
#end
and in my .m file:
- (void)buttonClicked {
[self.myDelegate goToNextPageV];
}
i know there is something missing in the ViewControllerSwitch but i don´t know what.
As LordTwaroog said, this line is returning an object (your app delegate) of type MyBookAppDelegate:
[[UIApplication sharedApplication] delegate];
Then you're attempting to cast it to be an object of type ViewControllerSwitch with this:
(ViewControllerSwitch *)
This is incorrect. Your app delegate is an NSObject subclass conforming to the UIApplicationDelegate protocol. It's not a view controller.
The correct code might look like this:
- (void)buttonClicked {
ViewControllerSwitch* next2 = [ViewControllerSwitch alloc] initWithNibName:#"ViewControllerSwitch" bundle:nil]
[next2 goToNextPage3];
}
But depending on your app structure this might not be what you want. This is creating a brand new object of type ViewControllerSwitch. It's not returning the possibly-already-existing other ViewControllerSwitch object.
When you were using the app delegate to perform the switching, you had the benefit of being able to retrieve the existing app delegate object (rather than retrieving a newly created object of it's type). The app delegate is a singleton object, easily retrieved by calling [[UIApplication sharedApplication] delegate]. However, your ViewControllerSwitch object might not be set up as a singleton. So your access to it will depend on your object ownership structure. We'd have to see more of your code to help you with that.
[[UIApplication sharedApplication] delegate] still returns MyBookAppDelegate. Why do you try to get ViewControllerSwitch object out of it? You should use your ViewControllerSwitch object. Can you provide more code details on this object?
Possible solutions (if I understand you well):
Put your ViewControllerSwitch as an object in AppDelegate, so you could use:
ViewControllerSwitch *switch = [[[UIApplication sharedApplication] delegate] viewControllerSwitch]
Each ViewController can have a reference to your ViewControllerSwitch
Each ViewController should have a delegate with protocol (e.g.) ViewControllerDelegate, which will have a method to perform switching. Then after setting the delegate to appropriate object, you'll be able to switch your pages
I'm using a modified View-Based Application, where I have starting UIViewController showing a input control & a TTThumbsViewController showing the results. I'm passing them in the AppDelegate using TTNavigator initWithName: for the TTThumbsViewController.
I did this by myself reading from the documentation:
The ViewDidLoad method inside my TTThumbsViewController:
- (void)viewDidLoad {
self.photoSource = [[PhotoSource alloc]
initWithType:PhotoSourceNormal
title:myTitle
photos:myImages
photos2:nil
];
}
The implementation of my AppDelegate:
#implementation geoFlickrAppDelegate
#synthesize window=_window;
#synthesize viewController=_viewController;
#synthesize navigator;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
navigator =[TTNavigator navigator];
navigator.window = self.window;
TTURLMap *map = navigator.URLMap;
[map from:#"app://home/" toViewController:[geoFlickrViewController class]];
[map from:#"app://album/(initWithName:)" toViewController:[AlbumController class]];
[navigator openURLAction:[TTURLAction actionWithURLPath:#"app://home/"]];
// Override point for customization after application launch.
[self.window makeKeyAndVisible];
return YES;
}
-(void)toGallery:(NSString*)txt
{
[navigator openURLAction:[TTURLAction actionWithURLPath:txt]];
}
The event inside my UIViewController for pushing the next view:
-(IBAction)search:(id)sender
{
NSString *str = [[NSString alloc] initWithFormat:#"app://album/%#",txtSearch.text];
geoFlickrAppDelegate *appDelegate = (geoFlickrAppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate toGallery:str];
}
The result from this code is that the input is passed through my AppDelegate in the TTThumbsViewController using initWithName: but the never gets pushed in & my ViewDidLoad method never gets called. Any idea why is that so?
Whenever I had an error like this, it was the initializer (in your case initWithName:) returning nil. This is the first thing I would check. If that doesn't solve try setting a breakpoint in [TTBaseNavigator presentController:parentURLPath:withPattern:action:].
If that method is not reached something is wrong with your URL-Map. You may for Example need to urlencode your users input. URL-based Navigation works with URLs. Strings that can not be used in URLs can not be passed unencoded.
If that method is reached, you may use the debugger and step through the code from there to find out whats wrong.
Another thing I would like to mention, is that you really do not need to reference your appDelegate with [[UIApplication sharedApplication] delegate] when you like to use the navigator. This is one of the reasons why the navigator is so useful. Try to change the call to:
-(IBAction)search:(id)sender
{
NSString *str = [[NSString alloc] initWithFormat:#"app://album/%#",txtSearch.text];
TTOpenURLFromView(str, self.view);
TTOpenURL(str); // Three20 < 1.0.3
}
You can then get rid of the toGallery: method.
In my code I have no:
navigator.window = self.window;
and instantiate the window calling:
navigator =[TTNavigator navigator];
navigator.window;
and also change [self.window makeKeyAndVisible] into
[navigator.window makeKeyAndVisible]
I have an iOS application for which I want to create a ViewController programmatically.
I started an empty XCode project and modified the main method so it looks like this
int main(int argc, char *argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
int retVal = UIApplicationMain(argc, argv, nil, #"MyAppDelegate_iPad");
[pool release];
return retVal;
}
The app is a Universal Application, MyAppDelegate_iPad is a subclass of MyAppDelegate, which is a subclass of NSObject <UIApplicationDelegate>.
My problem is that the applicationDidFinishLoading method I've overridden in MyAppDelegate_iPad is never called (break point on the first line never hits). The method looks like this
-(void) applicationDidFinishLaunching:(UIApplication *)application {
window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
if(!window)
{
[self release];
return;
}
window.backgroundColor = [UIColor whiteColor];
rootController = [[MyViewController alloc] init];
[window addSubview:rootController.view];
[window makeKeyAndVisible];
[window layoutSubviews];
}
I removed the line to link to a nib file from my plist file (I used to get the default "My Universal app on iPad" white screen) and now all that is displayed is a black screen. applicationDidFinishLoading is still not being called.
Am I doing something wrong? How should I properly create my AppDelegate instance?
There’s a main nib file that bootstraps your application. This nib file is referenced in the Info.plist file under the NSMainNibFile key and should contain an object that corresponds to your application delegate class (setting the Class attribute in Interface Builder). This application delegate object is referenced by the delegate outlet on the file’s owner placeholder.
So if I understand things correctly, the application loader loads the main nib file, setting itself as the nib owner. Its delegate property gets set to a fresh instance of your application delegate class, and so the loader knows where to dispatch the various application lifecycle event callbacks.
There’s an awesome blog post about Cocoa application startup on Cocoa with Love.
If you are making universal you don't need two different app delegate classes. see this link (my answer), it may be help you to make universal app.