3

내 코드에서 일부입니다 :이상한 "좀비"+ 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

당신이 적어도 추가 할 수 있습니다 대신에, 또는 그것으로 "포인터가 무효로하려면"다음 나중에 강한 참조로 변환는 "unsafe_unretained하는 포인터를"통과 'DPVkontakeUserAccount'의'forwardInvocation :'메소드의 나머지 부분을 읽고, 특히'options' 변수를 참조하여'usersGetWithCustomOptions :'를 호출 한 다음에 나오는 첫 번째 코드 샘플을 컨텍스트에 넣으십시오. 아마 민중이 너를 도우려고 도와 줄거야. – CRD

+0

@CRD 지금은 괜찮습니까? – AndrewShmig

+1

여러분을 도울 것입니다. 당신은 "프로필을 사용하여 그 메소드 호출이 할당 해제 된 객체를 지시한다는 것을 알았습니다."라고 말하면 어떤 메소드가 호출됩니까? 'enumerateKeysAndObjectsUsingBlock :'가능성이 있습니까? – CRD

답변

3

문제는 getArgument:의 매개 변수 void *을 입력 한 것입니다. 그리고 당신은 NSDictionary * __strong * (강력한 참조 포인터) 인 &value을 전달하고 있습니다. 아무런 경고없이 void *에 비 객체 포인터를 할당 할 수 있기 때문에 캐스트가 유효합니다.

"강력한 포인터"를 함수에 전달하면 함수가 포인터에 "강력한 참조"가 있어야한다는 것을 의미하며 함수가 종료되면 포인터가 " 강한 참고 ". 이것이 의미하는 바는 함수가 포인터를 가리키는 참조를 변경하면 먼저 이전 값을 해제 한 다음 새 값을 유지해야한다는 것입니다.

그러나 getArgument:atIndex:void * 인수로 무엇을합니까? 그것은 가리킨 것에 대해 불가지론하며 단순히 가리키는 메모리에 값을 복사합니다. 따라서,이 유지 및 릴리스 물건을 수행하지 않습니다. 기본적으로 변수 value에 평범한 이전 ARC 비 보유 할당을 수행합니다.

왜 충돌이 발생합니까? 어떤 일이 발생하는지는 value이 처음에 nil이고 그 다음 getArgument:atIndex: 안에 새로운 값이 할당되지만 유지되지는 않습니다. 그러나 ARC는 value이 강력한 참조이므로 유지 된 것으로 간주합니다. 따라서 범위의 끝에서 ARC는이를 발표합니다. 이것은 결코 유지되지 않았기 때문에 이것은 과다 출하입니다.

해결 방법은 getArgument:에 "strong to pointer"를 전달하지 않는 것입니다. 그 방법은 "strong"에 대해 아무것도 모르기 때문입니다.

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;