objective-c - 拦截/以编程方式设置 IBOutlet 属性

标签 objective-c constraints nib objective-c-runtime

问题:

有什么方法可以以编程方式和自动方式设置 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/

相关文章:

ios - UITableViewCell contentView 中的自动布局

ios - UITableViewCells Nib 在滚动时显示默认值

swift - 从外部引用设置 .attributedText 属性(可通过 NIB 加载的 UIView 内的 socket 访问)似乎失败

iphone - 保留 IBOutlet 数量

objective-c - 在 iOS objective-c 中将 iPhone 属性设置为只读

objective-c - 保存 NSScrollView 中的整个 NSView 内容

ios - 为什么我的 UIButton 中的标题在 iOS 8 中垂直未对齐?

ios - Swift4 - 我第一次无法显示 CollectionView "Unable to simultaneously satisfy constraints"

iphone - 正确排序 NSString 数组,包括以破折号或特殊符号开头的单词(对于字典)

约束比较器