我有一个
Nameable
协议,打算在 NSManagedObjects
上使用。该协议在其自己的 Swift 包中声明,并打算由许多其他包导入,因此该协议需要公开。我还需要维护协议方法,而不是使用继承的基类。我想使用下面的默认实现来验证我的名字并抛出错误,但似乎没有办法强制开发人员使用 set(_ name: String)
.
import CoreData
public protocol Nameable: NSManagedObject {
/// The name property of the entity
/// - 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
}
但由于协议是公开的,名称也需要公开设置。我想出的唯一解决方案是“软”(即警告评论,或类似
@NSManaged var unsafeName: String { get set }
的东西)。有什么方法可以实现编译器可以强制执行的预期结果吗?
你可以有一个内部的
MutableNameable
协议来改进你的 Nameable 协议:
public protocol Nameable: NSManagedObject {
var name: String { get }
// ...
}
public extension Nameable {
// ...
}
internal protocol MutableNameable: Nameable {
var name: String { get set }
}
extension MutableNameable {
// ...
}
这会让你拥有:
@objc(MyObject)
class MyObject: NSManagedObject, MutableNameable {
@NSManaged public internal(set) var name: String
}
MutableNameable
也可以是私有的,但它会强制您在同一个文件中拥有所有符合类型。