奇怪的“僵尸"在forwardInvocation中:+ getArgument:atIndex方法 [英] Strange "zombie" in forwardInvocation: + getArgument:atIndex methods

查看:113
本文介绍了奇怪的“僵尸"在forwardInvocation中:+ getArgument:atIndex方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我的代码的一部分:

Here is part from my code:

- (void)viewDidLoad
{
    [super viewDidLoad];

    CGRect frame = [[UIScreen mainScreen] bounds];
    _webView = [[UIWebView alloc] initWithFrame:frame];
    [_webView setHidden:NO];
    [self.view addSubview:_webView];

    _vk = [[DPVkontakteCommunicator alloc] initWithWebView:_webView];

    DPVkontakteUserAccount *user;
    NSString *accessToken = [[NSUserDefaults standardUserDefaults]
                                             objectForKey:@"accessToken"];
    NSInteger userId = [[[NSUserDefaults standardUserDefaults]
                                         objectForKey:@"userId"] integerValue];
    user = [[DPVkontakteUserAccount alloc]
                                    initUserAccountWithAccessToken:accessToken
                                                            userId:userId];

    NSLog(@"%@", user);

    [user setSuccessBlock:^(NSDictionary *dictionary)
    {
        NSLog(@"%@", dictionary);
    }];

    NSDictionary *options = @{@"uid":@"1"};
    //    [user usersGetWithCustomOptions:@{@"uid":@"1"}]; // Zombie
    [user usersGetWithCustomOptions:options]; // Not zombie

    //    __block NSDictionary *options = @{};
    //
    //    [_vk startOnCancelBlock:^{
    //        NSLog(@"Cancel");
    //    } onErrorBlock:^(NSError *error) {
    //        NSLog(@"Error: %@", error);
    //    } onSuccessBlock:^(DPVkontakteUserAccount *account) {
    //        NSLog(@"account:%@", account);
    //
    //        [account setSuccessBlock:^(NSDictionary *dictionary)
    //        {
    //            NSLog(@"%@", dictionary);
    //        }];
    //
    //        [account docsGetUploadServerWithCustomOptions:options];
    //    }];
}

这是处理userGetWithCustomOptions:方法的部分:

and here is the part which processes the userGetWithCustomOptions: method:

- (void)forwardInvocation:(NSInvocation *)anInvocation
{
    NSString *methodName = NSStringFromSelector([anInvocation selector]);
    NSDictionary *options;

    [anInvocation getArgument:&options
                      atIndex:2];

    NSArray *parts = [self parseMethodName:methodName];
    NSString *vkURLMethodSignature = [NSString stringWithFormat:@"%@%@.%@",
                                                                kVKONTAKTE_API_URL,
                                                                parts[0],
                                                                parts[1]];
    // appending params to URL
    NSMutableString *fullRequestURL = [vkURLMethodSignature mutableCopy];

    [fullRequestURL appendString:@"?"];

    [options enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop)
    {
        [fullRequestURL appendFormat:@"%@=%@&", key, [obj encodeURL]];
    }];

    [fullRequestURL appendFormat:@"access_token=%@", _accessToken];

    // performing HTTP GET request to vkURLMethodSignature URL
    NSURL *url = [NSURL URLWithString:fullRequestURL];
    NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
    AFJSONRequestOperation *operation;
    operation = [AFJSONRequestOperation
            JSONRequestOperationWithRequest:urlRequest
                                    success:^(NSURLRequest *request,
                                              NSHTTPURLResponse *response,
                                              id JSON)
                                    {
                                        _successBlock(JSON);
                                    }
                                    failure:^(NSURLRequest *request,
                                              NSHTTPURLResponse *response,
                                              NSError *error,
                                              id JSON)
                                    {
                                        _errorBlock(error);
                                    }];

    [operation start];
}

问题是当我使用"options"变量时,它工作正常,但是当使用直接值时,它失败,应用程序崩溃.通过使用Profile,我发现方法调用将直接指向已释放的对象.

problem is that when I am using "options" variable - it works fine, but when using direct values - it fails, app crashes. Using Profile I have found that method call directs to deallocated object.

为什么会这样? 没有其他代码可以帮助您.

Why this happens? There is no other code that can help.

ViewController.m代码: https://gist.github.com/AndrewShmig/5398546

ViewController.m code: https://gist.github.com/AndrewShmig/5398546

DPVkontakteUserAccount.m: https://gist.github.com/AndrewShmig/5398557

DPVkontakteUserAccount.m: https://gist.github.com/AndrewShmig/5398557

推荐答案

问题是getArgument:的参数类型为void *.并且您正在传递&value,它是NSDictionary * __strong *(指向强引用的指针).强制转换是有效的,因为可以在没有任何警告的情况下向void *和从void *分配任何非对象指针.

The problem is that the parameter of getArgument: is type void *. And you are passing &value, which is NSDictionary * __strong * (pointer to a strong reference) to it. The cast is valid because it is possible to assign any non-object pointer to and from void * without any warnings.

当您向函数传递指向强力的指针"时,这意味着函数应期望指向强引用"的指针,并且当函数退出时,应保留指针指向强指针"的事实.参考".这意味着,如果函数更改了引用(由指针指向),则必须首先释放先前的值,然后保留新的值.

When you pass a "pointer to strong" to a function, that means the function should expect the pointer to a "strong reference", and when the function exits, it should preserve the fact that the pointer points to a "strong reference". What this means is that if the function changes the reference (pointed to by the pointer), it must first release the previous value and then retain the new value.

但是,getArgument:atIndex:如何处理其void *自变量?它与所指向的对象无关,只需将其值复制到所指向的内存中即可.因此,它不会执行任何保留和释放操作.基本上,它会在value变量中执行普通的ARC前非保留分配.

However, what does getArgument:atIndex: do with its void * argument? It is agnostic about the thing pointed to, and simply copies the value into the memory pointed to. Therefore, it does not do any of this retain and release stuff. Basically, it performs a plain-old pre-ARC non-retaining assignment into your value variable.

那为什么会崩溃?发生的情况是,value首先是nil,然后在getArgument:atIndex:内,它向其中分配了新值,但并没有保留它.但是,ARC认为它已被保留,因为value是一个强引用.因此,在范围的最后,ARC释放了它.这是一个过发行版,因为它从未保留过.

So why is it crashing? What is happening is that value is at first nil, and then inside the getArgument:atIndex:, it assigns the new value into it, but it does not retain it. However, ARC assumes that it has been retained, since value is a strong reference. So at the end of the scope, ARC releases it. This is an over-release, since it was never retained.

解决方案是不要将强指针"传递给getArgument:,因为该方法对强"一无所知.而是向其中传递"unsafe_unretained指针"或"void指针",然后在以后将其转换为强引用:

The solution is to not pass a "pointer to strong" into getArgument:, because that method does not know anything about "strong". Instead, pass a "pointer to unsafe_unretained" or "pointer to void" into it, and then convert it to a strong reference later:

NSDictionary * __unsafe_unretained temp;
[anInvocation getArgument:&temp atIndex:2];
NSDictionary *options = temp; // or you can just use temp directly if careful

或替代:

void *temp;
[anInvocation getArgument:&temp atIndex:2];
NSDictionary *options = (__bridge NSDictionary *)temp;

这篇关于奇怪的“僵尸"在forwardInvocation中:+ getArgument:atIndex方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆