在layoutSubviews中使用dispatch_once有什么问题吗?

时间:2013-12-16 19:44:47

标签: ios iphone objective-c ipad

我正在设置自定义UIButton,并且只需要将一组视图添加为子视图一次。 为了保持我的实施文件变得苗条,并且不要在initWithFrame:中设置所有视图,只是让某人做button = [[Button alloc] init]; button.frame = someFrame;之类的事情,我正在做以下事情;

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

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

这一切对我来说都很好;我只是想知道我是否正在做一些不推荐的事情? 为了进一步扩展这个问题,将dispatch_once放在一个不断被调用的方法中是否安全? (例如,在viewDidAppear)中查看设置代码。

3 个答案:

答案 0 :(得分:4)

layoutSubviews不应该用于添加子视图,因为它被多次调用(旋转,状态栏高度变化等)

相反,在UIView子类的init方法中添加子视图,并在layoutSubviews中设置其框架。

答案 1 :(得分:3)

这适用于按钮的第一个实例。任何其他实例都不会执行dispatch_once阻止。

只有在onceToken为NULL时才会调用

dispatch_once,因此不会为对象的每个实例调用此对象,因为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已经执行过,并且不会再次执行。

答案 2 :(得分:1)

您应该只使用layoutSubviews来设置视图框架。如果您打算添加子视图,那么执行此任务的好地方是viewDidLoad Method或awakeFromNib。