2013-12-16 4 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은 이미 수행 한 것으로보고 다시 수행하지 않습니다.

+0

그것은 물건을 많이 지 웁니다. 고맙습니다. – Sid

+0

더 생각하면, 더 많이 볼수록이 패턴을 창 밖으로 내야하는 것처럼 느껴집니다. 사용자에게 하위보기를 제거 할 자유를 주려면 dispatch_once 때문에 하위보기를 다시 추가 할 수 없습니다. – Sid

+0

일반적으로 [속성에 대한 지연로드] (https://gist.github.com/skylarsch/7994593)를 수행합니다. 그런 다음 init에서 배경색이나 비슷한 것을 설정할 수 있습니다. – SkylarSch

4

layoutSubviews 당신의 UIView 하위의 init 방법에 파단이 (등 상태 표시 줄 높이 변화, 회전에) 여러 번 호출 이후, 파단을 추가

대신 추가하는 데 사용하고, 설정하지 말아야합니다 그들의 프레임은 layoutSubviews입니다.

+0

안녕하세요, Aaron, 그랬지.하지만 이것에 대한 초기화 도구를 사용하지 않으려 고했습니다. layoutSubviews 내의 dispatch_once가 ARC 아래의 싱글 톤 패턴과 유사하게 작동하지 않아야합니까? 우리는 싱글 톤을위한 공유 인스턴스 이니셜 라이저를 여러 번 호출하고 디스패치 _ 온스 (dispatch_once)를 포함합니다 ... 나는 layoutSubviews와 똑같이하는 것이 같은 일이라고 생각했습니다. – Sid

+0

모든 UI 작업은 주 스레드에서 수행되어야하므로이 작업을 위해 'dispatch_once'가 필요하지 않습니다. 'if (! someSubview)'를 사용할 수 있습니다. 하지만 이것이 왜 이니셜 라이저를 사용하는지 명확하게 밝혀야하는 이유는 무엇입니까? –

+0

UIButton의 경우 initWithFrame, init 및 buttonWithTitle 중 하나를 사용할 수 있다고 생각했습니다. 나는이 세 가지를 모두 커스터마이징하는 것을 피하기 위해 init 밖에서 실행 가능한 대안을 실험했다. – Sid

1

뷰 프레임을 설정하려면 layoutSubviews 만 사용해야합니다. 하위 뷰를 추가하려는 경우 viewDidLoad Method 또는 awakeFromNib를 사용하여이 작업을 수행 할 수 있습니다.

+0

불행히도 이것은 UIButton 하위 클래스이므로 IB 파일을 사용하고 있지 않으므로 해당 방법 중 하나도 적용되지 않습니다. 그러나 나는 이것을 할 다른 방법을 찾아 내려고 노력할 것이다. 내 유일한 관심사는이 사용자 정의 이니셜 라이저에서 벗어나려는 것입니다. 따라서 개발자는 버튼에 대해 원하는 초기화 도구 (initWithFrame, init, buttonWithTitle 등)를 자유롭게 사용할 수 있습니다. – Sid

+0

하위 클래스 단추 인 경우 init 메서드에 모든 하위 뷰를 추가하기 만하면됩니다. – D33pN16h7

관련 문제