2012-12-21 101 views
1

以前也有類似的問題,但是我無法解決我目前遇到的任何問題。保留iOS塊的問題

現狀:

CustomType *Object; 
BOOL (^doAverage)(CustomType *, int, int) = ^(CustomType *Trigger, int Total, int Pulse) { 
    //Calculate Average from Total and Pulse 
    Total /= Pulse; 
    [Trigger setValue:Total]; 
}; 

Object = [CustomType CreateObject]; //Autoreleased Object 
[Object addCallback:^{ return doAverage(Object, 56, 32); }]; 
[Array addObject:Object];  //Adds to collection. 

問題在手,你可能已經想通保留週期。
Object保留對addCallback中的塊的引用,並且塊doAverage保留對Object的引用。

使用實例變量是不可能的,因爲我想爲多個對象重用變量Object。 (臨時變量)。
使用本地變量會導致保留計數。
並且使用__block CustomType *Object也不起作用,因爲無論出於何種原因,Trigger都會在實際調用回調後變爲零。

任何想法?

我有一個臨時解決方案,但它似乎相當...哈克。

+0

剛指出它,總是使對象小寫,並且你在第一行中缺少一個指針。 – NSAddict

+0

@NSAddict感謝您的指針,我解決了這個問題。關於小寫......爲什麼?你看,我已經用C++「長大」了,因此贊成CamelCase符號。 (帶大寫字母的大寫字母) – ATaylor

+1

這是大多數編程語言的標準。類>從大寫字母開始,變量>從小寫字母開始,它更具可讀性,因爲您可以調用類和對象的方法。 – NSAddict

回答

1

如前所述,這個答案是相當哈克,我會很高興,如果有人能在一個更好的方向指向我。
很顯然,一個原始數據類型與__block變量結合起來,雖然這有點複雜。

void *Ptr;    //Variable for Block. 
__block CustomType *Obj; //Function variable, mutable by block. 
BOOL (^doAverage)(void *, int, int) = ^(void *Trigger, int Total, int Pulse) { 
    CustomType *T = (CustomType *)Trigger; //Conversion 
    //Calculate Average from Total and Pulse 
    Total /= Pulse; 
    [T setValue:Total]; 
}; 

//Convenience method. 
CustomObject *(^Add)(CustomObject *) = ^(CustomObject *)NewObject { 
    [Array addObject:NewObject]; 
    Obj = NewObject; //Assigns to the local block-Variable. 
    return Obj; 
}; 

Ptr = Add([CustomObject CreateObject]); //Creates the Object, and adds it to the array. 
[Obj addCallback:^{ return doAverage(Ptr, 56, 32); }]; 

由於Ptr是原始類型,它不會被保留,也不必被釋放。同時,它假設對象的地址,從而加倍。

一旦對象被釋放,帶指針的塊也是一切都很好。 一旦塊被調用,指針需要被轉換爲所討論的類型,但這只是一個小問題。

Add是可選的,當然,但我不喜歡的語法Ptr = Obj = [CustomObject CreateObject];

+0

這甚至不是有效的代碼。 'Add'塊有返回類型,但是在主體中沒有返回 – newacct

+0

@newacct我請求你的原諒。我一定在複製代碼時忘記了返回語句。 – ATaylor

-3

嘗試宣告對象爲

__weak CustomType *Object 
+2

XCode引發了一個警告:'不能在自動變量上指定__weak屬性。 – ATaylor

+0

這會在分配對象後儘快釋放該對象。 或者因爲它是一個自動釋放對象,只要它已被自動釋放。 – NSAddict

0

如果您的部署目標是至少的iOS 5(或OS X 10.7),你可以使用「歸零弱引用」:

CustomType *object = [CustomType makeObject]; 
__weak CustomType *weakObject = object; 
[object addCallback:^{ 
    CustomType *strongObject = weakObject; 
    if (strongObject) 
     return doAverage(weakObject, 56, 32); 
    else 
     return 0; 
}]; 

(我已經使用了makeObject代替CreateObject的「工廠法」的名字,因爲在他們的名字「創造」的方法有望重返一(+1)保留計數的對象,而不是一個自動釋放對象)

__weak引用不會增加保留計數,因此不會創建保留週期。如果object由於最後一次強參考消失而被破壞,則weakSelf設置爲nil。在塊內創建一個強引用,該引用或者指向該對象,如果它仍然存在,或者是nil,如果它不再存在。

如果我明白你的代碼正確,如果對象已被釋放,回調將不會被調用。在這種情況下,一個__unsafe_unretained參考就足夠了(這也適用於iOS 4):

CustomType *object = [CustomType makeObject]; 
__unsafe_unretained CustomType *unsafeObject = object; 
[object addCallback:^{ 
    return doAverage(unsafeObject, 56, 32); 
}]; 
+0

假設他正在使用ARC,即 – newacct

+0

@newacct:是的,我假設這一點。 __unsafe_unretained在沒有ARC的情況下可用,但可能無助於此。 –

+0

'__unsafe_unretained'不會在MRC下做你想要的。它仍將保留。您需要MRC下的'__block'。 – newacct

1

幾件事情。首先,我想看看你的addCallback:方法。您可能錯誤地實現了它。例如,如果您存儲一個塊供以後使用,則必須將其複製。如果這是不正確的,所有的投注都在其餘的東西上。

而且使用__block CustomType *對象也不管用,因爲 不管是什麼原因觸發最終成爲零一旦回調實際上是 調用。

所以,如果它是nil,則意味着您分配給nil某處Object

+0

是的,我注意到'複製'是必要的。這就是爲什麼'addCallback'創建一個對象(一個容器)用'[Block copy]保存引用'的原因。是的,分配一個「零」值是可能的。然而,我想要的是一個「非保留的對象拷貝」,一旦相應的對象被釋放,這個拷貝就會「丟失」。 – ATaylor

+0

@ATaylor:你是否在做循環內部的'addCallback',但是在循環之外聲明瞭__block'變量?如果是這樣,那麼所有塊將引用相同的'__block'變量,如果該變量的值在循環的迭代之間改變,則會導致問題。如果你正在做這樣的事情,你可能想把'__block'變量放在循環裏面 – newacct

+0

不是,但它是一個類似的行爲。我有一個使用相同變量添加到同一個數組的語句列表。雖然這給了我一個想法,即一組'__block'變量可能是解決方案......但是,對於這樣一個簡單的任務來說,這看起來非常複雜......儘管現在又出現了另一個想法。如果我聲明另一個名爲'addWithCallback'的塊,會發生什麼情況,它會同時使用對象和塊? – ATaylor

1
CustomType *Object; 
BOOL (^doAverage)(CustomType *, int, int) = ^(CustomType *Trigger, int Total, int Pulse) { 
//Calculate Average from Total and Pulse 
Total /= Pulse; 
[Trigger setValue:Total]; 
}; 

Object = [CustomType CreateObject]; //Autoreleased Object 
[Object addCallback:^{ return doAverage(Object, 56, 32); }]; 

泰勒說 - >「但是什麼我要的是有問題,這將是‘丟失’,一旦相應的對象被釋放一個‘對象的非保留副本’。」

此代碼似乎並不除非你或的addCallback([^ {}副本])內使用拷貝引起保留-cyle; ..

它在哪裏完全複製中使用您的碼?在addCallback內部?如果這是這樣的:

addCallback(o) { 

o = [o copy]; 
o(); 

then do a [o release]; when you done with a block object.. do not release it in dealloc() 
} 

如果你從來沒有使用複製的任何地方,沒有什麼可擔心的..這一切都發生在堆棧中的意思是不能保持在個循環所有,除非它是不是一個全球性!

如果有一個零售cyle,不要使用__block __weak等,而不是做釋放它是什麼對象在塊的末尾..並記住,沒有副本沒有保留週期..

+0

雖然我在'addCallback'中使用'copy',只是因爲否則在我使用它之前塊會被釋放。雖然我猜想'一次性'回調可能會訣竅。 (使用一次,然後釋放)。謝謝您的意見。 – ATaylor

+0

所以在你的回調中使用副本是做它的正確形式..複製它,調用它,並在完成後釋放塊,這將立即釋放對象..你在哪裏看到該方案中的保留週期不是對我清楚嗎?它不是創建保留循環的運行時,而是設計器/編碼器。在將其添加到回調並使用dispatch_async(0,{block(); [block release]})後釋放「Object」;以查看結果即使工作沒有複製它,如果它是一個即時操作(不持久)..保留週期塊的最終解決方案是中間obj,thnx – DeniziOS

+0

是的,就是這一點,我沒有釋放它在使用後,但當我完成了包含回調的對象時,該回調被塊保留下來......電腦......只要他們做了我想讓他們做的事情,而不是我告訴他們做的事,對吧? :) – ATaylor