拦截/以编程方式设置IBOutlet属性 [英] Intercept/Programmatically set IBOutlet properties

查看:137
本文介绍了拦截/以编程方式设置IBOutlet属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题:



有没有办法以编程方式和以自动方式设置IBOutlet属性属性设置)?也许有一些IBOutlet设置例程,我可以用我自己的专门的代码拦截?



背景: b

导致上述问题的问题源于以下事实:运行以下方法时未设置IBOutleted大小约束(宽度和高度)(这是一种替换占位符视图的方法从IB的真实视图):

  +(UIView *)replaceWithNibViewIfPlaceholder:(UIView *)view {

BOOL isPlaceholder =([[view subviews] count] == 0);

//按钮的特殊处理(包含它们的标题标签,因此
//总有一个子视图):
if([view isKindOfClass:[UIButton class]] &&&&&& [1] {

isPlaceholder = [[view subviews] firstObject] isKindOfClass:[UILabel class]
}

if(isPlaceholder){

//我们假设只有一个根视图,并且它是正确的类型:
UIView * replacer = [[view class] loadFromNib];

//我们不需要设置框架或autoresizingMask,因为我们使用自动布局。

replacer.tag = view.tag;
replacer.alpha = view.alpha;
replacer.hidden = view.hidden;

//复制内部约束(即大小约束,只与视图本身相关):
[[view constraints] enumerateObjectsUsingBlock:^(NSLayoutConstraint * constraint,NSUInteger idx,BOOL *停止){

//如果约束不是大小约束,则继续循环:
if((constraint.firstAttribute!= NSLayoutAttributeWidth&
constraint.firstAttribute! = NSLayoutAttributeHeight&
constraint.firstAttribute!= NSLayoutAttributeNotAnAttribute)||
(constraint.secondAttribute!= NSLayoutAttributeWidth&
constraint.secondAttribute!= NSLayoutAttributeHeight& $ b 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];

//现在添加宽度或高度约束:
[replacer addConstraint:constraintClone];
}];

return replacer;
}

return view;
}

此方法从UIView :: awakeAfterUsingCoder:(NSCoder *)coder调用。它已经与许多不同的Nibs测试,并且迄今为止工作完美。现在的问题是,我必须重新创建那些严格与被替换的视图相关的约束,即宽度和高度(与superview相关的约束被无缝地传递)。



为了说明,代码:

  [replacer addConstraint:constraintClone]; 

可以很好地添加和应用约束。




$ b

p> Sashas的答案是正确的,但截取IBOutlet赋值的方法没有解决我的问题。



正如Sasha指出的,我的背景部分是不清楚的。因此,我将快速尝试以不同的方式解释它。



我使用在Nib文件中存储更多或更少的复杂视图。为了无缝地插入故事板或其他nib文件中,我实现了一个NibLoadedView类,它基本上取代了来自initWithCoder的任何实例的复杂视图。换句话说,我可以在storyboard / IB中设置一个简单的占位符UIView的自定义类型,并在应用程序运行时将真实/复杂视图加载到它的位置。应用于该占位符视图的所有约束都应移动到真实视图。他们做了,至少所有约束表示占位符和其周围环境(其他视图)之间的关系。另一方面,尺寸约束存储在占位符视图中,并且如果不被传送到真实视图,则将丢失。这是我的问题,因为一旦我复制约束,它们应用如预期,但如果我引用其中一个作为IBOutlet,IBOutlet将变为nil(它指向约束相关的占位符视图,并且一旦删除所有其约束的视图,弱IBOutlet变为零;强IBOutlet不会改变任何东西,它将只保存错误的约束,而不是nil)。



解决方案是替换:

  [replacer addConstraint:constraintClone]; 

其中:

 code> memcpy((__ bridge void *)constraint,(__bridge const void *)constraintClone,malloc_size((__ bridge const void *)constraint)); 

[replacer addConstraint:constraint];

这会使用constraintClone覆盖约束在内存中的位置,即隐式更新IBOutlet,但是它被设置。

解决方案

IBOutlet :当故事板或笔尖被解码时,它为所有插座(动作,插座集合)调用 setValue:forKey:。如果由于某种原因要干扰此过程,请覆盖它,并在正确时自定义逻辑。



也许你想查看 awakeFromNib - 因为它是第一个方法,当nib完全解码和所有插座设置。说实话,我真的不明白目标,也许你可以多说一点。


Question:

Is there any way that I could set IBOutlet properties programmatically and in an automated way (i.e. without hard-coding the properties to be set)? Maybe there is some "IBOutlet setting" routine that I could intercept with my own specialized code?

Background:

The problem leading to the question above originates from the fact that "IBOutleted" size constraints (width and height) are not being set when running the following method (it's a method for replacing a "placeholder" view from IB with the real 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;
}

This method is called from UIView::awakeAfterUsingCoder:(NSCoder*)coder. It has been tested with a lot of different Nibs and has so far worked perfectly well. The problem now, though, is that I have to recreate those constraints that are strictly related to the view being replaced, i.e. width and height (constraints that are related to superview are seamlessly transferred). I have an IBOutlet for one such constraint, and it remains nil when going through this method.

To clarify, the code:

[replacer addConstraint:constraintClone];

works fine, the constraint is added and applied. However, the corresponding IBOutlet is not set (remains nil).

Update:

Sashas answer was correct, but the approach of intercepting IBOutlet assignments didn't solve the issue for me.

As Sasha pointed out, my background section is quite unclear. Thus I will make a quick attempt explain it in a different way.

I use to store more or less complex views in Nib files. In order to seamlessly insert those in storyboard or other nib files, I have implemented a "NibLoadedView" class, which basically replaces whatever instance comes from initWithCoder by the complex view. In other words, I can set the custom type of a simple placeholder UIView in storyboard/IB, and that will load the real/complex view in its place when the app runs. All constraints applied to that placeholder view are supposed to move to the real view. And they did, at least all constraints that expressed a relation between the placeholder and its surroundings (other views). Size constraints, on the other hand, are stored in the placeholder view, and will get lost if not transferred to the real view. And it was this transfer that I had problems with, because once I copied the constraints, they were applied as expected, but if I referenced one of them as an IBOutlet, that IBOutlet would turn nil (it was pointing to the constraint related to the placeholder view, and once that view with all of its constraints was removed, the weak IBOutlet turned nil; a strong IBOutlet would not change anything either, it would just hold the wrong constraint instead of being nil).

The solution was to replace:

[replacer addConstraint:constraintClone];

with:

memcpy((__bridge void*)constraint, (__bridge const void*)constraintClone, malloc_size((__bridge const void *)constraint));

[replacer addConstraint:constraint];

This overwrites the constraint at its place in memory with the constraintClone, that way implicitly updating the IBOutlet, wherever and however it is set.

解决方案

IBOutlets are set through KVC: when storyboard or nib is being decoded it calls setValue:forKey: for all outlets (actions, outlet collections). If, for some reason, you want to interfere with this process, override it and have your custom logic when key is right.

Perhaps you want to look into awakeFromNib - as it's the first method when nib was completely decoded and all outlets were set. To be honest, I do not really understand the goal, maybe you can explain it a bit more.

这篇关于拦截/以编程方式设置IBOutlet属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆