views:

253

answers:

6

As I try to write

NSLog(@"%d", myObject.myId);

where myId is int, console gives some hight number like 70614496. And when I use @"%@", I get exception -[CFNumber respondsToSelector:]: message sent to deallocated instance 0x466c910. Why is it so?

Here's definition of myObject:

@interface myObject : NSObject {
int myId;
NSString *title;
}

@property(nonatomic) int myId;
@property(nonatomic, retain) NSString *title;

@end

@implementation myObject

@synthesize myId, title;

- (void)dealloc {
[title release];

[super dealloc];
}

@end
+4  A: 

Here's an example showing that it should work the way you first tried it, if your class/object/instance variable are all set up correctly:

#import <Foundation/Foundation.h>

@interface MyClass : NSObject
{
  int myId;
}

@property int myId;
@end

@implementation MyClass
@synthesize myId;
@end

int main (int argc, const char * argv[]) {
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  MyClass *myObject = [[MyClass alloc] init];

  myObject.myId = 5;
  NSLog(@"%d", myObject.myId);

  [myObject release];
  [pool drain];
  return 0;
}

Your code shows you doing the equivalent of this line:

NSLog(@"%d", MyClass.myId);

Which doesn't even compile, giving the error:

foundation.m:21: error: accessing unknown 'myId' class method
Carl Norum
Konstantin
Probably you're overwriting that variable somewhere without noticing it. Errant `memcpy()` or something, perhaps.
Carl Norum
You might set a watch on that memory area in gdb. This would cause the program to stop every time that memory is written. http://www.delorie.com/gnu/docs/gdb/gdb_30.html
nall
+4  A: 

Carl's doing a good job of trying to get your code to compile. Just another word on the %@ format specifier, since your question seems to imply some confusion.

When you use %@ in an NSLog format, you're actually sending the argument a description message, and printing the resulting string. If myId is an int and not an instance of NSObject, it doesn't respond to the description message. Use %d for int values and %@ for NSNumber instances.

nall
A: 

Check out the String Format Specifiers to see how to format NSLog statements. It's easy to get lazy with NSLog because objects have a built-in -description method that returns a formatted string. For scaler values, you have to use the proper formatter.

Because precision changes as you move from hardware to hardware, it's better to get in the habit of using object conversions to log values. In this case:

NSLog(@"%@", [[NSNumber numberFromInt:myObject.myId] stringValue]);

This will print correctly always.


Edit#1: I apologize. I was sleep deprived when I wrote the above. What I actually intended was to warn against using a simple int versus NSInteger as well as printing with NSNumber numberWithInteger:.

Consider the following run on 64-bit hardware.

int x=pow(2,63);
NSLog(@"x=%d",x); //prints x=2147483647

NSInteger n=pow(2,63);
NSLog(@"n=%d",n); // prints n=-1
NSLog(@"n=%@",[[NSNumber numberWithInteger:n] stringValue]); // prints n=9223372036854775807

In the old days of 8-bit systems, you ran into problems with problems with using 8-bit 'int' all the time. Running a for-loop with more than 256 iterations required a long. With a 32-bit int you won't see those kinds of issues and will never develop the habit of tracking the size of your intvariables.

This can lead to pernicious bugs that are nearly impossible to track down because they only occur with very specific and rare values in the data.

Writing for the iPhone (or other future mobiles/platforms) means writing on potentially highly variable hardware just like we had to do in the old days. It's best to acquire the habit early of using system and API specific definitions.


Edit#2:

where myId is int, console gives some hight number like 70614496.

(1) If it prints a different number each time you run, then you're probably assigning a pointer to the int when you set it. The NSLog is correctly printing the value of the pointer as an int.

(2) if it prints the same number each time, the you probably have an overflow issue like in my first edit above.

In either case, you need to look at code where you assign the value to the id property and not where you print it.

TechZen
But then, if `myObject.myId` is an `int`, then `%d` will work just fine, and if it's not an `int`, that code will not print the right result.
Peter Hosey
Depends on the int. See my edit above.
TechZen
+1  A: 

Given that second error message, I think the %d is working fine, but somewhere else you’re assigning a CFNumber or NSNumber to the myID property when you should be assigning an integer.

Ben Stiglitz
that would be a good idea, but no, there's only one place where I assign that value and it's int.I go nuts, with "po myObj" I get object, but with "po myObj.myId" I always get "*** -[CFNumber respondsToSelector:]: message sent to deallocated instance 0x46706e0".
Konstantin
One more discovery I made - as I "renamed" int into NSNumber*, all things started to work properly. What's wrong with value type here???
Konstantin
@Konstantin: Can you show the code where you set the property?
Chuck
Konstantin, if you’re doing that renaming and it works it means that you’re assigning an NSNumber and not an int. Again, like Chuck said, let us see the code and we can help explain why.
Ben Stiglitz
A: 

It looks like your instance of myObject was autoreleased at some time and is no longer actually valid. That is why you see the strange NSNumber issue when you try to dereference it as an object. When you just ask for an integer, you won't get any kind of error, it will just display the pointer's address coerced into an integer.

To see when your myObject gets dealloced, try adding something like this to the dealloc method in your class:

- (void)dealloc
{
    NSLog(@"dealloc called on %@", self);
    [title release];
    [super dealloc];
}

I bet you will find this logging a dealloc before you see the log for your myObject.myID.

Jason Coco
Jason, this would be a very good idea! But no, my obj doesn't get deallocated anywhere prior to this issue...
Konstantin
You're sure that it's not getting autoreleased or accidentally over released?
Jason Coco
Almost sure - anyway dealloc isn't called before that
Konstantin
The error logged when the OP changes the log format from %d to %@ indicates that the object being printed isn’t a proper NSObject. If anything is being released, it’s the ID and not the receiver.
Ben Stiglitz
@Ben, that's absolutely untrue. the ID is an int, and therefore doesn't get retained or released. It is very common to release an object and have another object created elsewhere (typically by the frameworks you use) replace it in memory. That object (the CFNumber) could easily be released as well and the memory just hasn't been changed by anything else yet.
Jason Coco
A: 

I would try simply changing this:

@property(nonatomic) int myId;

to this:

@property(nonatomic, assign) int myId;

And let me know your result, I suspect that obj-c is doing something funky when assigning an old int to the new int?

deoryp
assign is already the default choice (and the only valid one) for scalar types.
Ben Stiglitz