gpt4 book ai didi

ios - 带 block 参数的 NSInvocation

转载 作者:可可西里 更新时间:2023-11-01 03:30:07 29 4
gpt4 key购买 nike

我试图将 block 参数传递给 NSInvocation,但应用程序崩溃了。调用发出网络请求并调用成功或失败 block 。我认为问题在于 block 在网络请求完成之前被释放。我设法让它与一些 Block_copy 黑客一起工作,并且它没有使用 Instruments 报告任何泄漏。

问题:- 即使静态分析器或仪器没有报告泄漏,是否有可能存在泄漏?- 有没有更好的方法来“保留” block ?

// Create the NSInvocation
NSMethodSignature *methodSignature = [target methodSignatureForSelector:selector];
NSInvocation* invoc = [NSInvocation invocationWithMethodSignature:methodSignature];
[invoc setTarget:target];
[invoc setSelector:selector];

// Create success and error blocks.
void (^successBlock)(id successResponse) = ^(id successResponse) {
// Some success code here ...
};

void (^errorBlock)(NSError *error) = ^(NSError *error) {
// Some failure code here ...
};

/*
Without the two Block_copy lines, the block gets dealloced too soon
and the app crashes with EXC_BAD_ACCESS
I tried [successBlock copy] and [failureBlock copy] instead,
but the app still crashes.
It seems like Block_copy is the only way to move the block to the heap in this case.
*/
Block_copy((__bridge void *)successBlock);
Block_copy((__bridge void *)errorBlock);
// Set the success and failure blocks.
[invoc setArgument:&successBlock atIndex:2];
[invoc setArgument:&errorBlock atIndex:3];

[invoc retainArguments]; // does not retain blocks

// Invoke the method.
[invoc invoke];

更新:我将代码更新到下面。这些 block 是 NSMallocBlocks,但应用程序仍然崩溃。

// Create success and error blocks.
int i = 0;
void (^successBlock)(id successResponse) = ^(id successResponse) {
NSLog(@"i = %i", i);
// Some success code here ...
};

void (^errorBlock)(NSError *error) = ^(NSError *error) {
NSLog(@"i = %i", i);
// Some failure code here ...
};

/*** Both blocks are NSMallocBlocks here ***/
// Set the success and failure blocks.
void (^successBlockCopy)(id successResponse) = [successBlock copy];
void (^errorBlockCopy)(NSError *error) = [errorBlock copy];

/*** Both blocks are still NSMallocBlocks here - I think copy is a NoOp ***/

// Set the success and failure blocks.
[invoc setArgument:&successBlockCopy atIndex:2];
[invoc setArgument:&errorBlockCopy atIndex:3];

[invoc retainArguments]; // does not retain blocks

// Invoke the method.
[invoc invoke];

block 在链中向下传递如下:

NSInvocationNSProxy(NSInvocation 使用 forwardInvocation:)→ method1方法N

methodN 根据 HTTP 响应最终调用成功或失败 block 。

我是否需要在每个阶段都复制区 block ?上面的例子是在谈论第一个 NSInvocation。我是否还需要 [invocation retainArguments]; 在每个适当的步骤?我正在使用 ARC。

最佳答案

Block_copy,确实是[block copy] return 副本。他们不会神奇地将原件与同一位置的副本切换。所以至少我认为你想要:

successBlock = Block_copy((__bridge void *)successBlock);
errorBlock = Block_copy((__bridge void *)errorBlock);

(或者,等效地,successBlock = [successBlock copy]; ...)

否则,您正在创建副本,对它们什么都不做,仍然将原件传递给调用。

编辑:所以,我将以下代码放入项目中:

@interface DummyClass: NSObject
@end

typedef void (^ successBlock)(id successResponse);
typedef void (^ failureBlock)(NSError *error);

@implementation DummyClass

- (id)init
{
self = [super init];

if(self)
{
SEL selector = @selector(someMethodWithSuccess:failure:);
id target = self;

// Create the NSInvocation
NSMethodSignature *methodSignature = [target methodSignatureForSelector:selector];
NSInvocation* invoc = [NSInvocation invocationWithMethodSignature:methodSignature];
[invoc setTarget:target];
[invoc setSelector:selector];

// Create success and error blocks.
void (^successBlock)(id successResponse) = ^(id successResponse) {
// Some success code here ...
NSLog(@"Off, off, off with %@", successResponse);
};

void (^errorBlock)(NSError *error) = ^(NSError *error) {
// Some failure code here ...
NSLog(@"Dance, dance, dance till %@", error);
};

successBlock = [successBlock copy];
errorBlock = [errorBlock copy];

// Set the success and failure blocks.
[invoc setArgument:&successBlock atIndex:2];
[invoc setArgument:&errorBlock atIndex:3];

[invoc retainArguments]; // does not retain blocks

// Invoke the method.
double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(),
^{
[invoc invoke];

});
}

return self;
}

- (void)someMethodWithSuccess:(successBlock)successBlock failure:(failureBlock)failureBlock
{
NSLog(@"Words:");
successBlock(@[@"your", @"head"]);
failureBlock([NSError errorWithDomain:@"you're dead" code:0 userInfo:nil]);
}

@end

并在 application:didFinishLaunchingWithOptions: 的末尾添加以下内容:

DummyClass *unusedInstance = [[DummyClass alloc] init];

结果是在启动我的程序两秒后控制台上出现以下内容:

2013-06-02 20:11:56.057 TestProject[3330:c07] Words:
2013-06-02 20:11:56.059 TestProject[3330:c07] Off, off, off with (
your,
head
)
2013-06-02 20:11:56.060 TestProject[3330:c07] Dance, dance, dance till Error Domain=you're dead Code=0 "The operation couldn’t be completed. (you're dead error 0.)"

关于ios - 带 block 参数的 NSInvocation,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16889292/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com