In the following example how many messages are sent to myObject?
- (void) myMethod:(id) myObject
NSLog(#"%#", myObject.myStringProperty);
NSLog(#"%#", myObject.myStringProperty);
NSLog(#"%#", myObject.myStringProperty);
}
I'm just curious about Objective-c potentially caching the value returned by myStringProperty on the stack. The value returned by myStringProperty could change between successive messages so perhaps caching doesn't make sense.
Three
I'm just curious about Objective-c potentially caching the value returned by myStringProperty on the stack. The value returned by myStringProperty could change between successive messages so perhaps caching doesn't make sense.
Nope, it's not cached. Every objc message is sent, provided of course myObject is not nil.
The compiler has no idea about any side effects within the method's execution (1) or influence of the global state (2).
e.g. does myObject or anything it references ever change during the execution of getting myStringProperty?
e.g. is the result affected by the current time?
You can set a breakpoint on -[myObject myStringProperty] and see for yourself. If myStringProperty is a getter method that you implement yourself, just click in the left gutter next to the method implementation to set the breakpoint.
If this is a synthesized accessor method, enter it as a symbolic breakpoint in Xcode's breakpoints navigator. Click on the right arrow icon in the navigator section to select the breakpoint navigator, press + at the bottom of the window, and choose "Add Symbolic Breakpoint…". Type -[TheClassName myStringProperty] in the symbol field, then click Done.
Related
With ARC turned off:
I create an instance of my custom class using alloc, so it has retain count of 1.
On the next line, I NSLog() the instance (I implemented a description method in my custom class).
On the next line, I release the object.
On the next line, I NSLog() the instance again, i.e. I send it a description message, and I see the same output in the console. I expected some kind of error output.
Here is the relevant code:
AppDelegate.m:
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
Greeter* host = [[Greeter alloc] initWithName:#"Maggie"]; //My custom class
NSLog(#"Greeter %#", host);
[host release];
NSLog(#"Greeter %#", host); //Create error: send a `description` message to an object whose retain count is 0.
return YES;
}
...
...
Greeter.m:
...
- (NSString*)description {
return [
[[NSString alloc] initWithFormat:#"\n\tname: %# \n\tCreated on %#", [self name], [self today]]
autorelease
];
}
--output in Console:--
2015-04-26 21:18:58.914 Flashlight[2380:62826] Greeter
name: Maggie
Created on 2015-04-27 03:18:58 +0000
2015-04-26 21:18:58.915 Flashlight[2380:62826] Greeter
name: Maggie
Created on 2015-04-27 03:18:58 +0000
Similar code in cocoa, causes weird stuff to happen, and Xcode flags the second NSLog() with EXC_BAD_ACCESS.
Response to comments:
I decided to start a new app to try some things, and here is what I discovered:
In Xcode 6.2, even though there is no error in the console, i.e. both NSLog()'s print the same thing, Product>Analyze will point out the line with the error saying: Reference-counted object is used after it is released. And if I click on that message, Xcode shows a nice graphical explanation of how that happened in the code.
If I edit the scheme to enable Zombie objects, then instead of the second NSLog() message, I get an error message:
Flashlight3[606:11093] *** -[Greeter respondsToSelector:]: message
sent to deallocated instance 0x7fb5e1caa8c0
After poking around in Xcode for much too long, I figured out how to edit the scheme. To the right of the Run and Stop buttons, there is a jump bar showing: ProjectName>Platform, which in my case is Flashlight>iPhone6. I clicked on Flashlight, and a drop down list displayed Edit scheme. I clicked on Edit scheme, then under Run/Debug, there is a checkbox for Enable Zombie Objects, which I checked.
Did you compile with debug symbols?
I guess not. I read some Apple docs to figure out how to do that: I clicked on the top line in the Project Navigator, chose Build Settings, then I scrolled down to Build Options, then I selected Build Variants, then I clicked the arrow to reveal Debug and Release. To the right of Debug, I clicked on normal, and I typed in debug.
I'm not sure what that does. I see no difference after doing that.
Do you find your code in the stack trace?
In the Stack Trace area:
Product>Profile
Scroll down the window and choose Zombies.
Then click the red Record button.
A Zombie Messaged popup will appear.
Inside the popup, click the arrow with the gray circle around it.
In the bottom pane, click on the Zombie line.
In the bottom right pane, at the top of pane, select the icon on the far right.
...there are a bunch of names in a list preceded by an icon:
Some of the icons are black. If I click on enough of the black icons, I eventually jump to my code. Doing that is problematic, though, because when I click on one of the black icons, it is hard to get back to the Stack Trace list to try another black icon. Edit: Okay, I found a way to get around that problem: when I click on one of the icons in the Stack Trace pane, it takes me to some code where one of the lines will have a red arrow pointing at it. If I click on the red arrow, it will show me a popup containing the Stack Trace list, and then I can click on one of the other black icons.
Just because an object's retain count goes to 0 and its dealloc method is called, doesn't mean the memory used by the object is instantly turned to garbage. The deallocated object could possibly sit in memory, intact, for a while before the memory space is reused for something else.
That seems to be the case here. The call to log host after it's been deallocated finds that the memory for the deallocated object is still intact so accessing its data works.
But it seems in your test on a Mac results in the memory being handled differently causing the exception.
rmaddy's answer is completely correct. But likely you want to know, how to get an error message in such a case.
There are two options:
Run the static analyzer. It can detect some of these errors.
Enable the zombie option in the scheme. This will keep the instance objects alive and report an error message, if they are used.
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.
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.
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.)
I understand that when you reach a breakpoint while debugging in Xcode you can hover the mouse pointer over objects and see their properties. But with most objects you only get a few of the properties. The rest are hidden. Trying this with a CLLocation object is next to useless.
Is there another way to peer inside this object while debugging?
Do I just have to resort to using NSLog to get what I want?
use the command: po VARNAME This will print out the value for you
As box pointed out, the gdb po command will print out whatever a varname points to. Xcode's debugger panel (the bottom pane in Xcode4) will also list out all objects in the current scope and allow you to view their ivars by clicking the disclosure buttons next to the objects. For Apple classes, though, this doesn't work so great, so I'd rely more on po, NSLog, and Apple's docs.
Create a -(NSString *)description method for whatever object you're trying to view.
At a breakpoint, right click on the variable in the local/global variable list (next to Console output) and click Print Description of "...". This will print out whatever details you want.