iOS正确的方法来使用自定义Xib和View覆盖initWithFrame?

时间:2014-07-21 20:06:39

标签: ios objective-c uiview xib nib

现在,我对我为创建自定义视图而创建的这个hacky变通方法感到不满。它在initWithFrame的另一个视图控制器中以编程方式初始化,因此我在代码中重写了它。这似乎不是初始化我的视图的正确方法,但我不确定还能做什么。

- (instancetype)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        self = [[[NSBundle mainBundle] loadNibNamed:@"OTGMarkerDetailView" owner:self options:nil] lastObject];
        [self setFrame:frame];
    }
    return self;
}

如果没有setFrame方法,自定义视图似乎总是在窗口顶部而不是在我用CGRectMake指定的坐标处创建。

我在视图控制器中的方法中初始化视图。

- (BOOL)mapView:(GMSMapView *)mapView didTapMarker:(GMSMarker *)marker {
    if (!self.detailView) {
        self.detailView = [[OTGMarkerDetailView alloc] initWithFrame:CGRectMake(0, 568, 320, 55)];
    }

    [self.view addSubview:self.detailView];
    self.detailView.backgroundColor = [UIColor whiteColor];

    NSRange range = [self.startAddress rangeOfString:@","];
    NSString *mainAddress = [self.startAddress substringToIndex:range.location];
    NSString *subAddress = [self.startAddress substringFromIndex:range.location + 1];
    [self.detailView setLabelsWithMainAddress:mainAddress subAddress:subAddress];

    [UIView animateWithDuration:0.5 animations:^{
        self.detailView.frame = CGRectMake(0, 513, 320, 55);
    }];

    return YES;
}

2 个答案:

答案 0 :(得分:0)

mapView方法为什么不执行init方法所做的操作,即直接将视图拉出其笔尖?换句话说,为什么你要隐藏mapView获取此视图实例的方法是加载一个笔尖?没有理由隐瞒这一事实。

或者,如果你想隐藏这个事实,为什么不把一个便利构造函数作为视图的类方法而不是误用initWithFrame?例如[OTGMarkerDetailView makeADetailView] ...

答案 1 :(得分:0)

一般来说,处理这类事情的最佳方法是使用类工厂方法:

+(instancetype)markerDetailView {
    [[[NSBundle mainBundle] loadNibNamed:@"OTGMarkerDetailView" owner:nil options:nil] lastObject];
}

然后使用以下命令创建视图:

self.detailView = [OTGMarkerDetailView markerDetailView];

请注意,我还希望采用更加类型安全的方法从nib文件加载视图:

+(instancetype)markerDetailView {
    for(OTGMarkerDetailView* view in [[NSBundle mainBundle] loadNibNamed:@"OTGMarkerDetailView" owner:nil options:nil]) {
        if([view isKindOfClass:[OTGMarkerDetailView class]]) {
            return view;
        }
    }

    NSAssert(false, @"Failed to load OTGMarkerDetailView");
    return nil;
}

如果您需要在InterfaceBuilder中使用自定义视图的实例,则必须覆盖initWithCoder:initWithFrame:。由于您要替换自己,因此我们确实无需拨打super

-(id)initWithCoder:(NSCoder*)aDecoder {
    self = [[self class] markerDetailView];
    // I think this will work to inherit settable properties in IB
    if((self = [super initWithCoder:aDecoder])) {
        // support any additional settable properties in IB
    }
    return self;
}