子类/扩展 UIView 以便所有其他视图(UIImageView、UITextField ...)在创建时继承

Posted

技术标签:

【中文标题】子类/扩展 UIView 以便所有其他视图(UIImageView、UITextField ...)在创建时继承【英文标题】:Subclass/Extend UIView so all other Views (UIImageView, UITextField ...) inherit upon creation 【发布时间】:2017-06-26 00:01:18 【问题描述】:

当我想向 UIView 添加功能以便我的应用程序中的所有视图都获得这些功能时,建议的方法是什么?事实上,我也需要添加一些存储的属性,所以扩展是不可能的。由于我需要处理 Textfields、ImageViews、Views(以及谁知道还会发生什么),我不想为每个子类添加该功能,所以目标是创建 UIView 的子类和我的所有控件(如果可能的话)开箱即用地获取该功能。

使用扩展会很容易,但正如我所说,我也需要存储一些东西,那么这个目标可以通过子类实现吗?或者什么是正确的方法(也许还有第三种选择)

谢谢

【问题讨论】:

嘿,我在 2-3 年前看到了一个类似的问题,并且得到了回答 -> 请更好地查看 SO.. 我认为关键是使用这个 developer.apple.com/documentation/objectivec/… 方法......但是你应该小心这一点,因为例如“UITextField”超级是“UIControl”——它似乎也被弃用了 是的,像这样的 smt 将是完美的,但显然扼杀了这个选项。我会搜索是否有类似的smt for swift 在运行时使用objective-c中的关联属性有一种令人讨厌的方法,但是很糟糕。最好谈谈为什么您认为需要向这些视图添加属性并考虑一些替代方案。作为一般原则,一堆视图用于呈现和编辑模型,通常是我们尝试通过属性丰富的模型。 主要是关于转型。我希望我的所有视图在特殊环境中(意味着当父级特殊时)具有所有转换功能(拖动、旋转、缩放......)。而且我认为在 UIView 中这样做会很好,而不是特别针对每个 View(bcz 代码实际上与 UIImageView、UITextView 有 90% 相似)。因此我还需要存储一些转换信息。但似乎我必须为我想要支持的每种视图类型都这样做...... 【参考方案1】:

为什么不在协议扩展中定义协议并提供默认实现,然后让 UIView 符合该协议?这是一个例子:

protocol MyProto 
    var someVar: Bool  get set 
    func someFunc() -> Void


extension MyProto 
    var someVar: Bool 
        get 
            // provide default implementation
            return true
        
        set 

        
    

    func someFunc() -> Void 
        // provide common implementation
    


extension UIView: MyProto 

您还可以使用where 子句来约束类型的默认行为。

extension MyProto where Self: UIControl 
    var someVar: Bool 
        get 
            return isUserInteractionEnabled
        
        set 
            isUserInteractionEnabled = newValue
        
    


extension MyProto where Self: UITextField 
    var someVar: Bool 
        get 
            return isFirstResponder
        
        set 
            newValue ? becomeFirstResponder() : resignFirstResponder()
        
    

【讨论】:

Bcz 这部分在扩展“var someVar: Bool”中无效 怎么无效? 但我仍然需要在“someVar”中存储一些值。我也需要一个二传手,然后你得到错误 只需在协议定义中设置属性 Settable 即可。我刚刚更新了我的答案以适合您的用例。 也许我没有看到它,但我仍然不明白(尽管我真的很惊讶你可以用 swift 协议做什么)。但要指出的是,我有一个属性来存储视图的最后位置(所以最后一次拖动视图),我将在哪里/以及如何在您的设置中存储该值?【参考方案2】:

TLDR;您不能这样做,并且您需要将每个要引入新属性的 UI 元素子类化。

您不能这样做(无法访问源代码),因为您将通过在 UIView 及其子类之间注入您自己的类来有效地更改类继承树。

考虑如果一种语言允许这样做的含义:

Class A 定义一个属性,a Class Binherits 来自Class A 并定义了一个属性b,这很好,因为Class A 没有这个属性。 Class C 继承自 Class B 并具有 ab 属性。

现在,如果你可以“注入”Class A1 以某种方式“低于”Class A,会发生什么?

Class A1 可以定义一个属性b,这很好,因为Class A 没有这个属性 Class B 现在有一个问题,因为 its b 与超类 b 发生冲突 Class C 具有属性 b 的多重继承钻石问题

当然,您只打算添加不冲突的属性(尽管您不知道这一点,因为您不知道所有可能的子类实现)并且不需要子类来访问您的属性,所以多重继承 不是问题,但如果这样的功能是一种语言,则需要解决这些潜在问题,因为您不能依赖与您有相同意图的每个人。

【讨论】:

我其实想更深入地了解这一点,也写了一些东西,但由于不可能,我决定删除它,因为讨论它会浪费时间:) 谢谢你的回答和澄清

以上是关于子类/扩展 UIView 以便所有其他视图(UIImageView、UITextField ...)在创建时继承的主要内容,如果未能解决你的问题,请参考以下文章

UIView bringSubviewToFront: *不*将视图带到前面

在视图控制器中访问 UIView 子类

iOS UIView 子类将透明文本绘制到背景

在 UIView 子类的子视图内绘图

使用动态大小的子视图调整 UIView 子类的大小

UIView:从自定义 XIB 加载导致崩溃