- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
在 Swift 3 中,我希望能够创建一个允许我添加元素并使用 for element in
进行迭代的协议(protocol)。该协议(protocol)应该适用于 NSMutableSet
和 NSMutableOrderedSet
(因为它们不是从同一个类继承的)。
我知道 NSMutableSet
和 NSMutableOrderedSet
不从同一个类继承是有充分理由的,解释了 here和 here .
但我想创建一个协议(protocol),它只使用 NSMutableSet
(和 NSMutableOrderedSet
)中所有方法的一小部分。
我已经让 add
开始工作了,就像这样:
protocol MutableSet {
func add(_ element: Any)
}
extension NSMutableSet: MutableSet {}
extension NSMutableOrderedSet: MutableSet {}
let one: NSString = "one"
let two: NSString = "two"
// Works if created with `NSMutableSet`
let mutableSet: MutableSet = NSMutableSet()
mutableSet.add(one)
mutableSet.add(two)
for element in mutableSet as! NSMutableSet {
print(element)
}
/*
This prints:
one
two
*/
// Also works if creating `NSMutableOrderedSet` instance
let mutableOrderedSet: MutableSet = NSMutableOrderedSet()
mutableOrderedSet.add(one)
mutableOrderedSet.add(two)
for element in mutableOrderedSet as! NSMutableOrderedSet {
print(element)
}
/*
This prints:
one
two
*/
但是我真的很想能够通过使用以下元素来迭代元素:
for element in mutableSet {
print(element)
}
我正在尝试使 protocol MutableSet
符合 Sequence
协议(protocol),类似这样,但它不起作用:
protocol MutableSet: Sequence {
func add(_ element: Any)
}
extension NSMutableSet: MutableSet {
typealias Iterator = NSFastEnumerationIterator
typealias Element = NSObject // I dont know what to write here
typealias SubSequence = Slice<Set<NSObject>> // Neither here....
}
let one: NSString = "one"
let two: NSString = "two"
let mutableSet: MutableSet = NSMutableSet() // Compile Error: Protocol `MutableSet` can only be used as a generic constraint because it has Self or associated type requirements
mutableSet.add(one)
mutableSet.add(two)
for element in mutableSet { // Compile Error: Using `MutableSet` as a concrete type conforming to protocol `Sequence` is not supported
print(element)
}
是否可以使我的协议(protocol)符合Sequence
?我应该怎么做?我已经尝试了 typealias
和 associatedtype
的 Element
、Iterator
等的各种组合。我也尝试了 this answer它对我不起作用。
编辑 2:在编辑 1 中回答我自己的问题
我得到了 var count: Int { get }
来使用这个解决方案,虽然不确定它是否是最好的...也很高兴不必实现 var elements: [Any] { get }
在 NSMutableSet
和 NSMutableOrderedSet
的扩展中,但我想这是不可避免的?
protocol MutableSet: Sequence {
subscript(position: Int) -> Any { get }
func add(_ element: Any)
var count: Int { get }
var elements: [Any] { get }
}
extension MutableSet {
subscript(position: Int) -> Any {
return elements[position]
}
}
extension NSMutableSet: MutableSet {
var elements: [Any] {
return allObjects
}
}
extension NSMutableOrderedSet: MutableSet {
var elements: [Any] {
return array
}
}
struct AnyMutableSet<Element>: MutableSet {
private let _add: (Any) -> ()
private let _makeIterator: () -> AnyIterator<Element>
private var _getElements: () -> [Any]
private var _getCount: () -> Int
func add(_ element: Any) { _add(element) }
func makeIterator() -> AnyIterator<Element> { return _makeIterator() }
var count: Int { return _getCount() }
var elements: [Any] { return _getElements() }
init<MS: MutableSet>(_ ms: MS) where MS.Iterator.Element == Element {
_add = ms.add
_makeIterator = { AnyIterator(ms.makeIterator()) }
_getElements = { ms.elements }
_getCount = { ms.count }
}
}
let one: NSString = "one"
let two: NSString = "two"
let mutableSet: AnyMutableSet<Any>
let someCondition = true
if someCondition {
mutableSet = AnyMutableSet(NSMutableSet())
} else {
mutableSet = AnyMutableSet(NSMutableOrderedSet())
}
mutableSet.add(one)
mutableSet.add(two)
for i in 0..<mutableSet.count {
print("Element[\(i)] == \(mutableSet[i])")
}
// Prints:
// Element[0] == one
// Element[1] == two
编辑 1:跟进问题使用@rob-napier 的出色答案和type erasure
技术,我扩展了protocol MutableSet
以具有count
和下标
能力,但是我只能使用丑陋的 func
(名为 getCount
)而不是 var
来做到这一点。这是我正在使用的:
protocol MutableSet: Sequence {
subscript(position: Int) -> Any { get }
func getCount() -> Int
func add(_ element: Any)
func getElements() -> [Any]
}
extension MutableSet {
subscript(position: Int) -> Any {
return getElements()[position]
}
}
extension NSMutableSet: MutableSet {
func getCount() -> Int {
return count
}
func getElements() -> [Any] {
return allObjects
}
}
extension NSMutableOrderedSet: MutableSet {
func getElements() -> [Any] {
return array
}
func getCount() -> Int {
return count
}
}
struct AnyMutableSet<Element>: MutableSet {
private var _getCount: () -> Int
private var _getElements: () -> [Any]
private let _add: (Any) -> ()
private let _makeIterator: () -> AnyIterator<Element>
func getElements() -> [Any] { return _getElements() }
func add(_ element: Any) { _add(element) }
func makeIterator() -> AnyIterator<Element> { return _makeIterator() }
func getCount() -> Int { return _getCount() }
init<MS: MutableSet>(_ ms: MS) where MS.Iterator.Element == Element {
_add = ms.add
_makeIterator = { AnyIterator(ms.makeIterator()) }
_getElements = ms.getElements
_getCount = ms.getCount
}
}
let one: NSString = "one"
let two: NSString = "two"
let mutableSet: AnyMutableSet<Any>
let someCondition = true
if someCondition {
mutableSet = AnyMutableSet(NSMutableSet())
} else {
mutableSet = AnyMutableSet(NSMutableOrderedSet())
}
mutableSet.add(one)
mutableSet.add(two)
for i in 0..<mutableSet.getCount() {
print("Element[\(i)] == \(mutableSet[i])")
}
// Prints:
// Element[0] == one
// Element[1] == two
我怎样才能让它与协议(protocol)中的 var count: Int { get }
和 var elements: [Any]
而不是函数一起工作?
最佳答案
几乎每个“我如何使用 PAT(具有关联类型的协议(protocol))...”的答案都是“将其放入一个盒子中”。那个盒子是type eraser .在您的情况下,您需要一个 AnyMutableSet
。
import Foundation
// Start with your protocol
protocol MutableSet: Sequence {
func add(_ element: Any)
}
// Now say that NSMutableSet is one. There is no step two here. Everything can be inferred.
extension NSMutableSet: MutableSet {}
// Create a type eraser for MutableSet. Note that I've gone ahead and made it generic.
// You could lock it down to just Any, but why limit yourself
struct AnyMutableSet<Element>: MutableSet {
private let _add: (Any) -> ()
func add(_ element: Any) { _add(element) }
private let _makeIterator: () -> AnyIterator<Element>
func makeIterator() -> AnyIterator<Element> { return _makeIterator() }
init<MS: MutableSet>(_ ms: MS) where MS.Iterator.Element == Element {
_add = ms.add
_makeIterator = { AnyIterator(ms.makeIterator()) }
}
}
// Now we can use it
let one: NSString = "one"
let two: NSString = "two"
// Wrap it in an AnyMutableSet
let mutableSet = AnyMutableSet(NSMutableSet())
mutableSet.add(one)
mutableSet.add(two)
for element in mutableSet {
print(element)
}
原则上还有另一种方法,即直接使用现有的“允许我添加元素并通过使用 for element in 进行迭代的协议(protocol)”。这是两个协议(protocol):SetAlgebra & Sequence
。在实践中,我发现让 NSMutableSet
或 NSOrderedSet
符合 SetAlgebra
是......烦人的。 NSMutableSet
在 Swift 3 中基本上被破坏了。它在不同的地方接受 Any
,但被定义为超过 AnyHashable
。基本代码不起作用:
let s = NSMutableSet()
let t = NSMutableSet()
s.union(t)
但那是因为你不应该使用 NSMutableSet
。它会自动桥接到 Set
,而您应该改用 Set
。而且 Set
确实符合 SetAlgebra & Sequence
,所以这很好。
但随后我们来到了NSOrderedSet
。这很难融入 Swift(这就是 Foundation 团队推迟这么久的原因)。在我看来,这真是一团糟,每次我尝试使用它时,我都会把它拔出来,因为它不能很好地与任何东西搭配。 (尝试使用 NSFetchedResultsController 在“有序关系”中使用顺序。)坦率地说,您最好的选择是将其包装在一个结构中并使该结构符合 SetAlgebra & Sequence
。
但如果你不这样做(或者只是摆脱有序集,就像我最终总是这样做的那样),那么类型删除几乎是你唯一的工具。
关于ios - 将 NSMutableSet 和 NSMutableOrderedSet 桥接在一起的协议(protocol),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39593295/
使用 NSMutableOrderedSet,我遇到了意外行为。 我在索引0处设置了一个对象,在接下来的调用中,我读出了索引0处的对象,我返回的指针怎么和我刚刚插入的指针不一样呢? - (void)s
我有一个 NSMutableOrderedSet,它看起来像这样: self.tableViewData = [[NSMutableOrderedSet alloc ]initWithObjects:
我有以下陈述 [[myListSet objectAtIndex:sender.tag] setValue:@"1" forKey:@"STATUS"]; 其中 myListSet 定义为 NSMut
我无法理解为什么我的有序集只保存了 1 个条目。 我的代码如下: let newInovice = NSEntityDescription.insertNewObjectForEntityForNam
array = [NSMutableArray arrayWithArray:[set allObjects]]; 这与 NSSet 一起工作,但如何让它与 NSMutableOrderedSet 一
我有这个for循环,p是一个NSManagedObject,fathers是一个对多关系,所以我需要将 NSMutableOrderedSet 转换为 [Family] 但它不起作用,为什么? for
在立即假设这是重复之前,请继续阅读。 我想对一个大的 NSMutableOrderedSet 进行排序以高效的方式。 我知道如何对 NSMutableOrderedSet 进行排序使用 NSSortC
我正在尝试实现一个通用的 Mutable Ordered Set 类型,它需要符合许多协议(protocol)才能与 Swift 中的 Array 和 Set 行为相同。首先要实现泛型类型元素需要符合
在 Swift 3 中,我希望能够创建一个允许我添加元素并使用 for element in 进行迭代的协议(protocol)。该协议(protocol)应该适用于 NSMutableSet 和 N
我是一名优秀的程序员,十分优秀!