2013-12-16 22 views
2

我設置了一個自定義UIButton,並且只需要將一堆視圖添加爲子視圖一次。 爲了保持我的實現文件苗條,並且避免設置initWithFrame:中的所有視圖,只讓某人執行類似button = [[Button alloc] init]; button.frame = someFrame;的操作,我正在執行以下操作;在layoutSubviews中使用dispatch_once有什麼問題嗎?

- (void)layoutSubviews 
{ 
    static dispatch_once_t onceToken; 
    dispatch_once(&onceToken, ^{ 
     [self setupViews]; 
    }); 
} 

- (void)setupViews 
{ 
    // add all subviews here 
} 

這一切看起來都很好,我只是想知道我是否正在做一些不被推薦的事情? 爲了進一步擴展這個問題,有沒有將dispatch_once放在一個不斷被調用的方法中是安全的? (例如,在viewDidAppear內查看設置代碼)。

+1

爲什麼不使用'viewDidLoad'來設置這個設置? – bdesham

+0

你有多少個實例? – Wain

+0

@bdesham,不能使用viewDidLoad,因爲它是一個子類UIButton。 – Sid

回答

3

這將適用於您的按鈕的第一個實例。任何其他實例將不會執行dispatch_once塊。

dispatch_once只有在onceToken爲NULL時纔會被調用,所以不會調用您的對象的每個實例,因爲onceToken在實例中持久存在。

[object layoutSubviews]

調用塊,但後來......

[object2 layoutSubviews]

不調用該塊。


@interface TestObject : NSObject 

- (void)log; 

@end 


@implementation TestObject 

- (void)log { 
    static dispatch_once_t onceToken; 
    dispatch_once(&onceToken, ^{ 
     NSLog(@"Called once"); 

    }); 
} 

@end 


TestObject *ob1 = [[TestObject alloc] init]; 
TestObject *ob2 = [[TestObject alloc] init]; 

[ob1 log]; 
[ob2 log]; 

2013-12-16 11:59:34.760 test[43445:70b] Called once

這就是你得到的輸出。因爲ob1已經運行,所以obj2看到onceToken已經執行並且不會再執行第二次。

+0

這清除了很多東西。謝謝。 – Sid

+0

經過進一步的思考,我越看越,越覺得我應該把這種模式從窗口中拿出來。如果我想讓用戶自由刪除子視圖,那麼由於dispatch_once的原因,無法將其添加回來。 – Sid

+0

我通常會[懶惰加載屬性](https://gist.github.com/skylarsch/7994593)。然後在init中,你可以設置背景顏色或類似的東西。 – SkylarSch

4

layoutSubviews不應該被用於添加子視圖,因爲它多次調用(上旋轉,狀態欄的高度變化等)

相反,添加子視圖在你的UIView子類的init方法,並設置他們的幀在layoutSubviews

+0

嗨亞倫,這是我以前做的,但我想擺脫使用這個初始化器。 layoutSubviews中的dispatch_once不應該類似於ARC下的單例模式嗎?我們多次調用一個單例的共享實例初始值設定項,並且它包含一個dispatch_once ...我認爲在layoutSubviews中做同樣的事情也是一樣的。 – Sid

+0

由於所有UI工作都應該在主線程上完成,因此您不需要'dispatch_once'。你可以使用'if(!someSubview)'。但是,當這正是初始化器的目的時,爲什麼「擺脫使用這個初始化器」呢? –

+0

我認爲對於UIButton,有些人可以使用initWithFrame,init和buttonWithTitle中的任何一種。我正在試驗可行的備選方案,以便在初始階段以外進行,以避免對三者進行定製。 – Sid

1

您應該只使用layoutSubviews來設置您的視圖框架。如果你打算添加子視圖,做這個任務的好地方是viewDidLoad Method或awakeFromNib。

+0

不幸的是,由於這是一個UIButton子類,我沒有使用這個IB文件,所以這些方法都不適用。不過,我會試圖找出一個不同的方式來做到這一點。我唯一擔心的是我想從這個自定義初始值設定項中移開。這使開發人員可以自由地使用他們想要的按鈕的任何初始化器(initWithFrame,init,buttonWithTitle等)。 – Sid

+0

如果是子類按鈕,則只需要在init方法中添加所有子視圖。 – D33pN16h7