Выполнение закрытия при модификации массива - PullRequest
0 голосов
/ 12 апреля 2019

У меня есть следующий код:

class Note: NSObject {
}

struct Global {
    static var notes: Array<Note> = [] {
        didSet {
            print("hi")
        }
    }
}

Это печатает "привет", если я добавляю или удаляю элемент из массива или если я делаю

Global.notes = []

Существует ли способ печати ("привет") каждый раз, когда один из объектов Note в массиве изменяется?

Спасибо за ваши ответы

Ответы [ 3 ]

0 голосов
/ 12 апреля 2019

Swift Array - это struct, а struct s имеют тип значения, что означает, что они полностью изменяются при добавлении / удалении / замене элементов.Следовательно, когда вы добавляете / удаляете / заменяете Note, наблюдатель свойства didSet вызывается, так как массив снова set.

Однако, по вашему вопросу:

Есть ли способ печатать ("привет") каждый раз, когда один из объектов Note в массиве изменяется?

Этим я предполагаю, что вы хотите что-то сделать, когдадоступ к элементу в этом массиве и изменение внутреннего свойства.

Это было бы хорошо, если бы вы имели дело только с объектами типа значения, т. е. если бы ваш Note объект также был struct, тогдаизменение чего-либо внутри одного Note также привело бы к изменению массива.
Но ваш Note объект является классом, то есть ссылочным типом, и остается тем же объектом, даже если его внутренние элементы изменяются.Следовательно, ваш массив не нуждается в обновлении, и didSet не вызывается.
Чтение: типы значений и ссылок


KVO Solution:

Сейчас ... Так как ваш Note является подклассом NSObject, вы можете использовать концепцию KVO

Согласно следующему рабочему примеру, мы наблюдаем толькоодно свойство класса Note.
Если вы хотите наблюдать больше свойств, вам нужно будет наблюдать еще эти много ключей .

Пример:

class Note: NSObject {
    @objc dynamic var content = ""

    init(_ content: String) {
        self.content = content
    }
}

class NoteList {
    var notes: [Note] = [] {
        didSet {
            print("note list updated")

            //register & save observers for each note
            self.noteMessageKVOs = notes.map { (note) -> NSKeyValueObservation in
                return note.observe(\Note.content, options: [.new, .old]) { (note, value) in
                    print("note updated: \(value.oldValue) changed to \(value.newValue)")
                }
            }
        }
    }

    //array of observers
    var noteMessageKVOs = [NSKeyValueObservation]()
}

let list = NoteList()
list.notes.append(Note("A"))   //note list updated
list.notes.append(Note("B"))   //note list updated
list.notes[0].content = "X"    //note updated: A changed to X
list.notes[1].content = "Y"    //note updated: B changed to Y

Примечания:

  • NSObject требуется для KVO
  • @objc dynamic требуется, чтобы сделать свойство наблюдаемым
  • \Note.message - это путь к ключу
  • noteMessageKVOs требуется для поддержания наблюдателей в живых
0 голосов
/ 12 апреля 2019

Не меняя class на struct, у меня есть два основных способа справиться с этим.

Это объект, о котором вы спрашивали о

class Note: NSObject {
}

struct Global {
    static var notes: Array<Note> = [] {
        didSet {
            print("hi")
        }
    }
}

Обтекание Notesв оболочке, которая представляет собой структуру для получения поведения структуры.

extension Note {
    struct Wrapper { let note: Note }
}

extension Global {
    static var wrappedNotes = [Note.Wrapper]() {
        didSet {
            print("hi")
        }
    }
}

Global.wrappedNotes.append(Note.Wrapper(note: Note()))
Global.wrappedNotes[0] = Note.Wrapper(note: Note())
Global.wrappedNotes.remove(at: 0)

Другой способ - создать менеджер заметок для переноса доступа к массиву.

class NoteManager {

    subscript(index: Int) -> Note {
        get {
            return values[index]
        }
        set {
            defer { onUpdate() }
            values[index] = newValue
        }
    }

    func append(_ newNote: Note) {
        defer { onUpdate() }
        values.append(newNote)
    }

    func remove(at index: Int) -> Note {
        defer { onUpdate() }
        return values.remove(at: index)
    }

    private func onUpdate() {
        print("hi")
    }

    private var values = [Note]()

}

extension Global {
    static var managedNotes = NoteManager()
}

Global.managedNotes.append(Note())
Global.managedNotes[0] = Note()
Global.managedNotes.remove(at: 0)
0 голосов
/ 12 апреля 2019

Согласно комментарию @staticVoidMan, если вы сделаете свою модель структурой, а не классом, тогда наблюдатель свойства didSet будет работать и для собственных свойств вашей Note модели.

import Foundation

struct Note {
    var name: String
}

struct Global {
    static var notes: Array<Note> = [] {
        didSet {
                print("hi")            
        }
    }
}

Global.notes.append(Note(name: "Shubham"))
Global.notes.append(Note(name: "Bakshi"))
Global.notes[0].name = "Boxy"

На консоли будет напечатано следующее:

hi

hi

hi

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...