Reputation: 409
I have a dilemma with strong and weak references in Xcode with Obj-C. When I create two objects with cross-references to each other inside, all weak:
Mouse *mouse = [[Mouse alloc] initWithComputer:nil];
Computer *computer = [[Computer alloc] initWithMouse:mouse];
NSLog(@"%@", computer.mouse); //prints legit address
mouse = nil; //destroy the ONLY strong reference to Mouse
NSLog(@"%@", computer.mouse); //still prints(holds) the same legit address
Before mouse = nil;
After mouse = nil;
After "destroying" the ONLY strong reference to Mouse class mouse, an instance of Mouse computer.mouse still holds the same memory address when it should be deallocated.
Absolutely the same code only in SWIFT in Xcode works correctly and deallocates the memory being held by computer.mouse making it nil
Is anything wrong with my Obj-c code? My Xcode is up to date, though with the previous version I had no luck either in Obj-c. I would appreciate any help.
Here are my classes:
Computer.h
#import <Foundation/Foundation.h>
@class Mouse;
@interface Computer : NSObject
@property (nonatomic, weak) Mouse *mouse;
- (instancetype) initWithMouse: (Mouse *) userPutMouse ;
@end
Computer.m
#import "Computer.h"
#import "Mouse.h"
@implementation Computer
- (instancetype) initWithMouse: (Mouse *) userPutMouse {
self = [super init];
if (self) {
self.mouse = userPutMouse;
self.mouse.computer = self;
}
return self;
}
@end
Mouse.h
#import <Foundation/Foundation.h>
@class Computer;
@interface Mouse : NSObject
@property (nonatomic, weak) Computer *computer;
- (instancetype) initWithComputer: (Computer *) userPutComputer;
@end
Mouse.m
#import "Mouse.h"
#import "Computer.h"
@implementation Mouse
- (instancetype) initWithComputer: (Computer *) userPutComputer {
self = [super init];
if (self ) {
if (userPutComputer) {
self.computer = userPutComputer;
}
}
return self;
}
@end
Upvotes: 1
Views: 51
Reputation: 100652
Your getters, being automatically synthesised, are placing the objects they return into the autorelease pool. Therefore your assignment of mouse
to nil
does not end the final owning reference. Never assume you are the only person with owning references to anything, only ensure that you follow appropriate behaviour.
For empirical demonstration, try this:
Mouse *mouse;
Computer *computer;
@autoreleasepool {
mouse = [[Mouse alloc] initWithComputer:nil];
computer = [[Computer alloc] initWithMouse:mouse];
NSLog(@"%@", computer.mouse); //prints legit address
mouse = nil; //destroy **my** ONLY strong reference to Mouse
}
NSLog(@"%@", computer.mouse); //prints (null)
... but also never try to diagnose whether proper ownership is happening empirically. That's why the retainCount
property is no longer available.
EDIT: to expand: the traditional behaviour expected of a getter is to return a non-owning reference that is nevertheless guaranteed to live for at least as long as the current call stack. This is so that, in pre-ARC days, you could use getters directly for supplying properties as arguments (in which case, don't burden the caller with memory management) or for getting something the caller can hold on to transiently, even if the original owner is deallocated in the meantime (i.e. the classic autorelease pool usage of making things act a bit like they're just on the stack). And then ARC just implements the old-fashioned rules but automatically, for full interoperability.
Upvotes: 4