Passing data to Cocoa Quartz event tap callback - bad casting from void* - objective-c

I am writing a simple logging program in Cocoa.
I create my callback function to log pressed keys into file, but here comes the problem. I have file handler in my AppDelegate and I can't reach it from inside the callback function.
I tried to pass it inside via last parameter of callback function (the void* one), but inside i have to cast it back to NSFileHandle - but to do that I have to "bridge-cast" it. But whether I use __bridge or __bridge_transfer the program crashes.
I am new to Objective-C so maybe I am missing something obvious, but I had searched "all" the internet, Quartz reference, Stack overflow and googled for few hours so I will appreciate every tip.
Thanks - M

I'm surprised the cast to void * (when you create the tap) is being allowed at all. Isn't the compiler giving you an error on that? The ARC spec says it's verboten.
Having a void pointer be your only strong reference to an object is an anti-pattern. Either that object should be the owner of (in this case) the event tap, or an object should own both the tap and the object that needs to be kept alive. Making the event tap be owned instead of the owner is much more likely to work under all memory-management schemes yet devised, and makes for cleaner code as a side benefit.
(This also goes for NSOpenPanels and NSSavePanels in pre-Blocks code.)

Related

dealloc is being called and I am not sure why

I have a view with some buttons, text fields, and methods. When I load the view, switch to another view, and then switch back, my app crashes. I added in an NSLog in each method to see what the last method call before the crash was, and it was -(void)dealloc{
I am wondering why this method was called? Is it called every time you reload a view? I've double checked my code and I definitely do not call it anywhere.
EDIT : Found my problem, I was releasing an array that I was using to store views. Thanks to #Darren I traced my problem.
Dealloc is called when a class is no longer needed and removed from memory.
When you have no more pointers holding onto anything in the view, then it's dealocated.
How are you switching to/from the view?
if you set a (strong) pointer to the view then it won't be dealocated automatically.
-dealloc is called whenever an object's reference count drops to 0. To find your problem, figure out what object's -dealloc was called. What's the second method on the call stack? The third? Was -dealloc sent to a valid object pointer in the first place?
There are several ways to approach this sort of thing. A good first step is to turn on NSZombies (Google for it). That'll let you know if you're sending a message (like, say, dealloc) to an invalid object. Usually, that causes a crash, but with NSZombies you'll get a nice error message instead.

Debugging properties in Xcode

So I have a few properties that I'm using in some sample code I'm playing with. Notably the "tag" property of the UIView class. Now I set this property, and if I NSLog it, or setup control statements based on the value of tag, I can see that the value I set is there, and being acted upon as expected.
However, if I hover the mouse over the .tag to see which tag value is there, I get nothing at all from Xcode. No pop up showing the value. So then I go to the auto/local/all window and I try to "Add Expression..." (seems that's the only way to setup a traditional "watch" variable, if there is another way, please let me know). Anyhow so I put my object.tag into the "watch" window and it's blank. No value. It isn't zero it's just nothing, as if it didn't exist.
Of course if I hover the mouse over the "object" part of "object.tag" then I get a pop up for the object with the disclosure triangle, which I expand, then I go looking for "_tag" (which appears to be the underlying instance variable).
So what is so difficult about this? Why isn't the tag property viewable during debug by simply hovering over it? Is this something to do with properties in Xcode dev?
I'm running Xcode 4.3.2
The tag property, as any other Objective-C property, is a syntactic sugar. In fact, properties are implemented as accessor methods, which, in turn, are translated to objc_msgSend() function calls. This machinery is nothing like accessing a struct field.
The debugger can show any field in a struct basically because it doesn't require any special knowledge and doesn't have any consequences. Only the struct definition is needed. Getting the value of an Objective-C property, on the other hand, requires executing code in the process context. You can do that manually in the debugger console, but the debugger just won't do this automatically.
I think this is still theoretically possible in isolated cases, but incredibly hard. Consider a case where executing an accessor method changes the object's internal state. For example, calling -[UIViewController view] (accessing its view property) results in loading the view. There may also be delegate methods called, etc. In such cases hovering the mouse over the property in IDE would alter the execution state of the process and thus make debugging itself a joke.

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.