1

I have some @properties that are behaving strangely in the debugger when I @synthesize them and then subclass the controller.

The @properties behave as expected when I remove @synthesize.

Here is a basic example, a ViewController subclass called SubClassedViewController.

ViewController.h

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController {
    NSNumber *someNumber;
}

@property (nonatomic, strong) NSNumber *someNumber;

@end

ViewController.m

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

@synthesize someNumber;  //Strange behavior unless I remove this line

- (void)viewDidLoad
{
    [super viewDidLoad];
    someNumber = [NSNumber numberWithInt:123];
    // Do any additional setup after loading the view, typically from a nib.
}

@end

SubClassedViewController.h

#import "ViewController.h"

@interface SubClassedViewController : ViewController

@end

SubClassedViewController.m

#import "SubClassedViewController.h"

@interface SubClassedViewController ()

@end

@implementation SubClassedViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.
}

Behavior with @synthesize

Unless I use self., the object points to the subclassed controller, not to the NSNumber:

(lldb) po someNumber
$3 = 0x07151a30 <SubClassedViewController: 0x7151a30>
(lldb) po self.someNumber
$4 = 0x08c37f20 123
(lldb) p (int)[someNumber intValue]
error: Execution was interrupted, reason: Attempted to dereference an invalid ObjC Object or send it an unrecognized selector.
The process has been returned to the state before execution.
(lldb) po (UIView*)[someNumber view]
$7 = 0x071574f0 <UIView: 0x71574f0; frame = (0 20; 320 548); autoresize = RM+BM; layer = <CALayer: 0x71575a0>>

Note that if I put NSLogs in my code, someNumber correctly points to the NSNumber; it is only identified as a SubClassedViewController in lldb (as far as I can tell).

Behavior without @synthesize

If I comment out @synthesize and change the NSNumber creation in ViewController.m to:

_someNumber = [NSNumber numberWithInt:123];  //I added _ before variable name

Then I get the following different behavior (which is the behavior I'd expect)

(lldb) po _someNumber
$0 = 0x0717db70 123
(lldb) po self.someNumber
$1 = 0x0717db70 123
(lldb) po self
$2 = 0x071853a0 <SubClassedViewController: 0x71853a0>

Questions

  • Is this a bug, or do I misunderstand something?

If this is a bug (which is my assumption)...

  • Is it a bug in Xcode, the debugger, or the compiler?

If this is not a bug...

  • I'm using Xcode 4.6.1, which doesn't require that I @synthesize things. But shouldn't the behavior of my app be identical whether or not I do?

  • Why would it ever make sense for a property to point to its "owner"?

Aaron Brager
  • 65,323
  • 19
  • 161
  • 287
  • possible duplicate of [If a subclass refers to a superclass ivar, synthesizing an unrelated property fails](http://stackoverflow.com/questions/6822518/if-a-subclass-refers-to-a-superclass-ivar-synthesizing-an-unrelated-property-fa) **and** [Property vs. instance variable](http://stackoverflow.com/questions/719788/property-vs-instance-variable) **and** [(Not So) Silly Objective-C inheritance problem when using property - GCC Bug?](http://stackoverflow.com/questions/2778405/not-so-silly-objective-c-inheritance-problem-when-using-property-gcc-bug) –  Mar 18 '13 at 22:14

1 Answers1

8

This is not "strange behavior". You're getting garbage objects because your code is wrong.

When you remove @synthesize, the compiler automatically synthesizes the ivar with the name _someNumber. This causes your bad code in -viewDidLoad to actually do nothing. Notably, the line

someNumber = [NSNumber numberWithInt:123];

is storing an autoreleased object into an ivar, which means it's going to get released and the ivar will hold a garbage object. The correct fix here is probably to say

self.someNumber = [NSNumber numberWithInt:123];

which will invoke the setter and retain the value for you.

Furthermore, I recommend deleting your ivar declaration entirely and deleting the @synthesize as well, and just let the compiler synthesize your ivar.

Lily Ballard
  • 182,031
  • 33
  • 381
  • 347
  • That was my initial suspicion, but if that's true, why does `NSLog(@"My Number: %d", someNumber.integerValue);` placed at the end of SubClassedViewController's viewDidLoad return the correct number? – Aaron Brager Mar 18 '13 at 22:25
  • (That is, if the pointer is garbage, how am I still getting the correct value?) – Aaron Brager Mar 18 '13 at 22:26
  • 1
    @AaronBrager: Because it's not garbage until the autorelease pool is drained. When you're logging it, the autorelease pool hasn't drained yet. – Lily Ballard Mar 18 '13 at 22:27