【问题标题】:Override swift protocol property to optional将 swift 协议属性覆盖为可选
【发布时间】:2018-12-31 00:29:52
【问题描述】:

我正在使用这个库,https://github.com/gcharita/XMLMapper

它包含协议,

public protocol XMLBaseMappable {
    var nodeName: String! { get set }
}

我想将这个 nodeName 设为可选,用于实现它的结构/类,例如

public protocol CustomXMLBaseMappable {
    var nodeName: String? { return "default" }

    //I don't want struct/classes using it, implements `nodeName`.
}

任何建议都会有所帮助。

【问题讨论】:

  • No 你不能改变协议的定义。
  • 您有这样做的理由吗?我问这个是因为这个属性的实现对于库的正确运行非常重要。
  • @gcharita 就我而言,我必须使用 Pod 对第三方库的类/结构进行编码。由于扩展不能包含存储属性,nodeName 给我带来了麻烦。救命!!

标签: ios swift xml codable xmlmapper


【解决方案1】:

您无法覆盖原始协议,但您可以手动更改它:

@objc protocol XMLBaseMappable {
    @objc optional var nodeName: String! { get set }
}

或保持原样,然后创建您的自定义协议

@objc protocol CustomXMLBaseMappable {
    @objc optional var nodeName: String! { get set }
}

【讨论】:

    【解决方案2】:

    XMLBaseMappable 协议中此属性的存在对于整个库的正常运行至关重要。

    话虽如此,您不能在结构和类中省略此属性的实现,但您可以将其“隐藏”在超类中。使用这个:

    class BasicXMLMappable: XMLMappable {
        var nodeName: String!
    
        required init(map: XMLMap) {
    
        }
    
        func mapping(map: XMLMap) {
    
        }
    }
    

    您可以拥有扩展 BasicXMLMappableXMLMappable 对象,它们不必实现 nodeName 属性:

    class TestBasicXMLMappable: BasicXMLMappable {
    
        // Your custom properties
    
        required init(map: XMLMap) {
            super.init(map: map)
        }
    
        override func mapping(map: XMLMap) {
            // Map your custom properties
        }
    }
    

    编辑: 从 1.5.1 版开始,您可以使用 XMLStaticMappable 在扩展中实现 XMLMapper。例如:

    class CustomClass {
        var property: String?
    }
    
    extension CustomClass: XMLStaticMappable {
        var nodeName: String! {
            get {
                return "default"
            }
            set(newValue) {
    
            }
        }
    
        static func objectForMapping(map: XMLMap) -> XMLBaseMappable? {
            // Initialize CustomClass somehow
            return CustomClass()
        }
    
        func mapping(map: XMLMap) {
            property <- map["property"]
        }
    }
    

    希望这会有所帮助。

    【讨论】:

    • 我想到了同样的实现,你所建议的。但就我而言,我必须 Encode 第三方库的类/结构,这些库使用 Pod。由于扩展不能包含存储属性,nodeName 给我带来了麻烦。救命!!
    • 有一个解决方法,但是你将在实现XMLMappable 协议指定的required init(map:) 时遇到问题,因为扩展也无法做到这一点。 (你不能直接实现XMLBaseMappable)我现在正在发布一个新版本的 pod,它添加了缺少的XMLStaticMappable 协议,我会更新我的帖子。
    • 我正在调查您所做的提交。一个建议,而不是将nodeName 添加到协议中并使其变得复杂,您为什么不遵循使用默认参数的方法,例如默认nodeName 将是root &如果用户想要更改它,他可以这样做, 在像toXMLString(with rootKey: String = "default-root") 这样的可映射方法中。这种方法将简化其可用性。
    • 谢谢。请原谅我坚持,但您不需要子类化所有第三方类。但是,您需要为它们中的每一个创建一个扩展。您可能已经这样做来实现XMLBaseMappable 协议的mapping(map:) 功能。如果是这种情况,您只需在这些扩展中添加我的答案的var nodeName: String! { get { return "default" } set(newValue) { } } 部分。
    • 宾果游戏!!这很棒。非常感谢,伙计! ?
    猜你喜欢
    • 2023-04-06
    • 2015-10-04
    • 1970-01-01
    • 2018-09-04
    • 1970-01-01
    • 2018-07-15
    • 2018-07-25
    • 1970-01-01
    • 2017-05-11
    相关资源
    最近更新 更多