首页 Objective-C 从 C++ 到 Objective-C(17):异常处理和多线程

从 C++ 到 Objective-C(17):异常处理和多线程

4 1.8K

异常处理

比起 C++ 来,Objective-C 中的异常处理更像 Java,这主要是因为 Objective-C 有一个@finally关键字。Java 中也有一个类似的finally关键字,但 C++ 中则没有。finally 是 try()...catch() 块的一个可选附加块,其中的代码是必须执行的,不管有没有捕获到异常。这种设计可以很方便地写出简短干净的代码,比如资源释放等。除此之外,Objective-C 中的 @try...@catch...@finally 是很经典的设计,同大多数语言没有什么区别。但是,不同于 C++ 的还有一点,Objective-C 只有对象可以被抛除。

不带 finally:

BOOL problem = YES;
@try {
    dangerousAction();
    problem = NO;
} @catch (MyException* e) {
    doSomething();
    cleanup();
} @catch (NSException* e) {
    doSomethingElse();
    cleanup();
    // 重新抛出异常
    @throw
}
if (!problem)
    cleanup();

带有 finally:

@try {
    dangerousAction();
} @catch (MyException* e) {
    doSomething();
} @catch (NSException* e) {
    doSomethingElse();
    @throw // 重新抛出异常
} @finally {
    cleanup();
}

严格说来,@finally不是必要的,但是确实是处理异常强有力的工具。正如前面的例子所示,我们也可以在@catch中将异常重新抛出。事实上,@finally@try块运行结束之后才会执行。对此我们将在下面进行解释。

int f(void)
{
    printf("f: 1-you see me\n");
    // 注意看输出的字符串,体会异常处理流程
    @throw [NSException exceptionWithName:@"panic"
                                   reason:@"you don’t really want to known"
                                 userInfo:nil];
    printf("f: 2-you never see me\n");
}

int g(void)
{
    printf("g: 1-you see me\n");
    @try {
        f();
        printf("g: 2-you do not see me (in this example)\n");
    } @catch(NSException* e) {
        printf("g: 3-you see me\n");
        @throw;
        printf("g: 4-you never see me\n");
    } @finally {
        printf("g: 5-you see me\n");
    }
    printf("g: 6-you do not see me (in this example)\n");
}

最后一点,C++ 的 catch(...) 可以捕获任意值,但是 Objective-C 中是不可以的。事实上,只有对象可以被抛出,也就是说,我们可以始终使用id捕获异常。

另外注意,Cocoa 中有一个NSException类,推荐使用此类作为一切异常类的父类。因此,catch(NSException *e)相当于 C++ 的catch(...)

多线程

线程安全

在Objective-C 中可以很清晰地使用 POSIX APIs 2 实现多线程。Cocoa 提供了自己的类管理多线程。有一点是需要注意的:多个线程同时访问同一个内存区域时,可能会导致不可预料的结果。POSIX APIs 和 Cocoa 都提供了锁和互斥对象。Objective-C 提供了一个关键字@synchronized,与 Java 的同名关键字是一样的。

@synchronized

@synchronized(...)包围的块会自动加锁,保证一次只有一个线程使用。在处理并发时,这并不是最好的解决方案,但却是对大多数关键块的最简单、最轻量、最方便的解决方案。@synchonized要求使用一个对象作为参数(可以是任何对象,比如self),将这个对象作为锁使用。

@implementation MyClass

-(void) criticalMethod:(id) anObject {
    @synchronized(self) {
        // 这段代码对其他 @synchronized(self) 都是互斥的
        // self 是同一个对象
    }
    @synchronized(anObject) {
        // 这段代码对其他 @synchronized(anObject) 都是互斥的
        // anObject 是同一个对象
    }
}
@end

4 评论

luckygg 2011年6月1日 - 15:38

hi, 看了下原文"//(with the same "self"...)", 上面翻译的“即使是同一个"self"...”,应当译为"self为同一个对象"

回复
DevBean 2011年6月1日 - 19:33

多谢指出哦

回复
csland 2012年7月3日 - 11:26

我用gnustep执行的结果是:
g: 1-you see me
f: 1-you see me
g: 3-you see me
D:\GNUstep\msys\1.0\home\l00117629\test\obj\LogTest.exe: Uncaught exception NSInternalInconsiste
ncyException, reason: Bad sequence length in constant string
是不是
} @catch(NSException* e) {
分支中的@throw使得g()结束而不会进入其后的@finally呢?

回复
DevBean 2012年7月4日 - 23:03

应该不会有这个问题。先检查一下是不是有其它异常?因为你的错误信息是 Bad sequence length in constant string

回复

发表评论

关于我

devbean

devbean

豆子,生于山东,定居南京。毕业于山东大学软件工程专业。软件工程师,主要关注于 Qt、Angular 等界面技术。

主题 Salodad 由 PenciDesign 提供 | 静态文件存储由又拍云存储提供 | 苏ICP备13027999号-2