120

I am overriding an object's description method. I need to know how to print the object's memory address to replace {???} in the code below:

-(NSString *) description {
    return [NSString stringWithFormat:@"<SomeClass: %@>\nparmeterOne: %@\nparameterTwo: %@",
            {???}, self.parameterOne, self.paramterTwo];
}

I want it to print in the console like this:

<SomeClass: 0x4c05600> parameterOne: 12 parameterTwo: sausages
Undo
  • 25,519
  • 37
  • 106
  • 129
Undistraction
  • 42,754
  • 56
  • 195
  • 331

2 Answers2

218

To print address use %p format specifier and self pointer:

-(NSString *) description {
    return [NSString stringWithFormat:@"<SomeClass: %p>\nparmeterOne: %@\nparameterTwo: %@",
            self, self.parameterOne, self.paramterTwo];
}
Vladimir
  • 170,431
  • 36
  • 387
  • 313
  • Nice. I thought that would cause recursion. Thanks a lot. – Undistraction Sep 26 '11 at 12:51
  • 6
    using self with '%@' specifier would indeed cause recursion as that will make -description method call again. %p specifier just outputs pointer address – Vladimir Sep 26 '11 at 12:53
  • 3
    I tend to `[NSString stringWithFormat:@"%@ parameterOne:...", [super description], ...];` — the address ends up in there because `NSObject` has it, but you also don't throw away anything you've decided is relevant to debugging in any superclasses you may be inheriting from. – Tommy Jun 02 '13 at 20:03
  • 8
    Additional note: `%p` expects a pointer of type `void *`, you have to cast `self` back to `void *`, else undefined behavior occurs. –  Jun 02 '13 at 20:23
  • 4
    @user529758: no need to cast, no undefined behaviour. `void *` and `id` are internally almost the same, and in this case there is no difference wether you cast it to `void *` or not. – Michael Apr 18 '14 at 10:15
  • 1
    You have to put '&' symbol before 'self' argument – Artem Deviatov Oct 13 '15 at 15:29
  • There is a difference between address of object when `self` and `&self`. You need to put &. – Nike Kov Apr 13 '17 at 13:04
  • 1
    @NikKov, why would you need that? self is already a pointer to the current object. – Vladimir Apr 13 '17 at 14:19
  • @Vladimir Ok, you're right. But in case of object variable, it's necessary. For example - in method `cellForRowAtIndexPath` for tableView if you will write `NSString *ident = @"identificator"; NSLog(@"%p", ident)`, than it would be the same address for every cell. Bit with NSLog(@"%p", &ident) it would be different address for every cell. – Nike Kov Apr 13 '17 at 19:59
  • 1
    @NikKov, not really. NSString *ident = @"identificator" is a special case - it is created as a __NSCFConstantString class so all equal string literals will share the same memory address to optimize memory usage. &ident will get an address of a local variable pointing to a NSString* and will have NSString** type – Vladimir Apr 14 '17 at 03:24
9

The easiest method is to use the super description

- (NSString *)description
{
    return [NSString stringWithFormat:@"%@ Area: %@, %@", [super description], self.identifier, self.name];
}

So in the case of this model object that is a subclass of NSObject, you can dodge extra work and remembering %p.

Manually using NSStringWithClass() and %p

- (NSString *)description
{
    return [NSString stringWithFormat:@"<%@: %p> Area: %@, %@", NSStringFromClass([self class]), self, self.identifier, self.name];
}

So in the case of an object model in which you have a concrete implementer that is derived from this class you will show the correct class name.

Cameron Lowell Palmer
  • 21,528
  • 7
  • 125
  • 126