何时设置 XIB 插座属性?
Posted
技术标签:
【中文标题】何时设置 XIB 插座属性?【英文标题】:When are XIB outlet properties set? 【发布时间】:2013-04-11 14:37:55 【问题描述】:我正在尝试使用 xib 文件实现继承。是的,有点奇怪,但让我告诉你为什么。
我有一个类,SLBaseViewController,我的许多视图控制器都继承自该类。当我想要一个子视图控制器时,我以通常的方式创建它:
SLHomeViewController *controller = [[SLHomeViewController alloc] initWithNibName:@"SLHomeViewController" bundle:nil];
这很好用。 SLHomeViewController 是一个 SLBaseViewController(它是一个 UIViewController)。
我这样做是因为我有其他想要继承 SLBaseViewController 行为的视图控制器。就我而言,我有一个在我的应用程序中通用的导航 UI 小部件,因此 SLSceneViewControll 也继承自 SLBaseViewController 并且 SLHomeViewController 和 SLSceneViewController 都获得了自定义导航小部件行为。
自定义导航小部件还具有跨 SLBaseViewControllers 通用的位置信息。所以我实现了一个穷人的方式来做xib继承。
@interface SLBaseViewController : UIViewController <SLNavBarViewControllerDelegate>
@property (strong, nonatomic) IBOutlet UIView *navBarExtendedFPO;
继承是在 initWithNibName 中完成的
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self)
Class callingClass = [self class];
Class slBaseViewControllerClass = NSClassFromString (SL_BASE_VC_CLASS_NAME);
if (callingClass != slBaseViewControllerClass)
SLBaseViewController *controller = [[SLBaseViewController alloc] initWithNibName:@"SLBaseViewController" bundle:nil];
// now load all the properties by hand
self.navBarExtendedFPO = controller.navBarExtendedFPO;
return self;
如果我创建一个 SLHomeViewController 加载 SLBaseViewController 的 xib,然后从中复制有趣的属性。如果 initWithNibName 检测到它正在加载一个 SLBaseViewController,它什么也不做,防止无限循环。
当然,问题是尚未设置出口属性。所以它只是复制 nil。
那么这些插座属性是什么时候设置的呢?
或者 - 有没有更好的方法来做我想做的事情?在我手动复制属性之前,这一切似乎都很美好。这对我来说似乎很脆弱。
(请注意,我可以使用仅限 ios6 的解决方案。)
【问题讨论】:
好的,所以你有两个UIViewControllers
,它们继承自第三个UIViewController
,对吗?这里的问题是您想在您通常从子类中使用的所有UIViewController's
+ UIViewController's
XIB 中使用一个小部件?是这样吗?
在视图控制器中有延迟初始化。因此,只有在调用属性 controller.view 后才会加载视图 - 在 viewController 中将调用 loadView 方法和 viewDidLoad 方法。
是的 Jacky Boy,但可能不止 2 个。
您的导航工具有多复杂?您是否考虑过一种以编程方式生成它的方法?可以在基本视图控制器的子类的每个实例中自反调用的东西?
@PaulCezanne,对不起我的英语,在您调用 controller.view 属性后,您的 IBOutlet 将不为零 :) 只需在 self.navBarExtendedFPO = controller.navBarExtendedFPO 之前调用 controller.view;
【参考方案1】:
这是因为 UIViewController 的延迟初始化。
UIViewController 的视图只会在一些之后加载 调用视图属性。
这样:
controller.view
所以,在你的情况下,你可以在self.navBarExtendedFPO = controller.navBarExtendedFPO;
之前调用controller.view
为了更清楚地解释视图生命周期,有一个例子:
在您的 SLBaseViewController 中有被覆盖的方法,self.label
是模拟的
navBarExtendedFPO
在 XIB 文件中定义
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self)
NSLog(@"initWithNibName: view loaded - %d , IBOuttlet loaded - %d", [self isViewLoaded], self.label != nil);
return self;
- (void)loadView
NSLog(@"loadView1: view loaded - %d , IBOuttlet loaded - %d", [self isViewLoaded], self.label != nil);
[super loadView];
NSLog(@"loadView2: view loaded - %d , IBOuttlet loaded - %d", [self isViewLoaded], self.label != nil);
- (void)viewDidLoad
NSLog(@"viewDidLoad1: view loaded - %d , IBOuttlet loaded - %d", [self isViewLoaded], self.label != nil);
[super viewDidLoad];
NSLog(@"viewDidLoad2: view loaded - %d , IBOuttlet loaded - %d", [self isViewLoaded], self.label != nil);
还有创建 SLBaseViewController 的方法
SLBaseViewController *testController = [[SLBaseViewController alloc] initWithNibName:@"SLBaseViewController" bundle:nil];
NSLog(@"after initialization: view loaded - %d , IBOuttlet loaded - %d", [testController isViewLoaded], testController.label != nil);
UIView * testView = testController.view;
NSLog(@"after calling testView.view: view loaded - %d , IBOuttlet loaded - %d", [testController isViewLoaded], testController.label != nil);
所以,有我们的日志:
initWithNibName: view loaded - 0 , IBOuttlet loaded - 0
after initialization: view loaded - 0 , IBOuttlet loaded - 0
loadView1: view loaded - 0 , IBOuttlet loaded - 0
loadView2: view loaded - 1 , IBOuttlet loaded - 1
viewDidLoad1: view loaded - 1 , IBOuttlet loaded - 1
viewDidLoad2: view loaded - 1 , IBOuttlet loaded - 1
after calling testView.view: view loaded - 1 , IBOuttlet loaded - 1
【讨论】:
以上是关于何时设置 XIB 插座属性?的主要内容,如果未能解决你的问题,请参考以下文章
使用 xib 创建可重用的 UIView(并从情节提要中加载)