void testBlockArray() {
int val = 10;
NSArray *arr = [NSArray arrayWithObjects:^(){NSLog(@"blk0:%d", val);},^(){NSLog(@"blk1:%d", val);}, nil];
NSLog(@"%@", arr);
}
// If we are type-erasing a block to a block-compatible
// Objective-C pointer type, we may need to extend the lifetime
// of the block object.
if (typeArgs && Args[i]->isRValue() && paramType->isBlockPointerType() &&
Args[i]->getType()->isBlockPointerType() &&
origParamType->isObjCObjectPointerType()) {
ExprResult arg = Args[i];
maybeExtendBlockObject(arg);
Args[i] = arg.get();
}
}
}
bool Sema::CheckMessageArgumentTypes(
const Expr *Receiver, QualType ReceiverType, MultiExprArg Args,
Selector Sel, ArrayRef<SourceLocation> SelectorLocs, ObjCMethodDecl *Method,
bool isClassMessage, bool isSuperMessage, SourceLocation lbrac,
SourceLocation rbrac, SourceRange RecRange, QualType &ReturnType,
ExprValueKind &VK)
/// Do an explicit extend of the given block pointer if we're in ARC.
void Sema::maybeExtendBlockObject(ExprResult &E) {
assert(E.get()->getType()->isBlockPointerType());
assert(E.get()->isRValue());
// Only do this in an r-value context.
if (!getLangOpts().ObjCAutoRefCount) return;
E = ImplicitCastExpr::Create(Context, E.get()->getType(),
CK_ARCExtendBlockObject, E.get(),
/*base path*/ nullptr, VK_RValue);
Cleanup.setExprNeedsCleanups(true);
}
在ARC环境下,下面的代码的执行结果是什么?
-(NSArray*) getBlockArray
{
int num = 916;
return [NSArray arrayWithObjects:
^{ NSLog(@"this is block 0:%i", num); },
^{ NSLog(@"this is block 1:%i", num); },
^{ NSLog(@"this is block 2:%i", num); },
nil];
}
- (void) forTest
{
int a = 10;
int b = 20;
}
- (void)test
{
NSArray* blockArr = [self getBlockArray];
[self forTest];
void (^blockObject)(void);
for(blockObject in blockArr){
blockObject();
}
答:
输出 this is block 0:916 后闪退
解析:
arrayWithObjects 方法只会copy第0个block,导致该block的类型修改为**NSMallocBlock**,后面的block被保持初始类型 NSStackBlock 并会在后续被系统回收内存。后面的for循环调用该指针时,会因为野指针而crash。