将“NSError *const __strong *”发送到“NSError *__autoreleasing *”类型的参数会更改指针的保留/释放属性

问题描述 投票:0回答:4

这个问题类似于 ios NSError types 但那里描述的解决方案不起作用,我相信它不完全是我需要的。

我有一个方法,它执行异步调用,然后调用完成块。当我尝试将 NSError ** 传递给完成块时,我收到此错误:

将“NSError *const __strong *”发送到“NSError 类型”的参数 *__autoreleasing *' 改变指针的保留/释放属性

代码如下:

+(void) agentWithGUID:(NSString *) guid completion:(void (^)(AKAgentProfile * agentProfile, NSError ** error)) completionBlock
{
    dispatch_queue_t requestQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(requestQueue, ^{
        NSString * parameterizedUrl = [AKAgentProfileEndPoint stringByAppendingString:guid];
        NSURL *url = [NSURL URLWithString:parameterizedUrl];
        NSData *data = [NSData dataWithContentsOfURL:url];

        NSError * error = nil;

        AKAgentProfile * agentProfile = [[[AKAgentFactory alloc] init] agentProfileWithData:data error:&error];

        dispatch_async(dispatch_get_main_queue(), ^{
            completionBlock(agentProfile,&error);
        });

    });
}
ios objective-c automatic-ref-counting
4个回答
6
投票

你的完成块参数完全是无稽之谈。

调用堆栈上有一个变量 NSError* err。

然后尝试将 err 的地址传递给将在主线程中调用的完成块。当完成块被调用时,你的函数早已返回,而 &err 就是垃圾。如果完成块试图在那里存储任何内容,它会存储一个 NSError* ,很久以前你的 err 变量就在堆栈上,很可能会覆盖完全不相关的方法的一些有价值的数据。

这不适用于回调块。


5
投票

按值传递错误,而不是按引用传递错误,即将块签名更改为

void (^)(AKAgentProfile * agentProfile, NSError * error)
并传递
error
而不是
&error


0
投票

我在不同的情况下遇到过这个。这是我的代码:

            NSError *_Nullable copyError = nil;
            ImpVirtualFileHandle *_Nullable writeFH = nil;

            [file getDataForkHFSPlusExtentRecord:extents];
            writeFH = [hfsPlusVol fileHandleForWritingToExtents:extents];
            bool const copiedDataFork = [file readDataFork:^bool(NSData *_Nonnull const data) {
                return [writeFH writeData:data error:&copyError] == data.length;
            } error:&copyError];

错误是:

Sending 'NSError * _Nullable const __strong *' to parameter of type 'NSError * _Nullable __autoreleasing *' changes retain/release properties of pointer

鉴于我们始终将指向强变量的指针传递给采用自动释放指针的参数,此错误消息并不能说明为什么这次突然无效。

无论如何,实际的问题是编译器完全忘记提及的:变量没有用

__block
声明,并且需要让块能够合法地分配给它。 (如果这是一个直接赋值,编译器会给出一个更直接的错误。)

添加一个简单的关键字:

            __block NSError *_Nullable copyError = nil;

现在该块被授权更改此变量的内容,因此引用传递现在是合法的并且错误消失了。


-1
投票

您在

中将错误定义为参数
+(void) agentWithGUID:(NSString *) guid completion:(void (^)(AKAgentProfile * agentProfile, NSError ** error)) completionBlock 

然后再次在块中,我建议您将块中的重命名为:

+(void) agentWithGUID:(NSString *) guid completion:(void (^)(AKAgentProfile * agentProfile, NSError ** error)) completionBlock
{
    dispatch_queue_t requestQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(requestQueue, ^{
        NSString * parameterizedUrl = [AKAgentProfileEndPoint stringByAppendingString:guid];
        NSURL *url = [NSURL URLWithString:parameterizedUrl];
        NSData *data = [NSData dataWithContentsOfURL:url];

        NSError * err = nil;

        AKAgentProfile * agentProfile = [[[AKAgentFactory alloc] init] agentProfileWithData:data error:&error];

        dispatch_async(dispatch_get_main_queue(), ^{
            completionBlock(agentProfile,&err);
        });

    });
}
© www.soinside.com 2019 - 2024. All rights reserved.