문제

나는 질문이 있습니다. 어쩌면 2 가지 질문.

첫 번째는이 코드 조각과 관련이 있습니다.

-(void)isLoggedIn {
NSString *urlString = [NSString stringWithFormat:@"%@%@%@", kBaseURL, kAPI, kUserIsLogged];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer = [AFJSONResponseSerializer serializerWithReadingOptions:NSJSONReadingAllowFragments];
[manager GET:urlString parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
    NSLog(@"JSON: %@", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    NSLog(@"Error: %@", error);
}];
}
.

이 방법은 공백이 아닙니다. 나는 그것을 사용 할 수있는 bool이나 무언가를 반환하고 싶습니다 : 사용자가 로그인 한> 확인 앱 어딘가에서 뭔가를하십시오. 사용자가 로그인하지 않았습니다> 확인은 사용자에게 자신의 자격 증명을 소개하고 로그인 할 수있는 화면에 사용자에게 메시지를 표시합니다.

두 번째 질문은이 코드 조각과 관련이 있습니다 :

-(void)detail {
NSString *urlString = [NSString stringWithFormat:@"%@%@%@", kBaseURL, kAPI, kUser];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer = [AFJSONResponseSerializer serializerWithReadingOptions:NSJSONReadingAllowFragments];
[manager GET:urlString parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
    NSLog(@"JSON: %@", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    NSLog(@"Error: %@", error);
}];
}
.

이 방법은 내가 원하는 곳 어디에서나 사용할 수있는 구문 분석 된 JSON으로 나에게 nsarray를 반환하고 싶습니다.

이 메소드는 NetworkModel (NSObject 서브 클래스)이라는 모델에 포함됩니다. 나는 왜 내가 블록 안에있는 모든 것을 해야하는지 궁금해하고있다. 나는 장소 전체에서 네트워크와 상호 작용하는 조각이 있어야하며 하나의 독특한 장소 / 클래스로 구성되지 않아야합니다. 그 일을 할 수있는 방법이 있습니까? 모든 ViewController를 요청하는 5 줄의 요청을 원하지 않습니다. ViewController에서 호출 할 수있는 메소드를 정의하고 싶습니다 (필요한 경우 헤더 파일을 가져 오는 헤더 파일 가져 오기).

모든 제안? 조언에 감사드립니다!

도움이 되었습니까?

해결책

2 개의 접근 방식 으로이 작업을 수행하거나 블록을 사용하기 위해 메소드를 변경하거나 세마포어를 사용하여 비동기 요청을 대기합니다.

세마포어 (추한 방법)

-(BOOL)isLoggedIn {

__block BOOL isLoggedIn;
 dispatch_semaphore_t waiter = dispatch_semaphore_create(0);

NSString *urlString = [NSString stringWithFormat:@"%@%@%@", kBaseURL, kAPI, kUserIsLogged];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer = [AFJSONResponseSerializer serializerWithReadingOptions:NSJSONReadingAllowFragments];
[manager GET:urlString parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
    NSLog(@"JSON: %@", responseObject);
    isLoggedIn = YES;
    dispatch_semaphore_signal(waiter);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    NSLog(@"Error: %@", error);
    isLoggedIn = NO;
    dispatch_semaphore_signal(waiter);

}];

dispatch_group_wait(waiter, DISPATCH_TIME_FOREVER);
return isLoggedIn;
}
.

그것을 할 올바른 방법

-(void)isLoggedIn:(void(^)(BOOL isLoggedIn))completionBlock {
NSString *urlString = [NSString stringWithFormat:@"%@%@%@", kBaseURL, kAPI, kUserIsLogged];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer = [AFJSONResponseSerializer serializerWithReadingOptions:NSJSONReadingAllowFragments];
[manager GET:urlString parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
    NSLog(@"JSON: %@", responseObject);
    completionBlock(YES);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    NSLog(@"Error: %@", error);
    completionBlock(NO);
}];
}
.

두 번째 질문에 대해서는 요청이 완료되거나 실패 할 때 호출 될 네트워킹 클래스에서 블록 변수를 설정할 수 있습니다.

어쨌든 나는 당신이 블록에 익숙하지 않다고 생각합니다 (두 번째 질문 때문에). 그리고 나는 그들을 좋아하지 않기 시작하고 몇 개의 코드를 조화시키는 경우 코드가 복잡하지 않다는 것을 알게 될 것입니다.또한 요청 및 구문 분석을 수행하는 것도 SOOO가 쉽게 디버깅하기 쉽고 문제를 찾을 수 있음을 알 수 있습니다. 이는 블록으로 일하기 시작했습니다.

블록 변수 사용

@interface YourNetworkClass:NSObject {
void(^resultHandlerBlock)(NSArray *results); //this block has as param a NSArray, you can change it to whatever you want
}

-(void)setResultHandlerBlock:(void(^)(NSArray *array))handlerBlock;

@implementation YourNetworkClass

-(void)setResultHandlerBlock:(void(^)(NSArray *array))handlerBlock {
resultHandlerBlock = block;
}

-(void)anotherMethodThatDoesNetworkOperationsAndReturnsAnArray {
 ....
 resultHandlerBlock(arrayOfResults);
}


@interface AViewControllerThatUseNetwork: UIViewController {
}

@implementation AViewControllerThatUseNetwork 

-(void)initNetworkClass {
  YourNetworkClass *networkClass = [[YourNetworkClass alloc] init]; //or other init methods
  [networkClass setResultHandlerBlock:^(NSArray *results) {
   //do whatever you want with the array
}];
}
.

다른 팁

나는 뭔가를 비슷하게 물었다.나는 당신이 당신의 해결책을 찾을 것이라고 믿습니다. Afnetworking 메소드에 블록을 전달 하시겠습니까?

일반적으로 "Return Bool을 기록한 경우"로그인 할 수 있는지 "Afnetworking 블록 내에서 무언가를 수행 할 수있는 경우 데이터를 가져올 수있는 방법을 변경해야합니다.

위의 링크는 두 번째 질문에 답합니다.

AfnetWorking 성공 성공 (또는 실패) 블록에서 실행될 블록 (또는 2 개)을 가져 가야합니다.이 접근법은 당신이하려는 것의 비동기적 성질을 포용합니다.이 비동기로 인해 메서드에 반환 값을 추가 할 수 없습니다.


그래서, 당신은 당신의 방법을 바꾼다 :

-(void)isLoggedInWithCompletion:(LoginCompletionBlock)completion {
    ...

    [manager GET:urlString parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
        NSLog(@"JSON: %@", responseObject);
        completion(/* whatever parameters your block specifies */);
    } ...
}
.

그래서 상황에 대해 거의 업데이트됩니다 (모든 소중한 제안 께 감사드립니다.). 이제 내 코드는 이렇게 보입니다 (Networkmodel.m에서는 NetworkModel.h에 메서드를 추가 할 수 있으므로 전화를 걸 수 있습니다.) :

-(void)isLoggedIn:(void(^)(BOOL isLoggedIn))completionBlock {
NSString *urlString = [NSString stringWithFormat:@"%@%@%@", kBaseURL, kAPI, kUserIsLogged];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer = [AFJSONResponseSerializer serializerWithReadingOptions:NSJSONReadingAllowFragments];
[manager GET:urlString parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
    NSLog(@"JSON: %@", responseObject);
    if ([[NSString stringWithFormat:@"%@", responseObject] isEqualToString:@"true"]) {
        completionBlock(YES);
    } else {
       completionBlock(NO);
    }
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    NSLog(@"Error: %@", error);
    completionBlock(NO);
}];
}
.

내 AppDelegate.h에서 My NetworkModel.h와 AppDelegate.M에 다음 코드가 있습니다.

[[self model] isLoggedIn:^(BOOL isLoggedIn) {
    if (isLoggedIn == YES) {
        UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
        UIViewController *controller = [storyboard instantiateViewControllerWithIdentifier:@"Start01"];
        [self.window setRootViewController:controller];
    } else {
        UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
        UIViewController *controller = [storyboard instantiateViewControllerWithIdentifier:@"Start00"];
        [self.window setRootViewController:controller];
    }    
}];
.

그리고 그것이 잘 작동합니다. 그러나 이제는 이것에 대해 또 다른 질문이 있습니다. 내가 앱을 실행하면 이상한 일이 일어나고 있습니다. 사용자 로그인 상태에 대한 정보를 검색하자마자 VC (Storyboard의 지정된 InitialView Controller - Start00)에서 VC (Storyboard의 LoggedInvc - Start01)에서 점프합니다. 이런 종류의 사용자에게 점프하는 방법이 있습니까? 또는 이것은 정상적인 행동입니까? 이제 사용자가 첫 번째 화면을 보낸 다음 실제로보아야하는 화면을 보았습니다 (그가 로그인 한 원인).

그러나 나는 블록으로 일하는 가장 쉬운 방법을 추측하고, 이것이 필요한 곳에서 그들을 사용하는 것입니다. 그들을 메서드 나 클래스에 캡슐화하려고하는 대신에 데이터가 거기에 자마자 성공 또는 실패 블록 내에 직접적으로있는 것을 할 것입니다. 내가 생각하고 있니?

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top