2012-02-16 77 views
2

我真的一直在努力,但我只是沒有得到很好的塊。我正在使用FMDatabaseQueue,我試圖做一個非常簡單的基於隊列的查詢。這是我有:如何從塊中獲取NSString?

-(NSString *) getReferenceForPage:(NSInteger) page 
{ 
    [queue inDatabase:^(FMDatabase *db) { 
     FMResultSet *rs = [db executeQuery:@"SELECT ref_text FROM table WHERE page = ?",[NSNumber numberWithInteger:page]]; 
     if ([rs next]) { 
      //this is where I get the string 
     } 
    }]; 
    return @""; //And this is where I need to return it, but I can't get it to work 
} 

我不知道爲什麼會這樣我很難把握,但我需要能夠做一些事情,我從結果集獲取字符串。通常情況下,我只會退還,但這不會在這裏飛。有人可以對此有所瞭解嗎?

感謝

編輯:我打電話給我的數據庫訪問對象,希望返回一個特定的值。很多這些調用將在後臺線程上運行,所以我使用這個數據庫隊列來保證線程安全。我更新了SQL查詢的上下文以顯示我需要做的事情。

+0

我很難理解你想要做什麼。你想要從塊中返回字符串......但是你要分配一個循環。你想要返回一個字符串嗎?全部歸還?你到底想要什麼? – 2012-02-16 07:27:31

+0

對不起,我將更新更多的上下文 – Lizza 2012-02-16 07:28:12

回答

7

看來你的問題歸結爲「如何從塊內返回值返回到調用函數?」它實際上很簡單,只要塊同步執行即可。只需使用__block變量並賦值給它。

__block NSString *result = nil; 
[queue inDatabase:^(FMDatabase *db) { 
    // I'm assuming this is synchronous, because I'm not familiar with the API 
    FMResultSet *rs = [db executeQuery:@"SELECT ref_text FROM table WHERE page = ?", [NSNumber numberWithInteger:page]]; 
    if ([rs next]) { 
     result = [[rs acquireStringSomehow] retain]; 
    } 
}]; 
return [result autorelease]; 

注意,該保留是因爲有可能是一個自動釋放池各地塊包裹,我們需要確保值保持(然後我們就可以自動釋放它的塊之外)。

如果該塊是異步執行的,那麼您不可能從調用函數返回值。如果您需要處理這種情況,那麼您需要將該值傳回適當的線程以供以後處理,例如,

NSString *str = [rs fetchStringSomehow]; 
dispatch_async(dispatch_get_main_queue(), ^{ 
    processString(str); 
}); 
+0

'processingString(str);'在Xcode 5中觸發一個警告,我通過創建一個本地方法並調用它來解決這個問題:'[self processString:str];' – sAguinaga 2014-01-25 11:15:32

4

我想你錯過了同步和異步執行的區別。我不熟悉你使用的隊列API,但我會說你插入到數據庫隊列中的塊不會立即同步執行。它在以後的某個時間點被異步執行,只有這樣你才能得到結果字符串。

對於getReferenceForPage方法,您有兩種選擇:使其異步,或者通過阻塞使其同步,直到結果字符串可用。第一種選擇更簡單,更可取。有實現它幾種方法,其中之一是傳遞一個塊消耗的字符串時,它的可用:

typedef void (^StringConsumer)(NSString*); 

-(void) getReferenceForPage: (NSInteger) page consumer: (StringConsumer) consumer 
{ 
    [queue inDatabase:^(FMDatabase *db) { 
     FMResultSet *rs = [db executeQuery:…]; 
     if ([rs next]) { 
      if (consumer) 
       consumer([db getResultString]); 
     } 
    }]; 
} 

// and in calling code: 
[self getReferenceForPage:1 consumer:^(NSString *reference) { 
    NSLog(@"Got reference: %@", reference); 
}]; 

另一種方法是調用已知的方法當字符串是可用的,看凱文的答案。

+0

是的,這是正確的答案,它應該放在FMDB的主頁面上,對嗎? – flypig 2012-08-20 07:02:11