0
votes

if for example we have 2 object with an NSString property, one is weak and one is strong like this

@interface Class1 : NSObject
@property (weak) NSString *weakString;
@end


@interface Class2 : NSObject
@property (strong) NSString *strongString;
@end

then doing this:

NSString *string = [[NSString alloc] initWithString:@"bla"];

Class2 *c2 = [[Class2 alloc] init];
c2.strongString = string;

string = nil;

Class1 *c1 = [[Class1 alloc] init];
c1.weakString = c2.strongString;

c2.strongString = nil;

or even

c2 = nil;

and then what c1.weakString contains ?

assigning string to strongString call a retain on string, assigning string to nil send the first release to the string, assigning strongString to weakString doesn't change the retain count, then assigning nil to strongString send the second release to string or even assigning nil to c2, so releasing c2 should send the second release to string and so now the retainCount of weakString (and so string) should be zero and then released so weakString zeroed having nil if we try to access it

but 'weakString' still containing "bla" so the original string object, WHY?

3
as long as you have at least one strong reference, an object should not be deallocated/set to nil. - user529758
I know but after assigning nil to the strongString and string, the strong referense shouldn't exist anymore, or am I wrong? - Manu
Oh, if that's your concern: deallocation does not happen immediately. It may be delayed slightly. - user529758
the deallocation happen at the next run loop cycle, but the thing is that is not happening at all, but if you skip the strong assignement the deallocation happen immediatelly - Manu
@Rob I did it and the behaviour doesn't change - Manu

3 Answers

2
votes

NSString is a class cluster and does some unintuitive optimizations in the background. If you repeat your test with some custom NSObject subclass rather than NSString, it will behave more like you're expecting.

Imagine the following variation on your example:

@interface MyTestObject : NSObject
@end

@interface Class1 : NSObject
@property (weak) NSString *weakString;
@property (weak) MyTestObject *weakObject;
@end

@interface Class2 : NSObject
@property (strong) NSString *strongString;
@property (strong) MyTestObject *strongObject;
@end

And then consider:

Class2 *c2 = [[Class2 alloc] init];
Class1 *c1 = [[Class1 alloc] init];

@autoreleasepool {
    NSString *string = [[NSString alloc] initWithString:@"bla"];
    MyTestObject *object = [[MyTestObject alloc] init];

    c2.strongString = string;
    c2.strongObject = object;

    string = nil;
    object = nil;

    c1.weakString = c2.strongString;
    c1.weakObject = c2.strongObject;

    c2.strongString = nil;
    c2.strongObject = nil;
}

NSLog(@"c1.weakString = %@", c1.weakString);
NSLog(@"c1.weakObject = %@", c1.weakObject);

You'd expect both weakString and weakObject to be nil, but only weakObject is. This is a result of some internal implementation optimizations going on in the NSString class.

0
votes

Deallocation doesn't happen immediately.

Put your implementation in @autoreleasepool and then print weakString, it would be nil.

(Use initWithFormat for string initialization instead of redundant initWithString)

Class2 *c2 = nil;
Class1 *c1 = nil;

@autoreleasepool {
    NSString *string = [[NSString alloc] initWithFormat:@"bla"];

    c2 = [[Class2 alloc] init];
    c2.strongString = string;

    string = nil;

    c1 = [[Class1 alloc] init];
    c1.weakString = c2.strongString;

    c2.strongString = nil;
}

NSLog(@"str = %@", c1.weakString);

OUTPUT : str = (null)

Now, if you change weakString property to 'strong' instead of 'weak'

@property (strong) NSString *weakString;

OUTPUT : str = bla

0
votes
  1. the retain count you calculated is right.

  2. ARC is just adding retain/release code at compile time for you ,so the basic rule is same as manual management memory. when retain count is zero, it will be dealloced at once.

  3. the example above is an special case: NSString is under special memory managed for performance . the string content is immutable. Same string content will point to the same memory address to not duplicate multi-times. the NSString retain count is too big to release.