Skip to main content

iOS ARC - weak and strong properties



I'm trying to understand the way ARC works, and as far as I know, I should be doing something wrong here. This is the code I'm using:





Interface:







@interface ViewController : UIViewController{



}



@property (strong, nonatomic) NSString * myString ;

@property (weak, nonatomic) NSString * myPointer ;







Implementation:







- (void)viewDidLoad{



[super viewDidLoad];

self.myString = @"Hello world!" ; // myString is strong

self.myPointer = self.myString ; // myPointer var is weak



[self performSelector:@selector(makeNilMyValue) withObject:nil afterDelay:1];

[self performSelector:@selector(printValues) withObject:nil afterDelay:2];

}



- (void) makeNilMyValue{

self.myString = nil ;

}



- (void) printValues{

NSLog(@"myString: %@", self.myString) ;

NSLog(@"myPointer: %@", self.myPointer) ;

}







After executing this, I get:







2012-02-26 11:40:41.652 test1[933:207] myString: (null)



2012-02-26 11:40:41.653 test1[933:207] myPointer: Hello world!







If I'm not wrong, due to myPointer is weak, it shouldn't retain the content of the object. So, it should show nil instead of "Hello World!".





What am I doing wrong?





Following Caleb's answer, I have created another weak pointer, see code below:







- (void)viewDidLoad{

[super viewDidLoad];

self.myString = @"Hello world!" ; // myString is strong

self.myPointer = self.myString ; // myPointer var is weak

self.myPointer2 = self.myString ; // myPointer2 var is weak



[self performSelector:@selector(makeNilMyValue) withObject:nil afterDelay:1];

[self performSelector:@selector(printValues) withObject:nil afterDelay:2];

}



- (void) makeNilMyValue{

self.myPointer2 = @"value changed!" ;

self.myString = nil ;



}



- (void) printValues{

NSLog(@"myString: %@", self.myString) ;

NSLog(@"myPointer: %@", self.myPointer) ;

}







The point is that I still got the same answer I used to have:







2012-02-26 12:08:13.426 test1[1333:207] myString: (null)

2012-02-26 12:08:13.427 test1[1333:207] myPointer: Hello world!




Comments

  1. As Caleb pointed out, using a constant NSString for this example is not a good idea.


    The simplest way to create a string object in source code is to use the Objective-C @"..." construct:

    NSString *temp = @"/tmp/scratch"; Note that, when creating a string
    constant in this fashion, you should avoid using anything but 7-bit
    ASCII characters. Such an object is created at compile time and exists
    throughout your program’s execution. The compiler makes such object
    constants unique on a per-module basis, and they’re never deallocated,
    though you can retain and release them as you do any other object. You
    can also send messages directly to a string constant as you do any
    other string:

    BOOL same = [@"comparison" isEqualToString:myString];


    The documentation explains that constant strings will never disappear.

    Try using something else for your experiment. I tried NSObject and it produced expected results.

    Interface:

    @interface ViewController : UIViewController

    @property (strong, nonatomic) NSObject * myString;
    @property (weak, nonatomic) NSObject * myPointer;

    @end


    Implementation:

    @implementation ViewController

    @synthesize myString = _myString;
    @synthesize myPointer = _myPointer;

    - (void)viewDidLoad{

    [super viewDidLoad];

    self.myString = [[NSObject alloc] init];
    self.myPointer = self.myString;
    self.myString = nil;
    NSLog(@"myString: %@", self.myString);
    NSLog(@"myPointer: %@", self.myPointer);
    }

    - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
    {
    return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
    }

    @end


    Weak pointers are set to nil when there are no strong pointers to the memory as explained in the documentation - Apple Developer or llvm.


    __weak specifies a reference that does not keep the referenced object alive. A weak reference is set to nil when there are no strong
    references to the object.

    ReplyDelete
  2. So, it should show nil instead of "Hello World!".


    First, constant strings are never deallocated, so your `@"Hello World!" never goes away.

    Second, even if the string were released and deallocated, that wouldn't change the value of self.myPointer. That property would still hold the same memory address, and so would appear to point to the same data unless that memory were modified. So your pointer could very easily point to something that used to be a valid object and just happens to still work. Relying on such a pointer is bad news, though -- it's a frequent source of intermittent crashes.

    ReplyDelete

Post a Comment

Popular posts from this blog

Why is this Javascript much *slower* than its jQuery equivalent?

I have a HTML list of about 500 items and a "filter" box above it. I started by using jQuery to filter the list when I typed a letter (timing code added later): $('#filter').keyup( function() { var jqStart = (new Date).getTime(); var search = $(this).val().toLowerCase(); var $list = $('ul.ablist > li'); $list.each( function() { if ( $(this).text().toLowerCase().indexOf(search) === -1 ) $(this).hide(); else $(this).show(); } ); console.log('Time: ' + ((new Date).getTime() - jqStart)); } ); However, there was a couple of seconds delay after typing each letter (particularly the first letter). So I thought it may be slightly quicker if I used plain Javascript (I read recently that jQuery's each function is particularly slow). Here's my JS equivalent: document.getElementById('filter').addEventListener( 'keyup', function () { var jsStart = (new Date).getTime()...

Is it possible to have IF statement in an Echo statement in PHP

Thanks in advance. I did look at the other questions/answers that were similar and didn't find exactly what I was looking for. I'm trying to do this, am I on the right path? echo " <div id='tabs-".$match."'> <textarea id='".$match."' name='".$match."'>". if ($COLUMN_NAME === $match) { echo $FIELD_WITH_COLUMN_NAME; } else { } ."</textarea> <script type='text/javascript'> CKEDITOR.replace( '".$match."' ); </script> </div>"; I am getting the following error message in the browser: Parse error: syntax error, unexpected T_IF Please let me know if this is the right way to go about nesting an IF statement inside an echo. Thank you.