1

I am seeing two very different behaviors for something that I thought were the exact same.

Defining my private member in the class extension like this:

@interface ClassA ()
@property ClassB* b;
@end

@implementation ClassA
-(ClassA*)initWithClassB:(ClassB*)newB
{
    self.b = newB;
    return self;
}

-(ClassB*)getB
{
    return self.b;
}

Or defining my private member in the class implementation like this:

@interface ClassA ()
@end

@implementation ClassA
ClassB* b;
-(ClassA*)initWithClassB:(ClassB*)newB
{
    b = newB;
    return self;
}

-(ClassB*)getB
{
    return b;
}

The way I am using this code is to create a ClassB object, initialize a ClassA object with that ClassB object, and then add the ClassA object to a mutable array

-(void)init
{
    self.classAList = [[NSMutableArray alloc] init];
    [self.classAList addObject:[[ClassA alloc] initWithClassB:[self createClassB1]]];
    [self.classAList addObject:[[ClassA alloc] initWithClassB:[self createClassB2]]];
    [self.classAList addObject:[[ClassA alloc] initWithClassB:[self createClassB3]]];
}
-(ClassB)createClassB1
{
    ClassB* classB = new ClassB();
    //do some init
    return classB;
}
// Same thing fore createClassB2 and createClassB3 except with different data

When I use the first approach, and define my member in the interface extension, I see that each element in my mutable array is indeed what I would expect.

However, using the second approach, I see that my ClassB* b pointer in the ClassA object always ends up pointing to the most recently created ClassB object. That is, once the -(void)init method finishes, the ClassB pointers in each of the ClassA objects points to the ClassB object I created in createClassB3

What is happening here?

I should also mention that the ClassB object is a C++ object and this is a an objective-c++ class.

Vince613
  • 329
  • 7
  • 18

2 Answers2

1

In your second snippet, b is just a global variable at file scope. The fact that it's inside of the @implementation ... @end is irrelevant. It is not an instance variable nor a property.

Ken Thomases
  • 88,520
  • 7
  • 116
  • 154
  • I noticed when I put `b` in `{ }` within the `@implementation...@end` I get the same behavior as the first approach, is this why? – Vince613 Jul 27 '14 at 19:10
  • Yes. Instance variables are always within braces in an `@interface` or `@implementation`. Note that instance variables and properties (which is what `b` is in your first snippet) are not the same thing. – Ken Thomases Jul 27 '14 at 19:15
1

With the second approach you're creating a global variable, meaning it's not related to any instance of ClassA, so you will always have one and the same instance of *b pointing to the same object in memory. So anytime you change the value of the *b you're changing the object in memory at which the b variable is pointing, but never creating a new one; to understand it better you're basically initialising every ClassA object with the same ClassB variable (which is *b), so if you change the value at the portion of memory to which *b is pointing you're changing it for all the instances of ClassA created.

Hope it's clear enough.

Danny S
  • 1,291
  • 8
  • 12