2013-02-28 112 views
3

我想要做的是Facebook iOS SDK的Facebook包裝。基本上這個想法是,我的ViewController應該什麼都不做,只是顯示ex。我將用一個簡單的調用,比如方法從FacebookSDK異步塊返回值

self.friends = [FacebookWrapper myFriends]; 
[self.tableView reloadData]; 

我的包裝myFriends方法來獲得朋友應該像這樣

+ (NSArray *)myFriends 
{ 
    __block NSArray *friends = nil; 
    [FBSession openActiveSessionWithReadPermissions:nil allowLoginUI:YES completionHandler:^(FBSession *session, FBSessionState status, NSError *error) { 
    if(FB_ISSESSIONOPENWITHSTATE(status)) { 
    [FBRequestConnection startForMyFriendsWithCompletionHandler:^(FBRequestConnection *connection, id data, NSError *error) { 
     CFRunLoopStop(CFRunLoopGetCurrent()); 
     if(error) { 
      return; 
     } 
     NSArray *friendsData = (NSArray *)[data data]; 
     NSMutableArray *fbFriends = [NSMutableArray array]; 
     for(id friendData in friendsData) { 
      Friend *friend = [Friend friendWithDictionary:friendData]; 
      fbFriends addObject:friend]; 
     } 
     friends = [NSArray arrayWithArray:fbFriends]; 
    }]; 
    CFRunLoopRun(); 
    } 
    }]; 
    return friends; 
} 

的問題是openActiveSessionWithReadPermissions和startForMyFriendsWithCompletionHandler是異步塊,這樣之前的方法返回塊完成他們的任務。

任何幫助將非常感激。

回答

0

如果你分派asynchronouos塊,你可以通過調用回它與您UIViewController子通信:

[self someSelectorWithCallbackData:stuffWhichYouWantToGiveBack]; 

這將調用self獲得由塊捕獲,因此將正常工作。從相關的方法你可以刷新視圖/重新加載tableview /跳舞夾具根據需要。

根據上下文,您可能需要__block範圍self,如

__block UIViewController *bsself = self; 

但是,如果你是後者,要小心避免保留環(構建和分析工具是指着還算不錯這一點)。

3

我在過去創建了一個類似的包裝,我的方法是在調用我的包裝方法時傳遞「完成塊」;一旦所有的異步調用都運行完成,這個完成塊就會被觸發,並且它會接收到你的方法在同步場景中返回的任何數據(在你的情況下是朋友數組)。

爲了說明 - 你可以有你的 「myFriends」 的方法重新定義爲:

+ (void)myFriendsWithCompletionBlock:(void (^)(NSArray *friends))completionBlock;

然後在實施中,friends = [NSArray arrayWithArray:fbFriends];線之後,你想補充一點:

if (completionBlock != nil) { 
    completionBlock(friends); 
} 

...並在最後刪除return聲明。

最後,您的視圖控制器(或使用該方法的對象上,你會做這樣的事情:

[FacebookWrapper myFriendsWithCompletionBlock:^(NSArray *friends){ 
    // do what you need to do with the friends array 
}]; 

當然,這仍然是異步的 - 但有沒有辦法解決,因爲這是怎麼了Facebook SDK是建立的(公平地說,這可能是最好的方法 - 等待請求完成同步將是可怕的!)

編輯:我注意到你也從包裝方法返回,以防它失敗;在這種情況下的,而不是返回你會做這樣的事情:

if (completionBlock != nil) { 
    completionBlock(nil); 
} 

,將導致friends陣列是nil當你完成塊被稱爲 - 那麼你可以把這個錯誤存在但似乎是適當的給你。

希望這有助於!

+0

這正是我一直在使用最多(當然我打電話我在錯誤的情況下completionBlock)的邏輯。但是,我想知道是否有任何方法有方法返回從方法本身內的異步塊獲取的值。不管怎麼說Thiago! – ozzotto 2013-02-28 15:59:13

+0

好吧!不幸的是,沒有辦法做到你想要達到的目的 - 至少不是沒有完全控制代碼,你沒有,因爲我們正在談論Facebook SDK :) – 2013-02-28 21:33:23

0

認爲你需要使用protol @class Webservice的;

@protocol WebserviceDelegate 
@optional 

-(void)webservice:(Webservice *)webservice didFetchPosts:(NSArray *)posts; 
-(void)webservice:(Webservice *)webservice didFetchComments:(NSArray *)comments forPostID:(NSString *)postID launchComments:(BOOL)launch; 
-(void)webservice:(Webservice *)webservice didLoginWithUser:(User *)user; 
-(void)webservice:(Webservice *)webservice didVoteWithSuccess:(BOOL)success forObject:(id)object direction:(BOOL)up; 

@end 

@interface Webservice : NSObject { 
    __weak id <WebserviceDelegate> delegate; 
} 
//Delegate 
@property (weak) id <WebserviceDelegate> delegate; 



-(void)getHomepage { 
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ 
     NSURLResponse *response; 
     NSError *error; 

     // Create the URL Request 
     NSMutableURLRequest *request = [Webservice NewGetRequestForURL:[NSURL URLWithString:@"https://www.hnsearch.com/bigrss"]]; 

     // Start the request 
     NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error]; 


     //Handle response 
     //Callback to main thread 
     if (responseData) { 
      NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSStringEncodingConversionAllowLossy]; 

      if (responseString.length > 0) { 
       dispatch_async(dispatch_get_main_queue(), ^{ 
        [self parseIDsAndGrabPosts:responseString]; 
       }); 
      } 
      else { 
       dispatch_async(dispatch_get_main_queue(), ^{ 
        [delegate webservice:self didFetchPosts:nil]; 
       }); 

      } 
     } 
     else { 
      dispatch_async(dispatch_get_main_queue(), ^{ 
       [delegate webservice:self didFetchPosts:nil]; 
      }); 
     } 


    }); 
} 


-(void)parseIDsAndGrabPosts:(NSString *)parseString { 
    // Parse String and grab IDs 
    NSMutableArray *items = [@[] mutableCopy]; 
    NSArray *itemIDs = [parseString componentsSeparatedByString:@"<hnsearch_id>"]; 
    for (int xx = 1; xx < itemIDs.count; xx++) { 
     NSString *idSubString = itemIDs[xx]; 
     [items addObject:[idSubString substringWithRange:NSMakeRange(0, 13)]]; 
    } 


    // Send IDs back to HNSearch for Posts 
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ 
     NSURLResponse *response; 
     NSError *error; 

     // Create Request String 
     NSString *requestString = @"http://api.thriftdb.com/api.hnsearch.com/items/_bulk/get_multi?ids="; 
     for (NSString *item in items) { 
      requestString = [requestString stringByAppendingString:[NSString stringWithFormat:@"%@,", item]]; 
     } 

     // Create the URL Request 
     NSMutableURLRequest *request = [Webservice NewGetRequestForURL:[NSURL URLWithString:requestString]]; 

     // Start the request 
     NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error]; 


     //Handle response 
     //Callback to main thread 
     if (responseData) { 
      NSArray *responseArray = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingAllowFragments error:&error]; 

      if (responseArray) { 
       NSMutableArray *postArray = [@[] mutableCopy]; 
       for (NSDictionary *dict in responseArray) { 
        [postArray addObject:[Post postFromDictionary:dict]]; 
       } 

       NSArray *orderedPostArray = [self orderPosts:postArray byItemIDs:items]; 

       dispatch_async(dispatch_get_main_queue(), ^{ 
        [delegate webservice:self didFetchPosts:orderedPostArray]; 

        // Update Karma for User 
        if ([HNSingleton sharedHNSingleton].User) { 
         [self reloadUserFromURLString:[NSString stringWithFormat:@"https://news.ycombinator.com/user?id=%@", [HNSingleton sharedHNSingleton].User.Username]]; 
        } 
       }); 
      } 
      else { 
       dispatch_async(dispatch_get_main_queue(), ^{ 
        [delegate webservice:self didFetchPosts:nil]; 
       }); 

      } 
     } 
     else { 
      dispatch_async(dispatch_get_main_queue(), ^{ 
       [delegate webservice:self didFetchPosts:nil]; 
      }); 
     } 


    }); 
}