handleGetURLEvent:withReplyEvent: in AppDelegate obscured by KVO? - objective-c

i'm seeing a weird issue trying to add custom URL support to my Mac app. i've defined the URL(s) in Info.plist, and when i navigate to them my app gets launched (or, if running, activated), but then, regardless of whether my app delegate implements handleGetURLEvent:withReplyEvent: or not, i see a couple of the following messages in the debug output:
+[NSKVONotifying_MyAppDelegate handleGetURLEvent:withReplyEvent:]: unrecognized selector sent to class 0x1d096e0
Apparently, NSKVONotifying_MyAppDelegate is a wrapper created by KVO for my real delegate (called MyAppDelegate), and that seems to obscure my implementation of handleGetURLEvent:withReplyEvent:, which never gets called. AFAICT, nothing in my app uses KVO on the delegate, and i'm running out of ideas as to what could be causing this.
any suggestions?

turns out the KVO thing was a red herring. the method needs to be static, as careful reading of the error message (or docs) would have made clear, while i had an instance method (as one would expect, for delegate methods? weird API design choice).

Related

Why won't an NSWindow restore its state (using Resume in Lion)?

I'm working on implementing Resume in my formerly Snow Leopard app. For my app's main window, I checked the Restorable checkbox in Interface Builder, and everything's working fine. Its delegate has -window:willEncodeRestorableState:state and -window:didDecodeRestorableState: called on it, just fine. Everything works.
I have another window that is also going to sometimes be open when the user quits. I checked Restorable for it, and implemented the two methods above. ..willEncode.. gets called when I quit with the window open, but ..didDecode.. never gets called, and the window doesn't get restored. I've read through the documentation and it seemed like I may want to create a restoration class, but the docs weren't particularly clear on how to do so.
I tried implementing the <NSWindowRestoration> protocol in my AppDelegate, and in my second restorable window's delegate, but the +restoreWindowWithIdentifier:state:completionHandler: method never got called for either of them.
What am I missing? Am I on the right track with NSWindowRestoration but not doing it right? The way the docs talked about the restoration class, it sounded like there would only be one. Do I need to specify it in the app's plist or something?
What the above linked Resume documentation neglects to mention is NSWindow's -restorationClass property. If you set this property in code (to a class that implements <NSWindowRestoration>, then that class is responsible for creating the window.

Calling delegate method, unrecognized selector because sending to wrong object

In my app I do a lot of network loading. My data model consists of "Loader" objects that do this loading and call their delegate when finished/failed. The delegates all conform to a "LoaderDelegate" protocol.
The issue I'm having is that sometimes seemingly random objects, not the delegate, are getting the delegate messages. This of course causes a crash because of an unrecognized selector.
Only one set of crash logs tell me which one of my loaders is having the issue, the others don't have that information, just the random object that got the message.
I'm stuck at how to determine the real cause of this issue.
One set of crash logs has a loader trying to call it's delegate but reaching _UIImageViewExtendedStorage. Another has a loader is reaching __NSCFInputStream. Another __NSBlockVariable__. And yet another, CALayer.
And that's just in my latest beta from 3 days ago.
It would be one thing if it was the same object each time, but it seems almost random. Is it possible that memory is getting overritten with a new object somehow?
My delegate property for all of my loaders is an assign property, but the delegate is always alive when the loader finishes (delegates are my view controllers calling the loaders).
Please post some code, cause it is hard to troubleshoot. Remember to nil your delegate in the dealloc.
- (void) dealloc {
objectOfWhichIAmTheDelegate.delegate = nil;
}
What is more you the delegate should be an assign property not retain - but that's not a problem in your situation.
#property (assign) id<TheMightyDelegate> delegate;
Another thing you should do is to guarantee that the delegate responds to the selector you want to send to him before you fire the method.
if ([delegate respondsToSelector:#selector(yourMethod)]) {
[delegate performSelector:#selector(yourMethod)];
}
Hope this will put some light on your problem. If not please provide some code.
Turns out I was getting this error randomly all over the place, just not in this particular class and not just with delegate methods.
In my case, the problem turned out to be that I was accessing properties of various classes in multiple threads and those properties were nonatomic. Since I fixed that (removed nonatomic attribute of the properties), I haven't seen this happen anymore.

Where do FirstResponder methods come from?

I'm looking at IKImageDemo supplied by Apple, the rotate round-slider is linked to a setRotation: method in the FirstResponder. However, none of the objects in the project seem to HAVE such a method, and yet the code works.
I'm trying copy this into my own project, and MY FirstResponder doesn't have a setRotation: method, so I'm not sure where it lives. Google has been unhelpful...
thanks.
Well, the first responder in the app happens to be an instance of IKImageView. IKImageView responds to the setRotation: selector (which can be seen by passing respondsToSelector:#selector(setRotation:) to any instance of IKImageView), although I cannot find where in documentation it mentions the setRotation: method
First Responder methods aren't magic. What happens when a message is sent to the first responder is that the app's current first responder (this is usually the focused view/control) is asked whether or not it implements the method. If it does, the method is called. If it doesn't, the next responder up the chain is asked, and so on until the top level (the NSApplication instance) is reached. The object must actually implement the method for it to be called, it can't just declare it.
In this case IKImageView implements -setRotation: as a private method. This means that the method is present (which is why the IKImageView accepts the message sent to the First Responder) but its use is not documented or supported. It seems odd that Apple would ship an example using a private method but there you go. It's definitely the case that sometimes methods are accidentally left out of the public headers when their use is supported, however it's generally wise to avoid private methods unless someone from Apple has specifically told you it's OK to use one.
You can generate headers for all methods of an Objective-C object, including private methods, from the binary using class-dump.
IKImageView has a public method -setRotationAngle: which is probably the way to go if you want to change the rotation.
I've found a way of resolving this annoyance. Even in the original Apple example, once you remove the binding for setRotation in the First Responder, you cannot put it back, unless doing this trick: simply use the Attributes Inspector for the First Responder and add a User Defined action "setRotation:" with type "id". Now even the yellow triangle in the First Responder binding for setRotation: in the Apple example disappears, and it shows up also in my own IKImageView instance.

Checking for a valid delegate object before sending it a message

I am trying to implement the delegate Pattern in Objective-C, however I am experiencing a Bad Access exception when invoking the delegate sometimes. It seems this is caused by the delegate being released. Apple does not recommend to retain delegates.
How can I check my delegate if is still valid before trying to send it a message?
If there's a chance that the delegate will get released by the setter, then there's something wrong with your design. You should only set delegates on objects that have a shorter lifespan than the delegate itself. For example, setting a delegate on a subview/controller is fine, because the subview/controller has a shorter lifespan than the caller.
AFAIK, there is no reliable way to detect if an object has been released already.
What Apple means about not retaining delegates is that objects should not retain their delegates because they don't own them. These are only objects that handle messages.
That doesn't mean that you shouldn't retain delegates at all. The object that creates the delegate needs to own it. In the context of non-GC apps this means it should handle the retain and release cycle, and for GC apps, it means that the controller object keeps hold of a pointer to the delegate in an iVar.
without seeing some code or the error message, it is hard to find the root of this problem.
In a photoviewer application I'm using asynchronous http to load images; it happens that the user often dismisses the current view (referenced by my async http object through a delegate) before the http download completed causing a BAD_ACCESS when calling the view controller delegate method. I solved this by setting the .delegate to nil inside the dealloc block of the view controller
I'd like to share my experience also, which is very similar to Nico's one.
I've been working with a modified example of LazyTablesCode, wich is an example that comes direcly from Apple and loads images in a UITableView asynchronously. Communication between the downloader and the view it's made via delegates.
In my code, I had the problem that sometimes the load of the image finishes when the form that should be called through the delegate has been released. I've been forced to add this piece of code inside the code of the viewController (dealloc method):
if (self.nsDictionaryWithObjectsDownloading != nil) {
for (id theKey in self.nsDictionaryWithObjectsDownloading) {
Myobj *downloader = [self.nsDictionaryWithObjectsDownloading objectForKey:theKey];
downloader.delegate = nil;
}
}
It seems that these lines are solving the problem. Anyway It would be very appreciated opinions about if it's a good solution or not or even about memory issues when doing downloader.delegate = nil;
Thanks and greetings,

Am I using NSTimer correctly in iPhone View-based app?

I'm working on a simple proof-of-concept for an iPhone app (and important bit of info, I'm pretty new to Mac OSX development all around). I created a view based app with a timer. I declared my NSTimer in the interface of my app's controller, used #property and #synthesize, and I initialize it in the controller's viewDidLoad method with scheduledTimerWithTimeInterval method. My selector is a method with the signature -(void)someMethod:(NSTimer *)timer which is declared in the interface and defined in the implementation file of the controller as well. I can step past the line where I assign the timer and see that it points to a valid object, but my program goes no further than the end of the viewDidLoad method and never reaches the breakpoint at the first line of my method that is called by the timer. Also, I see GDB: Program received bad signal: "EXC_BAD_ACCESS" in the status bar of xcode at this point (viewDidLoad end is reached). I didn't do anything in IB but add a view and a picker just so I'd see if the UI actually loads...it never does.
So, am I doing something wrong with the NSTimer, or are my troubles elsewhere? How can I use the debugging tools in xcode to get more information?
EXC_BAD_ACCESS usually indicates a memory management error, without seeing the code probably from somewhere else in your app. It's a very common error for beginners, but an important subject to fully understand, so I'd suggest looking through some of the questions on memory management here and find a few guides or tutorials to look through. It's actually pretty easy to learn.
Also, it shouldn't hurt but unless you need to access the timer in between fire events, you don't actually need to store it as an instance variable. Once you create and start a timer it's added to and retained by the application's run loop.
Have you got NSZombieEnabled?
Might be useful if this is failing on an over released object.