【发布时间】:2014-05-28 20:19:12
【问题描述】:
问题:
有什么方法可以以编程方式自动设置 IBOutlet 属性(即,无需对要设置的属性进行硬编码)?也许有一些“IBOutlet 设置”例程我可以用我自己的专用代码拦截?
背景:
导致上述问题的问题源于运行以下方法时未设置“IBOutleted”大小约束(宽度和高度)(这是一种将 IB 中的“占位符”视图替换为真实视图的方法)查看):
+ (UIView*) replaceWithNibViewIfPlaceholder:(UIView*)view {
BOOL isPlaceholder = ([[view subviews] count] == 0);
// Special treatment for buttons (which contain their title label, and thus
// always have one subview):
if ([view isKindOfClass:[UIButton class]] && [[view subviews] count] == 1) {
isPlaceholder = [[[view subviews] firstObject] isKindOfClass:[UILabel class]];
}
if (isPlaceholder) {
// We're assuming that there only is one root view, and that it is of the correct type:
UIView* replacer = [[view class] loadFromNib];
// We don't need to set the frame nor autoresizingMask as we're utilizing auto layout.
replacer.tag = view.tag;
replacer.alpha = view.alpha;
replacer.hidden = view.hidden;
// Copy intrinsic constraints (i.e. size constraints, which are only associated with the view itself):
[[view constraints] enumerateObjectsUsingBlock:^(NSLayoutConstraint* constraint, NSUInteger idx, BOOL *stop) {
// If the constraint is not a size constraint, continue loop:
if ((constraint.firstAttribute != NSLayoutAttributeWidth &&
constraint.firstAttribute != NSLayoutAttributeHeight &&
constraint.firstAttribute != NSLayoutAttributeNotAnAttribute) ||
(constraint.secondAttribute != NSLayoutAttributeWidth &&
constraint.secondAttribute != NSLayoutAttributeHeight &&
constraint.secondAttribute != NSLayoutAttributeNotAnAttribute))
return;
NSLayoutConstraint* constraintClone = [NSLayoutConstraint constraintWithItem:replacer attribute:constraint.firstAttribute relatedBy:constraint.relation toItem:nil attribute:constraint.secondAttribute multiplier:constraint.multiplier constant:constraint.constant];
// Now add the width or height constraint:
[replacer addConstraint:constraintClone];
}];
return replacer;
}
return view;
}
这个方法是从 UIView::awakeAfterUsingCoder:(NSCoder*)coder 调用的。它已经用许多不同的笔尖进行了测试,到目前为止效果很好。但是,现在的问题是我必须重新创建那些与被替换视图严格相关的约束,即宽度和高度(与超级视图相关的约束被无缝转移)。我有一个用于此类约束的 IBOutlet,并且在通过此方法时它仍然为零。
为了澄清,代码:
[replacer addConstraint:constraintClone];
工作正常,添加并应用了约束。但是,未设置相应的 IBOutlet(保持为零)。
更新:
Sashas 的回答是正确的,但是拦截 IBOutlet 分配的方法并没有解决我的问题。
正如 Sasha 所指出的,我的背景部分很不清楚。因此,我将快速尝试以不同的方式解释它。
我习惯在 Nib 文件中存储或多或少复杂的视图。为了将它们无缝地插入到故事板或其他 nib 文件中,我实现了一个“NibLoadedView”类,它基本上用复杂视图替换了来自 initWithCoder 的任何实例。换句话说,我可以在 storyboard/IB 中设置一个简单的占位符 UIView 的自定义类型,并在应用程序运行时加载真实/复杂的视图。应用于该占位符视图的所有约束都应该移动到真实视图。他们做到了,至少所有的约束都表达了占位符与其周围环境(其他视图)之间的关系。另一方面,大小约束存储在占位符视图中,如果不转移到真实视图中,将会丢失。正是这种转移,我遇到了问题,因为一旦我复制了约束,它们就会按预期应用,但是如果我将其中一个引用为 IBOutlet,则 IBOutlet 将变为 nil(它指向与占位符视图,一旦删除了所有约束的视图,弱 IBOutlet 变为 nil;强 IBOutlet 也不会改变任何东西,它只会持有错误的约束而不是 nil。
解决方案是替换:
[replacer addConstraint:constraintClone];
与:
memcpy((__bridge void*)constraint, (__bridge const void*)constraintClone, malloc_size((__bridge const void *)constraint));
[replacer addConstraint:constraint];
这将使用 constraintClone 覆盖其在内存中的位置的约束,这样会隐式更新 IBOutlet,无论它是在哪里设置的。
【问题讨论】:
-
你不能使用该插座属性的设置器吗?
-
@CrimsonChris 我可以,但这不是我在问题中要求的“自动方式”。此实现是许多不同组件视图的超类。
标签: objective-c constraints nib objective-c-runtime