swift 具有私有(集合)需求的类绑定协议

ffscu2ro  于 2023-03-11  发布在  Swift
关注(0)|答案(1)|浏览(85)

我有一个用于NSManagedObjectsNameable协议。此协议在其自己的Swift包中声明,并打算由许多其他包导入,因此协议需要是公共的。我还需要维护协议方法,而不是使用具有继承的基类。我希望使用以下默认实现验证我的名称并抛出错误,但是似乎没有办法强制开发人员使用set(_ name: String)

import CoreData

public protocol Nameable: NSManagedObject {
    /// The name property of the entitiy
    /// - Warning: **don't** set this directly, use `set(_ name: String)` to ensure the name is validated
    ///
    /// - Note: This needs to be an `@NSManaged`
    var name: String { get set }
    
    static var defaultName: String { get }
    
    static var maxNameLength: Int { get }
    
    func set(_ name: String) throws
}
public extension Nameable {
    // TODO: Localize
    static var defaultName: String { "Untitled" }
    
    static var maxNameLength: Int { 128 }
    
    func set(_ name: String) throws {
        guard !name.isEmpty else { throw NameError.nameEmpty }
        guard name.count <= Self.maxNameLength else { throw NameError.nameTooLong }
        self.name = name
        try managedObjectContext?.save()
    }
}

public enum NameError: Error {
    case nameEmpty
    case nameTooLong
}

我想这样使用协议:

@objc(MyObject)
class MyObject: NSManagedObject, Nameable {
  @NSManaged public private(set) var name: String
}

但是由于协议是公共的,name也需要是可公开设置的。我提出的唯一解决方案是“软”(即警告注解,或类似@NSManaged var unsafeName: String { get set }的东西)。有什么方法可以实现编译器可以强制执行的预期结果吗?

m4pnthwp

m4pnthwp1#

您可以使用内部MutableNameable协议来细化您的可命名协议:

public protocol Nameable: NSManagedObject {
    var name: String { get }
    // ...
}

internal protocol MutableNameable: Nameable {
    var name: String { get set }
}

public extension Nameable {
    // ...
}

public extension MutableNameable {
    // ...
}

这将允许您:

@objc(MyObject)
class MyObject: NSManagedObject, MutableNameable {
  @NSManaged public internal(set) var name: String
}

MutableNameable也可以是私有的,但它会强制您在同一个文件中包含所有符合的类型。

相关问题