【问题标题】:Custom collection in swift: is it a right way?swift中的自定义集合:这是正确的方法吗?
【发布时间】:2016-05-05 13:35:12
【问题描述】:

我学得很快。我想使用一个自定义类来循环[能够 for...in 循环],如 Array。以下是到目前为止我已经尝试过的给定示例代码。有问题的类是“GuestManager”,它持有客人的私人集合 [Guest 类的对象]

import Foundation

class Guest{
    var guestId: String
    var guestName: String

    init(gId: String, name: String){
        self.guestId = gId
        self.guestName = name
    }
}

class GuestManager: GeneratorType, SequenceType{
    private var guests = [Guest]?()
    private var nextIndex: Int

    init(guests: [Guest]){
        self.guests = guests
        self.nextIndex = 0
    }

    func next() -> Guest? {
        if  self.nextIndex > (self.guests?.count)! - 1 {
            self.nextIndex = 0
            return nil
        }
        let currentGuest = self.guests![self.nextIndex]
        self.nextIndex += 1
        return currentGuest
    }
    subscript(aGuestId gID: String) -> Guest{
        return (self.guests?.filter({$0.guestId == gID}).first)!
    }
}

我不想创建符合 GeneratorType 和 SequenceType 协议的单独类。相反,我创建了一个符合这两种协议的类。

以下是我的一些问题:

  1. 我想知道这是否是拥有自定义集合类型的正确方法?

  2. 我们可以使用下标作为一种基于属性执行搜索的方法,例如上面示例代码中的“subscript(aGuestId gID: String)”吗?

  3. 从上面示例代码中的 next() 函数实现代码中可以清楚地看出,当迭代结束时重置“nextIndex”。如何处理我们在 for...in 循环中使用 break 语句的情况,如下所示:

    for aGuest in guestManager{//guestManager an instance of GuestManager class instantiated with several guest objects
        print(aGuest.guestName)
    }
    for aG in guestManager{
        print(aG.guestId)
        break
    }
    

    在第二个 for 循环中,代码在获取第一个 Element [在这种情况下为来宾对象] 后中断。随后的 for 循环将从集合中的索引 1 开始,而不是从 0 开始。无论如何要处理这种中断情况,以便对于每个后续的 for 循环,索引始终设置为 0?

谢谢

编辑:似乎“nextIndex”重置问题可以用下面的代码 [添加到 GuestManager 类中] 用于 generate() 方法实现

func generate() -> Self {
        self.nextIndex = 0
        return self
    }

【问题讨论】:

    标签: ios swift2.2 custom-collection


    【解决方案1】:

    您不应该将nextIndex 存储在类中。您可以在 generate 方法中使用局部变量,然后让该变量被传递给在该方法中创建的生成器的闭包中捕获。这就是你需要采用SequenceType

    class GuestManager: SequenceType{
        private var guests: [Guest]
    
        init(guests: [Guest]) {
            self.guests = guests
        }
    
        func generate() -> AnyGenerator<Guest> {
            var nextIndex = 0
            return AnyGenerator {
                guard nextIndex < self.guests.endIndex else {
                    return nil
                }
                let next = self.guests[nextIndex]
                nextIndex += 1
                return next
            }
        }
    }
    

    对于下标,你应该采用Indexable。实际上,满足您所有要求的最简单方法是将SequenceTypeIndexable 以及最终(如果您想支持它)CollectionType 的尽可能多的逻辑传递给您的阵列,该阵列已经具有这些功能.我会这样写:

    class GuestManager {
        private var guests: [Guest]
    
        init(guests: [Guest]){
            self.guests = guests
        }
    }
    
    extension GuestManager: SequenceType {
        typealias Generator = IndexingGenerator<GuestManager>
    
        func generate() -> Generator {
            return IndexingGenerator(self)
        }
    }
    
    extension GuestManager: Indexable {
        var startIndex: Int {
            return guests.startIndex
        }
    
        var endIndex: Int {
            return guests.endIndex
        }
    
        subscript(position: Int) -> Guest {
            return guests[position]
        }
    }
    

    更多观察:

    1. 您的guests 属性不应是可选的。它使代码更复杂,没有任何好处。我在我的代码中相应地更改了它。
    2. 您的Guest 类可能应该是一个值类型(一个结构)。 GuestManager 也是结构体的理想候选者,除非您需要类的引用语义(标准库中的所有集合类型都是结构体)。

    【讨论】:

      【解决方案2】:

      我认为您在这里尝试的下标方法有点复杂。就个人而言,为了清楚起见,我会使用一个函数来执行此操作。

      guestManager[aGuestId: guestId]
      
      guestManager.guestWithID(guestId) 
      

      所以从风格上讲,我可能会选择这样的东西

      import Foundation
      
      class Guest{
        var guestId: String
        var guestName: String
      
        init(guestId: String, guestName: String){
          self.guestId = guestId
          self.guestName = guestName
        }
      }
      
      class GuestManager: GeneratorType, SequenceType{
        private var guests: [Guest]
        private var nextIndex = 0
      
        init(guests: [Guest]){
          self.guests = guests
        }
      
        func next() -> Guest? {
          guard guests.count < nextIndex else {
            nextIndex = 0
            return nil
          }
      
          let currentGuest = guests[nextIndex]
          nextIndex += 1
          return currentGuest
        }
      
        func guestWithID(id: String) -> Guest? {
          return guests.filter{$0.guestId == id}.first ?? nil
        }
      }
      

      【讨论】:

      • 通过下标,我想让 GuestManager 可以通过某些关键属性进行搜索,尽管我们也可以创建函数,但我正在寻找一种更简洁的搜索方式。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-24
      • 1970-01-01
      相关资源
      最近更新 更多