Objective - C中提供了线程同步和异常处理
Objective - C中提供了线程同步和异常处理
Objective - C中提供了线程同步和异常处理。要打开这些功能的支持,使用- fobjc -exceptions的GNU编译器集(GCC)3.3版本或者更高版本。
注:要么使用这些功能在一个程序,使得应用程序可运行在Mac OS X中只有10.3和更高版本因为异常处理和同步运行时不支持该软件的早期版本中存在。
Objective-c支持多线程的应用程序。 这意味着,两个线程可以尝试修改在同一时间相同的对象,这种情况可能导致在程序中的严重问题。 为了保护代码部分在一个时间被执行在多个线程,Objective - C提供了@synchronized()同步指令。
在@ synchronized()指令锁定的的代码段由单个线程使用。其他线程被阻塞,直到该线程退出保护的代码; 也就是说,只有在过去的最后声明后才继续执行@ synchronized()块再见哦那个的代码。
@ synchronized()指令作为任何 Objective - C对象和它自己唯一的参数。这个对象被称 为一个相互排斥或互斥信号量。它允许一个线程锁定代码段以防止其他线程使用。您应该使用单独的信号量来保护一个程序的不同关键部分。在创造一切相互排斥成为多线程应用程序之前,这样做是最安全的,以避免竞争条件。
清单1 显示了一个代码示例采用自同步的互斥访问当前对象的实例方法。你可以采取类似的方法来同步相关类的类的方法,使用类对象而不是自我。在后一种情况下,当然,只有一个线程在一个时间允许执行一个类方法,因为对所有呼叫者只有一个类的对象共享。
Listing1 Locking a method using self
- (void)criticalMethod
{
@synchronized(self)
{
// Critical code.
...
}
}
清单2使 用当前选择,_cmd作为互斥。这种同步是有益的只有当正在同步的方法有一个唯一的名称。这是因为没有其他对象或类将被允许执行一个具有相同名称不同的方法,直到当前方法的结束。
Listing 2 Locking a method using _cmd
- (void)criticalMethod
{
@synchronized(NSStringFromSelector(_cmd))
{
// Critical code.
...
}
}
清单3显示了一个普遍的做法。在关键代码执行前,得从Account类获取一个信号量,并用它来锁的关键部分。该Account类可以在 initialize 方法中创建信号量。
Listing 3 Locking a method using a custom semaphore
Account *account = [Account accountFromString:[accountField stringValue]];
// Get the semaphore.
id accountSemaphore = [Account semaphore];
@synchronized(accountSemaphore)
{
// Critical code.
...
}
在Objective - C的同步功能支持递归和重载代码。在一个递归中,一个线程可以使用一个信号量几次。其他线程被阻止使用它,直到线程释 放所 有 与它获得锁,也就是说,每一个@synchronized()块正常退出或抛出一个异常。
当同步代码快@synchronized()抛出一个异常,在Objective - C的运行时捕获该异常,释放信号量(这样,受保护的 代码可以被其他线程执行), 并重新抛异常到下一个异常处理程序。
在Objective - C的语言有一个异常处理的语法类似Java和C + +的。再加上使用的NSException, NSError,或自定义类,您可以添加健壮的错误处理你们的程序。
唯一的区别是围绕四个支持编译器指令:@try,@catch,@throw,和@finally。代码有可能抛出有可能抛出的异常是封闭在一个@ try块。 @catch()块包含为@ try 块抛出的异常的异常处理逻辑。一个@ finally块包含代码必须执行是否引发异常与否。您可以使用@throw指令抛出一个异常,这基本上是一个对Objective - C对象的指针。你可以使用NSException对象但不限于他们。
下面的例子描述 了一个简单的异常处理算法:
Cup *cup = [[Cup alloc] init];
@try {
[cup fill];
}
@catch (NSException *exception) {
NSLog(@"main: Caught %@: %@", [exception name], [exception reason]);
}
@finally {
[cup release];
}
要抛出一个异常实例,您必须使用相应的信息,如异常的名称和它被抛出的理由。
NSException *exception =
[NSException exceptionWithName:@"HotTeaException"
reason:@"The tea is too hot"
userInfo:nil];
@throw exception;
@catch() 块内,你可以重新抛出捕获的异常使用@throw指令不需要任何参数。这可以帮助你的代码更具可读性。
你也可以继承NSException 实现专门类型的异常,如文件系统异常或通信异常。
注意:您不局限于扔NSException对象。你可以抛出一个异常对象为任何 Objective - C对象。该NSException类提供的方法,在异常协助处理。但你可以实现自己的异常,如果你愿意的话。
为了捕捉@ try块一个异常块,在@try块后使用抛出一个异常的一个或多个@catch()块。在@catch()代码块应该从most-specific命令到least-specific命令。这样,你可以定制exception异常,如清单9-1所示。
Listing 9-1 An exception handler
@try {
...
}
@catch (CustomException *ce) { // 1
...
}
@catch (NSException *ne) { // 2
// Perform processing necessary at this level.
...
// Rethrow the exception so that it's handled at a higher level.
@throw; // 3
}
@catch (id ue) {
...
}
@finally { //4
// Perform processing necessary whether an exception occurred or not.
...
}
下面的列表描述 了编号的代码行:
1. 捕捉最具体的异常类型
2. 捕捉更多的一般异常类型
3. 重新抛出异常捕获
要划分异常处理,您可以嵌套在程序中的异常处理程序。该这样,如果一个方
法或函数捕获一个异常,它不能处理,它可以重新投入到下一个异常处理程序。
4. 执行任何清洁处理,必须始终执行,无论是exception抛掷或没有。