3

這裏是我的代碼部分:聊齋志異 「殭屍」 在forwardInvocation:+ getArgument:atIndex方法

- (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部分:方法:

- (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]; 
} 

問題當我使用「選項」變量 - 它工作正常,但使用直接值時 - 失敗,應用程序崩潰。使用配置文件我發現方法調用指向釋放對象。

爲什麼會發生這種情況? 沒有其他可以提供幫助的代碼。

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

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

+1

您可以加入至少剩餘部分來自'DPVkontakeUserAccount'的'forwardInvocation:'方法,並將第一個代碼示例放在上下文中 - 特別是在調用'usersGetWithCustomOptions:'之後特別引用了'options'變量?這可能會幫助民間人士幫助你。 – CRD

+0

@CRD現在可以嗎? – AndrewShmig

+1

我相信這會幫助人們。你說「使用配置文件我發現方法調用指向釋放對象。」,哪個方法調用?任何機會'enumerateKeysAndObjectsUsingBlock:'? – CRD

回答

3

的問題是,的getArgument:該參數的類型void *。並且您傳遞&value,即NSDictionary * __strong *(指向強引用)。該轉換是有效的,因爲可以在沒有任何警告的情況下分配來自void *的任何非對象指針。

當您將「強指針」傳遞給函數時,這意味着函數應該期望指向「強引用」的指針,並且當函數退出時,它應該保留指針指向「強有力的參考「。這意味着如果函數更改引用(由指針指向),它必須先釋放先前的值,然後保留新的值。

但是,getArgument:atIndex:做什麼void *論點?對指向的事物是不可知的,並且簡單地將該值複製到指向的內存中。因此,它不會做任何保留和釋放的東西。基本上,它會在您的value變量中執行一個普通的ARC之前的非保留分配。

那麼它爲什麼會崩潰?發生了什麼事value最初是nil,然後在getArgument:atIndex:裏面,它將新值賦給它,但它不保留它。但是,ARC假定它已被保留,因爲value是一個有力的參考。因此,在範圍的最後,ARC發佈了它。這是一個過度釋放,因爲它從來沒有保留。

解決方法是不要將「強指針」傳遞到getArgument:,因爲該方法不知道任何有關「強」的內容。相反,通過一個「指針unsafe_unretained」或「指針無效」了進去,然後將其轉換爲強引用後:

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;