Собственная коллекция в swift: это правильный путь?

Я учусь быстро. Я хотел бы использовать пользовательский класс для цикла [возможность цикла 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", когда итерация достигает конца. Как справиться с ситуацией, когда мы используем оператор break внутри цикла for... in, как показано ниже:

    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 код прерывается после получения первого Элемента [в данном случае гостевого объекта]. Последующий цикл for будет начинаться с индекса 1 в коллекции, а не с 0. Есть ли способ обработать эту ситуацию прерывания, чтобы для каждого последующего цикла был установлен индекс 0?

Спасибо

Изменить: Кажется, проблема сброса "nextIndex" может быть исправлена ​​с помощью приведенного ниже кода [добавлен в класс GuestManager] для реализации метода generate()

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

2 ответа

Вы не должны хранить 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, На самом деле, самый простой способ выполнить все ваши требования - передать как можно больше логики SequenceType, Indexableи в конце концов (если вы хотите поддержать это) 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 также является хорошим кандидатом для структуры, если вам не требуется ссылочная семантика класса (все типы коллекций в стандартной библиотеке являются структурами).

Я думаю, что подход к подписке, который вы здесь пробуете, довольно запутанный. Лично я бы использовал функцию, чтобы сделать это для ясности.

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
  }
}
Другие вопросы по тегам