Cocoa NSBundle loadNibNamed deprecated - cocoa

I'm developing a Cocoa App and I noticed NSBundle loadNibNamed is deprecated.
I'm trying to use a Sheet to show some config options. I'm using an AppController and the Config Sheet is a NIB created separately.
This is my code.
- (IBAction)showConfig:(id)sender{
if (!_config) {
[NSBundle loadNibNamed:#"Config" owner:self];
}
[NSApp beginSheet:self.config modalForWindow:[[NSApp delegate] window] modalDelegate:self didEndSelector:NULL contextInfo:NULL];
}
Using that code, the config Sheet opens and closes perfectly.
When I switch this [NSBundle loadNibNamed:#"Config" owner:self]; to [[NSBundle mainBundle] loadNibNamed:#"Config" owner:self topLevelObjects:nil]; the config Sheet still works fine.
My real problem is when I want to close it. The app crashes throwing this error:
Thread 1:EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
This is my IBAction to close the config Sheet.
- (IBAction)closeConfig:(id)sender{
[NSApp endSheet:self.config];
[self.config close];
self.config = nil;
}
Once I skip the deprecated line, what do I need to do to close the config sheet correctly?
I'm running Yosemite and Xcode 6.4.

Is the window property in your app delegate class weak? If so, see this answer. The not-deprecated method that you are now using requires your controller to have strong references to the top level objects.

Related

Has there been a change to the way Mac OSX Mavericks handles CFBundleURLName "Custom url" launches for applications?

I created an app which is launched from a custom url in any OSX browser. This worked just fine by adding a standard CFBundleURLName entry to the app's plist.
My application works by reading by parsing some of the parameters on the custom url and then reacting to them.
So for example with a custom url of:
foobar://param1/param2/param3
When clicking on the above url in a browser, OSX would launch my app and pass the actual custom url itself as the first argument to the app. Therefore in the app I could read the first arg and get the url the opened the app, and parse it for params I need.
This works fine in OSX 10.5-10.8, but in 10.9 Mavericks it appears to work slightly differently. Namely that if the application is not already running, it still launches the app but does not pass the custom url as first argument - so the app thinks it's just been launched manually by the user (such as selecting it from launchpad) rather than directly from a browser.
Weirdly, if the application is already open, then clicking the custom url DOES send the url string over to the app as first argument and functionality within the app occurs as expected.
I've tested this across 10.6->10.9 with new and old versions of my app and all exhibit the same behaviour. All work fine on first launch with versions before 10.9 Mavericks, but in 10.9 they don't get the url passed as first arg but then work on 2nd click once already running.
If anyone could shed some light on this I would be very grateful.
Where do you set up your URL handler? It needs to happen early. If you currently have it in applicationDidFinishLaunching, try to move it to applicationWillFinishLaunching.
The following works for me and logs the URL at launch even when the app is not running before I open the URL in Safari, for example. When I change WillFinishLaunching to DidFinishLaunching, I see exactly the behavior you describe.
#implementation AppDelegate
- (void)applicationWillFinishLaunching:(NSNotification *)notification
{
NSAppleEventManager *appleEventManager = [NSAppleEventManager sharedAppleEventManager];
[appleEventManager setEventHandler:self andSelector:#selector(handleGetURLEvent:withReplyEvent:) forEventClass:kInternetEventClass andEventID:kAEGetURL];
}
- (void)handleGetURLEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent
{
NSAppleEventDescriptor *obj = [event descriptorForKeyword:keyDirectObject];
DescType type = [obj descriptorType];
if (type == typeChar) {
NSData *data = [obj data];
if (data) {
NSString *urlString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSURL *url = [NSURL URLWithString:urlString];
NSLog(#"url: %#", url);
}
}
}
#end

how to make NSURL point to local dir?

reading Adium code today, found an interesting usage of NSURL:
NSURL *baseURL = [NSURL URLWithString:[NSString stringWithFormat:#"adium://%#/adium", [messageStyle.bundle bundleIdentifier]]];
[[webView mainFrame] loadHTMLString:[messageStyle baseTemplateForChat:chat] baseURL:baseURL];
I tried to log the url and got this adium://im.adium.Smooth Operator.style/adium, Then I created a blank project to see how to create such an NSURL but failed. When I sending loadHTMLString message to a webview's frame in my project, if the baseURL is nil, everything is fine, if not, I got a blank page in the view.
here is my code, the project name is webkit
NSURL *baseURL = [NSURL URLWithString:#"webkit://resource"];
//if baseURL is nil or [[NSBundle mainBundle] bundleURL], everything is fine
[[webView mainFrame] loadHTMLString:#"<html><head></head><body><div>helloworld</div></body></html>"
baseURL: baseURL];
[frameView setDocumentView:webView];
[[frameView documentView] setFrame:[frameView visibleRect]];
the question is how to make a self defined protocol instead of http://?
adium://%#/adium , first section is called protocol you can also register your protocol webkit: Take a look at How to map a custom protocol to an application on the Mac? and Launch Scripts from Webpage Links
[NSURLProtocol registerClass:[AIAdiumURLProtocol class]];
[ESWebView registerURLSchemeAsLocal:#"adium"];
I tried to find where did adium define the adium schema in the info.plist, unfortunately, there's nothing there, only some irc/xmpp protocols.
so I finally launched the debugger, and found the code above in the AIWebKitDelegate init method, anyway this is another way to register a self defined protocol~

NSWorkspace launchApplication:showIcon:autolaunch: - how to check autolaunch flag?

I have implemented a login item as I was recommended in this post. In the helper app I launch the main app using NSWorkspace method launchApplication:showIcon:autolaunch:, sending YES to autolaunch parameter.
The problem is in following: I need to check if the applications was autolaunched not to show start tooltip. The only variant I found is [[NSUserDefaults standardUserDefaults] boolForKey:#"autolaunch"], and it returns NO always.
The problem could be solved using launch arguments - but sandbox, unfortunately, cuts them too.
Is there something I missed?
I use the following code to hide the launched application:
[[NSWorkspace sharedWorkspace] launchApplicationAtURL:[NSURL fileURLWithPath:appPath] options:NSWorkspaceLaunchAndHide configuration:nil error:nil];
If you want to set additional parameters, you can give the method a custom configuration dictionary.
If you have the launcher inside the application bundle:
NSString *appPath=[[[[[[NSBundle mainBundle] bundlePath] stringByDeletingLastPathComponent] stringByDeletingLastPathComponent] stringByDeletingLastPathComponent] stringByAppendingPathComponent:#"MacOS/myApp"];

mfmailcomposeviewcontroller crashing on iOS 6

Normally, when I use mfmailcomposeviewcontroller like so:
if ([MFMailComposeViewController canSendMail])
{
MFMailComposeViewController *mcvc = [[MFMailComposeViewController alloc] init];
mcvc.mailComposeDelegate = self;
[mcvc setSubject:#"Check out these diamonds!"];
[self presentModalViewController:mcvc animated:YES];
[mcvc release];
}
And I am now getting this error on iOS 6:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException',
reason: 'Could not load NIB in bundle: 'NSBundle </Users/ericshorr/Library/Application Support/iPhone Simulator/6.0/Applications/7904C2AD-23E1-4211-B5FA-A1F03CB3A875/SDE Group Diamonds.app> (loaded)' with name 'MFMailComposeInternalViewController''
Because you need to setup a mail account in your iPad to be able to send mails in iOS 6. Go to Mail, Contacts, Calenders in Settings, then add a mail account.
I had a similar issue recently where I added a category to UIViewController, so that I could override init and append an additional modifier to the nib name. Like so...
self = [self initWithNibName:[nibName stringByAppendingString:#"_modifier"] bundle:nil];
Although the UIViewController category was not #imported in the class that was attempting to launch the MFMailComposeViewController, it was imported in the header of a different class that was being added as a child view controller. Hence, the MFMailComposeViewController was trying to find a NIB with name: MFMailComposeInternalViewController_modifier.
Seems obvious in hindsight but this was a nightmare to catch, so I thought I'd add it here as a possible solution, for anyone else who runs in to a similar situation.

Making a button change the webview

I'm trying to make a mac app using the apple developer tools, specifically xcode. I'm basically imbedding my website into in in a sort of iTunes-esque way- side bar at right, user clicks a button on side bar and webview web page changes. Problem is I'm having trouble trying to get the button to load a specific URL into the webview.
WebView* webView = [[WebView alloc] initWithFrame:CGRectMake(0, 0, 500, 500)];
NSString *urlAddress = #”http://www.example.com”;
NSURL *url = [NSURL URLWithString:urlAddress];
NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];
[webView loadRequest:requestObj];
So you first get the url as a string, turn it into an NSURL object, and then into an NSURLRequest object and finally give that to the webview object to load. You could also do this with a webview created in Interface Builder by ommiting the first line (where the webview is being initialised) and make sure you add the webView property to the viewcontroller as an IBOutlet and connecting it to the webview in Interface Builder.
Edit: It seems I was using iPhone syntax for the webview. Loading a url on a mac webview however is still similar, so all I've changed is the class name.

Resources