Objective c 使用通用方法对多个UIVIew类型进行子类化

Objective c 使用通用方法对多个UIVIew类型进行子类化,objective-c,swift,Objective C,Swift,在Objective-C/Swift中,如何使用常用方法对多个UIView进行子类化? 例如,子类化UILabel和UITextView,其中setText方法是常见的。我不想复制分别从UILabel和UITextView继承的两个独立类的代码。如果“self”是UILabel或UITextView,我需要一个单独使用setText方法的类。此外,我希望能够在故事板中为UILabels和UITextView设置此类 谢谢,你不能,至少不容易。在Swift中,可以声明具有setText()方法的协

在Objective-C/Swift中,如何使用常用方法对多个UIView进行子类化? 例如,子类化UILabel和UITextView,其中setText方法是常见的。我不想复制分别从UILabel和UITextView继承的两个独立类的代码。如果“self”是UILabel或UITextView,我需要一个单独使用setText方法的类。此外,我希望能够在故事板中为UILabels和UITextView设置此类


谢谢,

你不能,至少不容易。在Swift中,可以声明具有
setText()
方法的协议,然后使用实现该协议的版本将
UILabel
UITextView
子类化。但由于这两个都是
UIView
子类,因此Objective-C兼容,因此最好使用Objective-C方法
[NSObject respondsToSelector:
并传入
@selector(setText:)
,以确定对象是否符合该方法,如果符合,在objective-c中,您可以定义一个协议来声明现有方法或属性的公共子集

@protocol TextViewType <NSObject>
@property(nonatomic, strong) NSString *text;
@end

在Swift中,可以采用类似的方法:

import UIKit

protocol TextViewType {
    var text: String? { set get }
}

extension UILabel: TextViewType {}
extension UITextField : TextViewType {}
但这对我来说是行不通的

extension UITextView : TextViewType {}
这是因为不同的选项:

UILabel
UITextField
拥有此属性:

var text: String?
UITextView
拥有:

var text: String!
在这里,您可以使用协议继承和协议扩展:

protocol TextViewType {
    var theText: String? { set get }
}
这定义了我们以后要使用的接口

protocol OptionalTextViewType: TextViewType {
    var text: String? { set get }
}
TextViewType
的这种专门化定义了支持变量
var text:String?

protocol ImplicitUnwrappedOptionalTextViewType: TextViewType {
    var text: String! { set get }
}
TextViewType
的这种专门化定义了支持变量
var text:String

现在,我们可以为专业化添加协议扩展:

extension OptionalTextViewType {
    var theText: String? {
        set {
            self.text = newValue
        }
        get {
            return self.text
        }
    }
}

extension ImplicitUnwrappedOptionalTextViewType {
    var theText: String? {
        set {
            self.text = newValue ?? ""
        }
        get {
            return self.text ?? ""
        }
    }
}
现在我们需要定义与更具体协议的一致性:

extension UILabel: OptionalTextViewType { }
extension UITextField: OptionalTextViewType {}
extension UITextView : ImplicitUnwrappedOptionalTextViewType {}
我们可以像这样使用它:

var label: TextViewType = UILabel(frame: CGRect(x: 0, y: 0, width: 120, height: 20))
label.theText = "Label"

var textView: TextViewType = UITextView(frame: CGRect(x: 0, y: 0, width: 120, height: 20))
textView.theText = "TextView"

var textField: TextViewType = UITextField(frame: CGRect(x: 0, y: 0, width: 120, height: 20))
textField.theText = "TextField"

由于
label
textView
textField
被键入为
TextViewType
,只有
var-theText:String?
是公开的。

只是好奇,为什么要从2
UIView
子类继承?我正在执行一些必须在UILabel和UITextView对象中工作的任务。两者都使用相同的任务方法,例如“setText”,因此我不想重复代码而使用单个类。现在,我正在使用两个类,它们的代码和方法完全相同,一个是UILabel子类,另一个是UIExtView子类。我还需要能够在故事板中为UILabels和UIExtView设置这个类。我可以用你的解决方案吗?另外,使用您的方法,我需要为每个属性(UILabel和UITextView)使用setText方法复制所有行。我希望“self”像一个泛型,接受成为UILabel或UITextView而不使用属性。我可以用您的解决方案做到这一点吗?是:
@property(弱,非原子)IBOutlet id textView。为什么不想使用属性?它们只是语法上的糖衣方法?但也许你应该换一种方式:使用一个UIView子类,它接受一个对象,并为不同的对象进行不同的配置。在Swift中,这可能是通用的。最近,我创建了一个应用程序,这个应用程序更进一步。我引入了通用渲染器,而不是通用视图,它具有视图的通用属性和需要显示的对象的通用外围。这使我能够编写高度可重用的代码。这几乎和您一样,但如果我使用属性,在没有连接插座的情况下,我将无法在故事板中为UILabels和UITextView设置此类。连接插座对于像我这样的大型项目来说是一项艰巨的工作。我想将这个类设置为自定义类,这样应用起来会更快。好吧,如果这对你的项目来说真的是一个问题,我会说你没有正确使用编程提供给我们的工具箱。听起来好像您没有正确地重用代码。视图控制器有多少行代码,故事板中有多少行?如果我使用respondsToSelector,我需要检查它是否在我调用UILabel/UITextView方法的每一行上都有响应。我想让编译器明白self是UILabel或UITextView,因此不需要每次都进行此检查。
extension OptionalTextViewType {
    var theText: String? {
        set {
            self.text = newValue
        }
        get {
            return self.text
        }
    }
}

extension ImplicitUnwrappedOptionalTextViewType {
    var theText: String? {
        set {
            self.text = newValue ?? ""
        }
        get {
            return self.text ?? ""
        }
    }
}
extension UILabel: OptionalTextViewType { }
extension UITextField: OptionalTextViewType {}
extension UITextView : ImplicitUnwrappedOptionalTextViewType {}
var label: TextViewType = UILabel(frame: CGRect(x: 0, y: 0, width: 120, height: 20))
label.theText = "Label"

var textView: TextViewType = UITextView(frame: CGRect(x: 0, y: 0, width: 120, height: 20))
textView.theText = "TextView"

var textField: TextViewType = UITextField(frame: CGRect(x: 0, y: 0, width: 120, height: 20))
textField.theText = "TextField"