Friday, 6 November 2015

Safe implementations of custom accessor methods for non-atomic types

- (void)setSomeString:(NSString *)aString
{
    if (someString != aString)
    {
        [someString release];
        someString = [aString copy];
    }
}
This only fixes the memory issue, it doesn't fix the atomicity issue. To handle that, the only simple solution is to used a @synchronized section:
- (void)setSomeString:(NSString *)aString
{
    @synchronized(self)
    {
        if (someString != aString)
        {
            [someString release];
            someString = [aString copy];
        }
    }
}
This approach will also work for retain properties as well (simply replace the copy method with a retain.
To maintain atomicity, you also need a retain/autorelease pattern and lock on any getter methods too:
- (NSString *)someString
{
    @synchronized(self)
    {
        id result = [someString retain];
    }
    return [result autorelease];
}
The @synchronized section is only required around the retain since that will prevent a setter releasing the value before we can return it (the autorelease is then safely done outside the section).
For struct and other compound data types, we don't need to retain or copy, so only the @synchronized section is required:
- (NSRect)someRect
{
    @synchronized(self)
    {
        return someRect;
    }
}
- (void)setSomeRect:(NSRect)aRect
{
    @synchronized(self)
    {
        someRect = aRect;
    }
}

No comments:

Post a Comment