iOS 异常和线程

在异步线程中,可以使用try catch

在异步线程中使用try catch DEMO如下,如果异常是可以被catch住,thread不会异常的

enum OperateType: Error {
    case noParameter
    case emptyParameter
}
class func operate(parameter: String?) throws -> String {
    guard let para = parameter else {
        throw OperateType.noParameter
    }
    if para.characters.count > 0 {
    } else {
        throw OperateType.emptyParameter
    }
    return para.lowercased()
}

OperationQueue().addOperation {
    do {
        let _ = try operate(parameter: nil)
    } catch let error {
        print(error)
    }
}

在try catch中 使用异步线程是不安全的

而在try catch中调用异步线程, 异步线程中的异常被系统的libdispatch接管,无法catch住,会直接导致线程退出等问题。而事实上,在Swift中根本写不出这样的代码,原因是异步线程的block结构是 ()->(), 而能够抛出异常的代码结构是() throws -> (), 类似NSInvocationOperation的方法直接被废弃了。

enum OperateType: Error {
    case someError
}

OperationQueue().addOperation {
    throw OperateType.someError
}

在Objective-C中的, 一般的try catch 是这样的

@try {
    NSString *str = nil;
    NSArray<NSString *> *strs = @[str];
    NSLog(@"%lu",strs.count);
} @catch (NSException *exception) {
    NSLog(@"%@", exception.reason);
} @finally {
}

但是,如果对中间的操作放到异步线程,如下面代码,就会, 就会丢失try catch的保护,出现异常,导致线程退出

@try {
    [[[NSOperationQueue alloc] init] addOperationWithBlock:^{
        NSString *str = nil;
        NSArray<NSString *> *strs = @[str];
        NSLog(@"%lu",strs.count);
    }];
} @catch (NSException *exception) {
    NSLog(@"%@", exception.reason);
} @finally {
}

应当对thread里面的所有操作进行“保护”,放到try catch,可以发现 中间的代码块与前面的一样:所以请记住这样的结构

[[[NSOperationQueue alloc] init] addOperationWithBlock:^{
    @try {
        NSString *str = nil;
        NSArray<NSString *> *strs = @[str];
        NSLog(@"%lu",strs.count);
    } @catch (NSException *exception) {
        NSLog(@"%@", exception.reason);
    } @finally {
    }
}];

为次可以分装一下这样一个线程安全的函数

+ (void)tryExcuteWithQueue:(NSOperationQueue*)queue tryBlock:(void(^)())tryBlock catchBlock:(void(^)(NSException *))catchBlock finishedBlock:(void(^)())finishedBlock {
    [queue addOperationWithBlock:^{
        @try {
            if (tryBlock) {
                tryBlock();
            }
        } @catch (NSException *exception) {
            if (catchBlock) {
                catchBlock(exception);
            } else {
#if DEBUG
                NSLog(@"exception:%@\n model:%@", exception.reason, nil);
#endif
            }
        } @finally {
            if (finishedBlock) {
                finishedBlock();
            }
        }
    }];
};

try catch 不是万能的

严格来讲try catch只能捕获异常,不是保证main thread不crash的万能钥匙。try catch不能捕获线程不安全的问题

static id object;
for (int i = 0; i < 100; i++) {
    dispatch_async(global_queue) ^{
        object = [NSObject new];
    }
}

在Swift中 do try catch只有带try的是做异常捕获,其它的没有也不必须
编程过程中,尤其是动态语言,必须考虑周全,类型、越界、逻辑完整性等

results matching ""

    No results matching ""