如果一个方法在同一时间被调用两次,如何只执行一次?

ero*_*ppa 5 iphone cocoa-touch objective-c uikit

我们在iPhone SDK中有一个委托方法.问题是,操作系统在同一时间调用此方法两次.这个方法做了一些繁重的工作,所以我不想执行两次逻辑.有什么好方法可以检测到这种情况并阻止其中一个运行?


忘了提一下,它是从不同的线程调用的.

nal*_*all 10

一种方法是您在输入方法时设置的BOOL成员,并在离开时清除.如果在输入时设置了变量,您知道它已经在执行并且可以返回.

假设您是从多个线程调用的,那么您将需要锁定对此关键检查/设置区域的访问.NSLock对此有好处.

下面的代码有两个实现:myMethod1使用NSLock,myMethod2使用@synchronize显示.

@interface MyClass : NSObject
{
    NSLock* theLock;
    BOOL isRunning;
}
@end

@implementation MyClass

-(id)init
{
    self = [super init];
    if(self != nil)
    {
        theLock = [[NSLock alloc] init];
        isRunning = NO;
    }
    return self;
}

-(void)dealloc
{
    [theLock release];
    [super dealloc];
}

// Use NSLock to guard the critical areas
-(void)myMethod1
{
    [theLock lock];

    if(isRunning == YES)
    {
        [theLock unlock]; // Unlock before returning
        return;
    }

    isRunning = YES;        

    // Do fun stuff here

    isRunning = NO;

    [theLock unlock];    
}

// This method uses @synchronize
-(void)myMethod2
{
    @synchronized(self)
    {
        if(isRunning == YES)
        {
            return;
        }

        isRunning = YES;

        // Do stuff here.

        isRunning = NO;
    }
}
@end
Run Code Online (Sandbox Code Playgroud)


bbu*_*bum 5

哇.答案是正确的,但过度设计.只是用@synchronized().

foo.h中:

@interface Foo
{
    id expensiveResult;
}
- (void) bar;
@end
Run Code Online (Sandbox Code Playgroud)

Foo.m:

@implementation Foo
- (void) bar
{
    @synchronized(self) {
        if (expensiveResult) return expensiveResult;
        .... do expensive stuff here ....
        expensiveResult = [theResult retain];
    }
    return expensiveResult;
}
@end
Run Code Online (Sandbox Code Playgroud)

如果你有多个Foo实例并希望保证所有实例的排他性,那么创建一个全局变量+(void)initialize- 一个NSString就可以了 - 并且就此@synchronized()而言.

但是,您的问题提出了一个更重要的问题.特别是,除非您非常明确地将应用程序配置为导致确实发生这种情况,否则永远不会同时调用同一方法两次.

答案提供的声音更像是对症状的修复,而不是对真正问题的修复.

注意:这依赖于expensiveResultnil,因为所有iVars在实例化时都是零.显然,如果要重新计算,请将ivar重置为nil.