2013-05-02 79 views
1

所以我有:如何保留在塊中設置的局部變量?

@interface testAppControl : NSObject 
{ 
    NSString *s; 
} 

,然後在我的塊我想做

[SendAPI setGroupWithName:groupName completionHandler:^(NSArray *errors) { 
    s = @"something"; 
}]; 

NSLog(@"%@", s); //<--- s is null 

所以我要保持價值"something"後,我離開我的塊。這可能與ARC?

+0

你的意思是,下次你遇到同樣的方法時,'s'應該有'something'。如果是這種情況,請將其聲明爲靜態。 – Mahesh 2013-05-02 20:52:31

+0

沒有,當我離開塊時,'s'是零,就像它從未設置,目前 – Pittfall 2013-05-02 20:53:49

+1

@Pittfall更可能,而不是_never_被設置,它的設置比你想象的晚,因爲'setGroupWithName'可能是一個緩慢的操作,在後臺異步運行。如果沒有看到這個方法的代碼或文檔,很難說,但它是來自'completionHandler'參數名稱的邏輯推理。 – Rob 2013-05-03 03:29:36

回答

0

是不完全清楚爲什麼你想這樣做,我給你3個選擇是什麼:

  • 聲明變量s塊外,將裏面 自動複製該塊內
  • 如果你需要改變它的值並讀取它在 __block說明符之外的塊之外聲明,注意如果你在異步過程中改變這個var,塊之後的值可能是無用的
  • 如果你想要至 保持和每次調用 塊期間改變其值decalre它的塊內爲static把這將是「看得見」的只有塊
0

它看起來就像你正在執行異步操作中,當完成塊被稱爲您已經離開定義s的功能/範圍。

考慮在「全局」範圍內(如類變量或屬性)聲明s,那麼只要您的類實例處於活動狀態,您將能夠讀取該塊設置的結果。

我會推薦使用一個屬性,並在塊中捕獲一個「弱自我」指針,以避免在存在s的實例被釋放的情況下錯誤的內存訪問。

3

聲明它爲__block變量,那麼你可以在塊外使用它並在塊內改變它。

__block NSString *s = nil; 

void(^block)(void) =^{ 
    s = @"something"; 
}; 
block(); 
NSLog(@"%@", s); 

s = @"blah"; 
NSLog(@"%@", s); 

block(); 
NSLog(@"%@", s); 
+0

在OP的代碼中,'s'是一個實例變量。 – newacct 2013-05-03 07:00:01

+0

@newacct問題已編輯,最初沒有指定。 – 2013-05-03 07:27:00

3

completionHandler非常存在可能導致一個在邏輯上推斷setGroupWithName是一個異步方法。這是iOS開發中的一種常見編程模式:在前臺(在此期間用戶界面將被凍結)中執行一些可能耗時的進程,而不是在後臺異步執行它,但在此情況下爲,completionHandler,這樣您可以確定在異步過程完成時應該發生什麼。

在這種情況下,它看起來像你調用setGroupWithName,在一些後臺線程/隊列的理解,雖然這是發生,你會繼續在主線程(在你的情況下,在該NSLog語句),確保您的應用在緩慢操作完成時保持響應。但是,當完成setGroupWithName的異步後臺操作時,它將執行由completionHandler(在您的情況中,s設置爲@"something")代表的代碼塊。

如果你把一個NSLog聲明completionHandler塊,在那裏你設置s@"something"裏面,你可能會看到,它是你的setGroupWithName調用後,對現有NSLog語句之後發生的好。


爲了說明的例子中,這裏是具有completionHandler參數,即NSURLConnection類方法,sendAsynchronousRequest標準可可方法的一個例子。

問題是如何執行緩慢的操作,但仍然有一個用戶界面,無需等待Internet操作的慢速響應。

所以,考慮下面的代碼:

- (void)performSearch:(NSString *)term 
{ 
    NSLog(@"%s start: array has %d items", __FUNCTION__, [self.array count]); 

    // prepare to do search (the details here are not relevant) 

    NSOperationQueue *queue = [[NSOperationQueue alloc] init]; 
    NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://search.twitter.com/search.json?q=%@", term]]; 
    NSURLRequest *request = [NSURLRequest requestWithURL:url]; 

    // submit an Internet search that will be performed in the background 

    [NSURLConnection sendAsynchronousRequest:request 
             queue:queue 
          completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) { 

           // in the background, when the Twitter search is done, 
           // and when it's done, we'll make an array of the results 

           self.array = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; 
           NSLog(@"%s: after background query, array now has %d items", __FUNCTION__, [self.array count]); 
          }]; 

    // in the meantime, let's immediately carry on while that search is taking place 

    NSLog(@"%s end: array still has %d items", __FUNCTION__, [self.array count]); 
} 

這段代碼的細節都不是很重要,但其基本思想是,它是做一些緩慢(在因特網上執行一個Twitter搜索),但它會立即繼續在主線程中運行代碼,讓後臺線程按照自己的步調繼續運行。

各種NSLog語句的時間戳是示出所有這些的定時:

 
2013-05-02 20:42:58.922 myapp[81642:c07] -[ViewController performSearch:] start: array has 0 items 
2013-05-02 20:42:58.923 myapp[81642:c07] -[ViewController performSearch:] end: array still has 0 items 
2013-05-02 20:42:59.798 myapp[81642:1303] __32-[ViewController performSearch:]_block_invoke: after background query, array now has 11 items 

注意,經過之間的「開始」和「結束」的時間是大約1毫秒,但在完成的Twitter搜索在後臺花了幾乎整整一秒才完成。設計原則是,如果我們沒有異步執行此操作,在這種情況下使用completionHandler,應用程序的用戶界面就會被凍結一秒鐘。但通過使用異步編程技術,該應用程序保持良好和響應,而是在後臺執行緩慢的操作。

我不熟悉setGroupWithName方法,但它大概是執行相同類型的異步操作。因此,您嘗試查看後面緊跟的值將不會反映一旦該方法完成後將會更改的值(有點像我的示例中的「結束」NSLog語句不反映將發生的更改秒後)。