Pergunta

Under C++, I have a Mutex class, and I use this RAII-style class to ensure the mutex is unlocked, regardless of the reason for the method return:

class MutexLock {
protected:
    Mutex &m_mutex;
public:
    MutexLock(Mutex &mutex) :
        m_mutex(mutex) {
        m_mutex.lock();
    }

    ~MutexLock() {
        m_mutex.unlock();
    }
};

Is there any reason, and when using ARC, that an equivalent Objective-C class wouldn't work just as well:

@interface Locker : NSObject {
    NSLock *_lock;
}
- (void)setLock:(NSLock *)lock;
@end

@implementation Locker

- (void)setLock:(NSLock *)lock {
    [_lock unlock];
    _lock = lock;
    [_lock lock];
}

- (void)dealloc {
    self.lock = nil;
}
@end

Which might be used in the following way:

NSLock *_lock;    // instance variable

- (void)myFunc {
    Locker *locker = [[Locker alloc] init];
    locker.lock = _lock;

    return;     // Whenever I like
}

I understand it won't work in the case of Objective-C exceptions, unlike the C++ version, but assuming all Objective-C exceptions are fatal, I'm not worried about that.

UPDATE Just knocked-up a quick test, and it appears to be working fine. See this gist.

Foi útil?

Solução 3

I would say that class methods like

+ (Locker *)lockerWithLock:(NSLock *)lock;

would probably cause ARC to autorelease the return value (see this article). I think it will be autoreleased unless the method name begins with alloc, new, init, copy, mutableCopy (or unless you use special macros to force the compiler into not autoreleasing, NS_RETURNS_RETAINED), the clang ARC documentation is pretty good. An autoreleased object would obviously be a problem given your lock wouldn't be unlocked until the autorelease pool is drained.

I always thought of RAII as being a C/C++ thing where you can allocate objects statically. But I guess you can do it this way, as long as you make well sure that the objects are not autoreleased.

Outras dicas

Better API: use a block:

void performBlockWithLock(NSLock *lock, void (^block)(void)) {
    [lock lock];
    block();
    [lock unlock];
}

Example:

NSLock *someLock = ...;
performBlockWithLock(someLock, ^{
    // your code here
});

If you want RAII patterns, you should use Objective-C++ and write C++ RAII classes.

ARC is unlikely to give you the result you want. The object may be deallocated too late, if something causes it to be autoreleased. The object may be deallocated too early, if the ARC optimizer decides the object is no longer used.

Don't do this! I recently hunted bugs for a day or so until i found out tima and order of objects released via arc is kinda random, some time after the last referece goes away. it seems auto release pools are popped kinda at random. also order is not preserved. i.e. a child object referenced only by one other object was deallocated after its parent object. I ended up doing manual resource deininit via self-made "destruct" messages, and will propably end up porting all but some glue code to c++. i am sorry for people having to use swift. basically its all the problems that you have with gc....

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top