问题:
有什么方法可以以编程方式和自动方式设置 IBOutlet 属性(即无需对要设置的属性进行硬编码)?也许有一些“IBOutlet 设置”例程我可以用自己的专用代码拦截?
背景:
导致上述问题的原因在于,在运行以下方法时未设置“IBOutleted”尺寸约束(宽度和高度)(这是一种用真实的 IB View 替换“占位符” View 的方法) View ):
+ (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 调用的。它已经在许多不同的 Nib 上进行了测试,到目前为止效果非常好。但现在的问题是,我必须重新创建那些与被替换的 View 严格相关的约束,即宽度和高度(与 super View 相关的约束被无缝转移)。我有一个 IBOutlet 用于此类约束,并且在执行此方法时它仍然为零。
为了澄清,代码:
[replacer addConstraint:constraintClone];
工作正常,约束已添加并应用。但是,相应的 IBOutlet 未设置(保持为 nil)。
更新:
Sashas 的答案是正确的,但是拦截 IBOutlet 分配的方法并没有解决我的问题。
正如 Sasha 指出的,我的背景部分相当不清楚。因此我将快速尝试以不同的方式解释它。
我用来在 Nib 文件中存储或多或少复杂的 View 。为了将它们无缝地插入 Storyboard或其他 nib 文件中,我实现了一个“NibLoadedView”类,它基本上用复杂 View 替换了来自 initWithCoder 的任何实例。换句话说,我可以在 Storyboard/IB 中设置简单占位符 UIView 的自定义类型,并且当应用程序运行时,它将在其位置加载真实/复杂 View 。应用于该占位符 View 的所有约束都应该移动到真实 View 。他们做到了,至少表达了占位符与其周围环境(其他 View )之间关系的所有约束。另一方面,大小约束存储在占位符 View 中,如果不转移到真实 View 中,就会丢失。我遇到的正是这种传输问题,因为一旦我复制了约束,它们就会按预期应用,但如果我将其中一个引用为 IBOutlet,则 IBOutlet 将变为 nil(它指向与占位符 View ,一旦该 View 及其所有约束被删除,弱 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,无论其设置在何处以及如何设置。
最佳答案
IBOutlet
通过 KVC 设置:当 Storyboard 或 nib 被解码时,它会为所有 socket (操作、 socket 集合)调用 setValue:forKey:
。如果由于某种原因您想干扰此过程,请覆盖它并在 key
正确时使用自定义逻辑。
也许您想研究一下awakeFromNib
- 因为它是 nib 完全解码且所有导出均已设置时的第一个方法。说实话,我不太明白这个目标,也许你可以解释一下。
关于objective-c - 拦截/以编程方式设置 IBOutlet 属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23921071/