From b95eda6507cd66942e8a90ac4f2e8b90cfe5061c Mon Sep 17 00:00:00 2001 From: Craig Reyenga <craig.reyenga@gmail.com> Date: Fri, 14 Feb 2025 21:41:50 -0500 Subject: [PATCH] Improve Observable by adding a function that calls out to each observer and handles the case of disappearing observers --- .../Extensions/Foundation/Observable.swift | 41 +++++--- .../MediaLibraryModel/AlbumModel.swift | 16 +-- .../MediaLibraryModel/ArtistModel.swift | 16 +-- .../MediaLibraryModel/CollectionModel.swift | 20 ++-- .../MediaLibraryModel/GenreModel.swift | 16 +-- .../MediaLibraryModel/HistoryModel.swift | 8 +- .../MediaGroupViewModel.swift | 28 +++--- .../MediaLibraryModel/PlaylistModel.swift | 24 ++--- .../MediaLibraryModel/ShowEpisodeModel.swift | 4 +- .../MediaLibraryModel/TrackModel.swift | 16 +-- .../MediaLibraryModel/VideoModel.swift | 20 ++-- .../Media Library/MediaLibraryService.swift | 97 +++++++++---------- 12 files changed, 159 insertions(+), 147 deletions(-) diff --git a/Sources/Extensions/Foundation/Observable.swift b/Sources/Extensions/Foundation/Observable.swift index 069486d49..3df5521d1 100644 --- a/Sources/Extensions/Foundation/Observable.swift +++ b/Sources/Extensions/Foundation/Observable.swift @@ -6,25 +6,14 @@ * Copyright © 2019 Videolabs * * Authors: Soomin Lee <bubu # mikan.io> + * Craig Reyenga <craig.reyenga # gmail.com> * * Refer to the COPYING file of the official project for license. *****************************************************************************/ -// MARK: - Observer - -// Since weak is a property assigned to anything that is of class type and not struct -// you have to explicitly constraint your generic parameter to be of class type -class Observer<T: AnyObject> { - weak var observer: T? - - init(_ observer: T) { - self.observer = observer - } -} - class Observable<T: AnyObject> { // Using ObjectIdentifier to avoid duplication and facilitate identification of observing object - private(set) var observers = [ObjectIdentifier: Observer<T>]() + private var observers = [ObjectIdentifier: Observer<T>]() func addObserver(_ observer: T) { let identifier = ObjectIdentifier(observer) @@ -35,4 +24,30 @@ class Observable<T: AnyObject> { let identifier = ObjectIdentifier(observer) observers.removeValue(forKey: identifier) } + + /// Notify observers by executing the provided action upon each. + /// - Parameter action: the action to execute upon each observer + func notifyObservers(action: (T) -> Void) { + // Copy keys before iterating so we can detect observers that have been + // removed as a side effect of calling out to a previous observer. + let keys = Array(observers.keys) + + for k in keys { + guard let observer = observers[k]?.observer else { continue } + action(observer) + } + } + +} + +// MARK: - Observer + +// Since weak is a property assigned to anything that is of class type and not struct +// you have to explicitly constraint your generic parameter to be of class type +fileprivate class Observer<T: AnyObject> { + weak var observer: T? + + init(_ observer: T) { + self.observer = observer + } } diff --git a/Sources/Media Library/MediaLibraryModel/AlbumModel.swift b/Sources/Media Library/MediaLibraryModel/AlbumModel.swift index 9307edb2e..a2ccfa9f2 100644 --- a/Sources/Media Library/MediaLibraryModel/AlbumModel.swift +++ b/Sources/Media Library/MediaLibraryModel/AlbumModel.swift @@ -87,8 +87,8 @@ extension AlbumModel { } sortModel.currentSort = criteria sortModel.desc = desc - observable.observers.forEach() { - $0.value.observer?.mediaLibraryBaseModelReloadView() + observable.notifyObservers { + $0.mediaLibraryBaseModelReloadView() } } } @@ -112,8 +112,8 @@ extension VLCMLAlbum: SearchableMLModel { extension AlbumModel: MediaLibraryObserver { func medialibrary(_ medialibrary: MediaLibraryService, didAddAlbums albums: [VLCMLAlbum]) { albums.forEach({ append($0) }) - observable.observers.forEach() { - $0.value.observer?.mediaLibraryBaseModelReloadView() + observable.notifyObservers { + $0.mediaLibraryBaseModelReloadView() } } @@ -134,8 +134,8 @@ extension AlbumModel: MediaLibraryObserver { fileArrayLock.lock() files = swapModels(with: albums) - observable.observers.forEach() { - $0.value.observer?.mediaLibraryBaseModelReloadView() + observable.notifyObservers { + $0.mediaLibraryBaseModelReloadView() } } @@ -147,8 +147,8 @@ extension AlbumModel: MediaLibraryObserver { files.removeAll { albumsIds.contains(NSNumber(value: $0.identifier())) } - observable.observers.forEach() { - $0.value.observer?.mediaLibraryBaseModelReloadView() + observable.notifyObservers { + $0.mediaLibraryBaseModelReloadView() } } diff --git a/Sources/Media Library/MediaLibraryModel/ArtistModel.swift b/Sources/Media Library/MediaLibraryModel/ArtistModel.swift index fdb169ad0..4934fab6e 100644 --- a/Sources/Media Library/MediaLibraryModel/ArtistModel.swift +++ b/Sources/Media Library/MediaLibraryModel/ArtistModel.swift @@ -94,8 +94,8 @@ extension ArtistModel { medialibrary.artists(sortingCriteria: criteria, desc: desc, listAll: true) sortModel.currentSort = criteria sortModel.desc = desc - observable.observers.forEach() { - $0.value.observer?.mediaLibraryBaseModelReloadView() + observable.notifyObservers { + $0.mediaLibraryBaseModelReloadView() } } } @@ -112,8 +112,8 @@ extension VLCMLArtist: SearchableMLModel { extension ArtistModel: MediaLibraryObserver { func medialibrary(_ medialibrary: MediaLibraryService, didAddArtists artists: [VLCMLArtist]) { artists.forEach({ append($0) }) - observable.observers.forEach() { - $0.value.observer?.mediaLibraryBaseModelReloadView() + observable.notifyObservers { + $0.mediaLibraryBaseModelReloadView() } } @@ -137,8 +137,8 @@ extension ArtistModel: MediaLibraryObserver { files = swapModels(with: artists) addNewArtists(artists) filterGeneratedArtists() - observable.observers.forEach() { - $0.value.observer?.mediaLibraryBaseModelReloadView() + observable.notifyObservers { + $0.mediaLibraryBaseModelReloadView() } } @@ -150,8 +150,8 @@ extension ArtistModel: MediaLibraryObserver { files.removeAll { artistsIds.contains(NSNumber(value: $0.identifier())) } - observable.observers.forEach() { - $0.value.observer?.mediaLibraryBaseModelReloadView() + observable.notifyObservers { + $0.mediaLibraryBaseModelReloadView() } } diff --git a/Sources/Media Library/MediaLibraryModel/CollectionModel.swift b/Sources/Media Library/MediaLibraryModel/CollectionModel.swift index ab4a6c146..9bd87f214 100644 --- a/Sources/Media Library/MediaLibraryModel/CollectionModel.swift +++ b/Sources/Media Library/MediaLibraryModel/CollectionModel.swift @@ -110,8 +110,8 @@ class CollectionModel: MLBaseModel { files = mediaCollection.files(with: criteria, desc: desc) ?? [] sortModel.currentSort = criteria sortModel.desc = desc - observable.observers.forEach() { - $0.value.observer?.mediaLibraryBaseModelReloadView() + observable.notifyObservers { + $0.mediaLibraryBaseModelReloadView() } } } @@ -126,8 +126,8 @@ extension CollectionModel: MediaLibraryObserver { if mediaCollection is VLCMLPlaylist { fileArrayLock.lock() files = mediaCollection.files() ?? [] - observable.observers.forEach() { - $0.value.observer?.mediaLibraryBaseModelReloadView() + observable.notifyObservers { + $0.mediaLibraryBaseModelReloadView() } sort(by: sortModel.currentSort, desc: sortModel.desc) @@ -140,8 +140,8 @@ extension CollectionModel: MediaLibraryObserver { } fileArrayLock.lock() files = mediaCollection.files() ?? [] - observable.observers.forEach() { - $0.value.observer?.mediaLibraryBaseModelReloadView() + observable.notifyObservers { + $0.mediaLibraryBaseModelReloadView() } sort(by: sortModel.currentSort, desc: sortModel.desc) @@ -153,8 +153,8 @@ extension CollectionModel: MediaLibraryObserver { } fileArrayLock.lock() files = mediaCollection.files() ?? [] - observable.observers.forEach() { - $0.value.observer?.mediaLibraryBaseModelReloadView() + observable.notifyObservers { + $0.mediaLibraryBaseModelReloadView() } sort(by: sortModel.currentSort, desc: sortModel.desc) @@ -171,8 +171,8 @@ extension CollectionModel: MediaLibraryObserver { } fileArrayLock.lock() files = mediaCollection.files() ?? [] - observable.observers.forEach() { - $0.value.observer?.mediaLibraryBaseModelReloadView() + observable.notifyObservers { + $0.mediaLibraryBaseModelReloadView() } sort(by: sortModel.currentSort, desc: sortModel.desc) diff --git a/Sources/Media Library/MediaLibraryModel/GenreModel.swift b/Sources/Media Library/MediaLibraryModel/GenreModel.swift index 004e07a70..6824e031e 100644 --- a/Sources/Media Library/MediaLibraryModel/GenreModel.swift +++ b/Sources/Media Library/MediaLibraryModel/GenreModel.swift @@ -53,8 +53,8 @@ class GenreModel: AudioCollectionModel { extension GenreModel: MediaLibraryObserver { func medialibrary(_ medialibrary: MediaLibraryService, didAddGenres genres: [VLCMLGenre]) { genres.forEach({ append($0) }) - observable.observers.forEach() { - $0.value.observer?.mediaLibraryBaseModelReloadView() + observable.notifyObservers { + $0.mediaLibraryBaseModelReloadView() } } @@ -74,8 +74,8 @@ extension GenreModel: MediaLibraryObserver { fileArrayLock.lock() files = swapModels(with: genres) - observable.observers.forEach() { - $0.value.observer?.mediaLibraryBaseModelReloadView() + observable.notifyObservers { + $0.mediaLibraryBaseModelReloadView() } } @@ -87,8 +87,8 @@ extension GenreModel: MediaLibraryObserver { files.removeAll { genresIds.contains(NSNumber(value: $0.identifier())) } - observable.observers.forEach() { - $0.value.observer?.mediaLibraryBaseModelReloadView() + observable.notifyObservers { + $0.mediaLibraryBaseModelReloadView() } } @@ -111,8 +111,8 @@ extension GenreModel { files = medialibrary.genres(sortingCriteria: criteria, desc: desc) sortModel.currentSort = criteria sortModel.desc = desc - observable.observers.forEach() { - $0.value.observer?.mediaLibraryBaseModelReloadView() + observable.notifyObservers { + $0.mediaLibraryBaseModelReloadView() } } } diff --git a/Sources/Media Library/MediaLibraryModel/HistoryModel.swift b/Sources/Media Library/MediaLibraryModel/HistoryModel.swift index 04a089757..c16873637 100644 --- a/Sources/Media Library/MediaLibraryModel/HistoryModel.swift +++ b/Sources/Media Library/MediaLibraryModel/HistoryModel.swift @@ -57,8 +57,8 @@ extension HistoryModel: MediaLibraryObserver { } else { files = medialibrary.medialib.videoHistory() ?? [] } - observable.observers.forEach() { - $0.value.observer?.mediaLibraryBaseModelReloadView() + observable.notifyObservers { + $0.mediaLibraryBaseModelReloadView() } } @@ -72,8 +72,8 @@ extension HistoryModel: MediaLibraryObserver { } else { files = medialibrary.medialib.videoHistory() ?? [] } - observable.observers.forEach() { - $0.value.observer?.mediaLibraryBaseModelReloadView() + observable.notifyObservers { + $0.mediaLibraryBaseModelReloadView() } } diff --git a/Sources/Media Library/MediaLibraryModel/MediaGroupViewModel.swift b/Sources/Media Library/MediaLibraryModel/MediaGroupViewModel.swift index 688a92d2b..43bdd193d 100644 --- a/Sources/Media Library/MediaLibraryModel/MediaGroupViewModel.swift +++ b/Sources/Media Library/MediaLibraryModel/MediaGroupViewModel.swift @@ -95,8 +95,8 @@ class MediaGroupViewModel: MLBaseModel { } sortModel.currentSort = criteria sortModel.desc = desc - observable.observers.forEach() { - $0.value.observer?.mediaLibraryBaseModelReloadView() + observable.notifyObservers { + $0.mediaLibraryBaseModelReloadView() } } @@ -172,8 +172,8 @@ extension MediaGroupViewModel: MediaLibraryObserver { } } } - observable.observers.forEach() { - $0.value.observer?.mediaLibraryBaseModelReloadView() + observable.notifyObservers { + $0.mediaLibraryBaseModelReloadView() } } @@ -192,8 +192,8 @@ extension MediaGroupViewModel: MediaLibraryObserver { fileArrayQueue.sync { files = swapModels(with: mediaGroups) } - observable.observers.forEach() { - $0.value.observer?.mediaLibraryBaseModelReloadView() + observable.notifyObservers { + $0.mediaLibraryBaseModelReloadView() } } @@ -204,18 +204,18 @@ extension MediaGroupViewModel: MediaLibraryObserver { mediaGroupsIds.contains(NSNumber(value: $0.identifier())) } } - observable.observers.forEach() { - $0.value.observer?.mediaLibraryBaseModelReloadView() + observable.notifyObservers { + $0.mediaLibraryBaseModelReloadView() } } // MARK: - VLCMLMedia func medialibrary(_ medialibrary: MediaLibraryService, didModifyVideos videos: [VLCMLMedia]) { - if !videos.isEmpty { - observable.observers.forEach() { - $0.value.observer?.mediaLibraryBaseModelReloadView() - } + guard !videos.isEmpty else { return } + + observable.notifyObservers { + $0.mediaLibraryBaseModelReloadView() } } @@ -227,8 +227,8 @@ extension MediaGroupViewModel: MediaLibraryObserver { guard success else { return } - observable.observers.forEach() { - $0.value.observer?.mediaLibraryBaseModelReloadView() + observable.notifyObservers { + $0.mediaLibraryBaseModelReloadView() } } } diff --git a/Sources/Media Library/MediaLibraryModel/PlaylistModel.swift b/Sources/Media Library/MediaLibraryModel/PlaylistModel.swift index 43311aa91..25c1e9732 100644 --- a/Sources/Media Library/MediaLibraryModel/PlaylistModel.swift +++ b/Sources/Media Library/MediaLibraryModel/PlaylistModel.swift @@ -77,8 +77,8 @@ class PlaylistModel: MLBaseModel { // Update directly the UI without waiting the delegate to avoid showing 'ghost' items fileArrayLock.lock() filterFilesFromDeletion(of: items) - observable.observers.forEach() { - $0.value.observer?.mediaLibraryBaseModelReloadView() + observable.notifyObservers { + $0.mediaLibraryBaseModelReloadView() } } @@ -89,8 +89,8 @@ class PlaylistModel: MLBaseModel { return } append(playlist) - observable.observers.forEach() { - $0.value.observer?.mediaLibraryBaseModelReloadView() + observable.notifyObservers { + $0.mediaLibraryBaseModelReloadView() } } } @@ -105,8 +105,8 @@ extension PlaylistModel { files = medialibrary.playlists(sortingCriteria: criteria, desc: desc) sortModel.currentSort = criteria sortModel.desc = desc - observable.observers.forEach() { - $0.value.observer?.mediaLibraryBaseModelReloadView() + observable.notifyObservers { + $0.mediaLibraryBaseModelReloadView() } } } @@ -122,8 +122,8 @@ extension VLCMLPlaylist: SearchableMLModel { extension PlaylistModel: MediaLibraryObserver { func medialibrary(_ medialibrary: MediaLibraryService, didAddPlaylists playlists: [VLCMLPlaylist]) { playlists.forEach({ append($0) }) - observable.observers.forEach() { - $0.value.observer?.mediaLibraryBaseModelReloadView() + observable.notifyObservers { + $0.mediaLibraryBaseModelReloadView() } } @@ -144,8 +144,8 @@ extension PlaylistModel: MediaLibraryObserver { fileArrayLock.lock() files = swapModels(with: playlists) - observable.observers.forEach() { - $0.value.observer?.mediaLibraryBaseModelReloadView() + observable.notifyObservers { + $0.mediaLibraryBaseModelReloadView() } } @@ -160,8 +160,8 @@ extension PlaylistModel: MediaLibraryObserver { } return true } - observable.observers.forEach() { - $0.value.observer?.mediaLibraryBaseModelReloadView() + observable.notifyObservers { + $0.mediaLibraryBaseModelReloadView() } } diff --git a/Sources/Media Library/MediaLibraryModel/ShowEpisodeModel.swift b/Sources/Media Library/MediaLibraryModel/ShowEpisodeModel.swift index af6291946..debed46d1 100644 --- a/Sources/Media Library/MediaLibraryModel/ShowEpisodeModel.swift +++ b/Sources/Media Library/MediaLibraryModel/ShowEpisodeModel.swift @@ -58,8 +58,8 @@ extension ShowEpisodeModel { extension ShowEpisodeModel: MediaLibraryObserver { func medialibrary(_ medialibrary: MediaLibraryService, didAddShowEpisodes showEpisodes: [VLCMLMedia]) { showEpisodes.forEach({ append($0) }) - observable.observers.forEach() { - $0.value.observer?.mediaLibraryBaseModelReloadView() + observable.notifyObservers { + $0.mediaLibraryBaseModelReloadView() } } diff --git a/Sources/Media Library/MediaLibraryModel/TrackModel.swift b/Sources/Media Library/MediaLibraryModel/TrackModel.swift index c837addd7..f7cdb6b0c 100644 --- a/Sources/Media Library/MediaLibraryModel/TrackModel.swift +++ b/Sources/Media Library/MediaLibraryModel/TrackModel.swift @@ -54,8 +54,8 @@ extension TrackModel { desc: desc) sortModel.currentSort = criteria sortModel.desc = desc - observable.observers.forEach() { - $0.value.observer?.mediaLibraryBaseModelReloadView() + observable.notifyObservers { + $0.mediaLibraryBaseModelReloadView() } } } @@ -69,8 +69,8 @@ extension TrackModel: MediaLibraryObserver { } fileArrayLock.lock() tracks.forEach({ append($0) }) - observable.observers.forEach() { - $0.value.observer?.mediaLibraryBaseModelReloadView() + observable.notifyObservers { + $0.mediaLibraryBaseModelReloadView() } } @@ -81,8 +81,8 @@ extension TrackModel: MediaLibraryObserver { } fileArrayLock.lock() files = swapModels(with: tracks) - observable.observers.forEach() { - $0.value.observer?.mediaLibraryBaseModelReloadView() + observable.notifyObservers { + $0.mediaLibraryBaseModelReloadView() } } } @@ -98,8 +98,8 @@ extension TrackModel: MediaLibraryObserver { } return true } - observable.observers.forEach() { - $0.value.observer?.mediaLibraryBaseModelReloadView() + observable.notifyObservers { + $0.mediaLibraryBaseModelReloadView() } } } diff --git a/Sources/Media Library/MediaLibraryModel/VideoModel.swift b/Sources/Media Library/MediaLibraryModel/VideoModel.swift index f5bca2928..d438d50f4 100644 --- a/Sources/Media Library/MediaLibraryModel/VideoModel.swift +++ b/Sources/Media Library/MediaLibraryModel/VideoModel.swift @@ -55,8 +55,8 @@ extension VideoModel { desc: desc) sortModel.currentSort = criteria sortModel.desc = desc - observable.observers.forEach() { - $0.value.observer?.mediaLibraryBaseModelReloadView() + observable.notifyObservers { + $0.mediaLibraryBaseModelReloadView() } } } @@ -70,8 +70,8 @@ extension VideoModel: MediaLibraryObserver { } fileArrayLock.lock() videos.forEach({ append($0) }) - observable.observers.forEach() { - $0.value.observer?.mediaLibraryBaseModelReloadView() + observable.notifyObservers { + $0.mediaLibraryBaseModelReloadView() } } @@ -82,8 +82,8 @@ extension VideoModel: MediaLibraryObserver { } fileArrayLock.lock() files = swapModels(with: videos) - observable.observers.forEach() { - $0.value.observer?.mediaLibraryBaseModelReloadView() + observable.notifyObservers { + $0.mediaLibraryBaseModelReloadView() } } } @@ -99,8 +99,8 @@ extension VideoModel: MediaLibraryObserver { } return true } - observable.observers.forEach() { - $0.value.observer?.mediaLibraryBaseModelReloadView() + observable.notifyObservers { + $0.mediaLibraryBaseModelReloadView() } } @@ -117,8 +117,8 @@ extension VideoModel: MediaLibraryObserver { } fileArrayLock.lock() files = swapModels(with: [media]) - observable.observers.forEach() { - $0.value.observer?.mediaLibraryBaseModelReloadView() + observable.notifyObservers { + $0.mediaLibraryBaseModelReloadView() } } } diff --git a/Sources/Media Library/MediaLibraryService.swift b/Sources/Media Library/MediaLibraryService.swift index 766b4de07..4a218f2e7 100644 --- a/Sources/Media Library/MediaLibraryService.swift +++ b/Sources/Media Library/MediaLibraryService.swift @@ -510,9 +510,9 @@ extension MediaLibraryService: VLCMediaLibraryDelegate { let videos = media.filter {( $0.type() == .video )} let tracks = media.filter {( $0.type() == .audio )} - for observer in observable.observers { - observer.value.observer?.medialibrary?(self, didAddVideos: videos) - observer.value.observer?.medialibrary?(self, didAddTracks: tracks) + observable.notifyObservers { + $0.medialibrary?(self, didAddVideos: videos) + $0.medialibrary?(self, didAddTracks: tracks) } } @@ -534,11 +534,11 @@ extension MediaLibraryService: VLCMediaLibraryDelegate { let tracks = media.filter {( $0.type() == .audio)} // Shows and albumtracks are known only after when the medialibrary calls didModifyMedia - for observer in observable.observers { - observer.value.observer?.medialibrary?(self, didAddShowEpisodes: showEpisodes) - observer.value.observer?.medialibrary?(self, didAddAlbumTracks: albumTrack) - observer.value.observer?.medialibrary?(self, didModifyVideos: videos) - observer.value.observer?.medialibrary?(self, didModifyTracks: tracks) + observable.notifyObservers { + $0.medialibrary?(self, didAddShowEpisodes: showEpisodes) + $0.medialibrary?(self, didAddAlbumTracks: albumTrack) + $0.medialibrary?(self, didModifyVideos: videos) + $0.medialibrary?(self, didModifyTracks: tracks) } } @@ -547,16 +547,16 @@ extension MediaLibraryService: VLCMediaLibraryDelegate { mediaIds.forEach { stringIds.append("\($0)") } CSSearchableIndex.default().deleteSearchableItems(withIdentifiers: stringIds, completionHandler: nil) - for observer in observable.observers { - observer.value.observer?.medialibrary?(self, didDeleteMediaWithIds: mediaIds) + observable.notifyObservers { + $0.medialibrary?(self, didDeleteMediaWithIds: mediaIds) } } func medialibrary(_ medialibrary: VLCMediaLibrary, thumbnailReadyFor media: VLCMLMedia, of type: VLCMLThumbnailSizeType, withSuccess success: Bool) { - for observer in observable.observers { - observer.value.observer?.medialibrary?(self, thumbnailReady: media, - type: type, success: success) + observable.notifyObservers { + $0.medialibrary?(self, thumbnailReady: media, + type: type, success: success) } } } @@ -565,21 +565,21 @@ extension MediaLibraryService: VLCMediaLibraryDelegate { extension MediaLibraryService { func medialibrary(_ medialibrary: VLCMediaLibrary, didAdd artists: [VLCMLArtist]) { - for observer in observable.observers { - observer.value.observer?.medialibrary?(self, didAddArtists: artists) + observable.notifyObservers { + $0.medialibrary?(self, didAddArtists: artists) } } func medialibrary(_ medialibrary: VLCMediaLibrary, didModifyArtistsWithIds artistsIds: [NSNumber]) { - for observer in observable.observers { - observer.value.observer?.medialibrary?(self, didModifyArtistsWithIds: artistsIds) + observable.notifyObservers { + $0.medialibrary?(self, didModifyArtistsWithIds: artistsIds) } } func medialibrary(_ medialibrary: VLCMediaLibrary, didDeleteArtistsWithIds artistsIds: [NSNumber]) { - for observer in observable.observers { - observer.value.observer?.medialibrary?(self, didDeleteArtistsWithIds: artistsIds) + observable.notifyObservers { + $0.medialibrary?(self, didDeleteArtistsWithIds: artistsIds) } } } @@ -588,21 +588,21 @@ extension MediaLibraryService { extension MediaLibraryService { func medialibrary(_ medialibrary: VLCMediaLibrary, didAdd albums: [VLCMLAlbum]) { - for observer in observable.observers { - observer.value.observer?.medialibrary?(self, didAddAlbums: albums) + observable.notifyObservers { + $0.medialibrary?(self, didAddAlbums: albums) } } func medialibrary(_ medialibrary: VLCMediaLibrary, didModifyAlbumsWithIds albumsIds: [NSNumber]) { - for observer in observable.observers { - observer.value.observer?.medialibrary?(self, didModifyAlbumsWithIds: albumsIds) + observable.notifyObservers { + $0.medialibrary?(self, didModifyAlbumsWithIds: albumsIds) } } func medialibrary(_ medialibrary: VLCMediaLibrary, didDeleteAlbumsWithIds albumsIds: [NSNumber]) { - for observer in observable.observers { - observer.value.observer?.medialibrary?(self, didDeleteAlbumsWithIds: albumsIds) + observable.notifyObservers { + $0.medialibrary?(self, didDeleteAlbumsWithIds: albumsIds) } } } @@ -611,22 +611,22 @@ extension MediaLibraryService { extension MediaLibraryService { func medialibrary(_ medialibrary: VLCMediaLibrary, didAdd genres: [VLCMLGenre]) { - for observer in observable.observers { - observer.value.observer?.medialibrary?(self, didAddGenres: genres) + observable.notifyObservers { + $0.medialibrary?(self, didAddGenres: genres) } } func medialibrary(_ medialibrary: VLCMediaLibrary, didModifyGenresWithIds genresIds: [NSNumber]) { - for observer in observable.observers { - observer.value.observer?.medialibrary?(self, didModifyGenresWithIds: genresIds) + observable.notifyObservers { + $0.medialibrary?(self, didModifyGenresWithIds: genresIds) } } func medialibrary(_ medialibrary: VLCMediaLibrary, didDeleteGenresWithIds genresIds: [NSNumber]) { - for observer in observable.observers { - observer.value.observer?.medialibrary?(self, didDeleteGenresWithIds: genresIds) + observable.notifyObservers { + $0.medialibrary?(self, didDeleteGenresWithIds: genresIds) } } } @@ -635,21 +635,21 @@ extension MediaLibraryService { extension MediaLibraryService { func medialibrary(_ medialibrary: VLCMediaLibrary, didAdd playlists: [VLCMLPlaylist]) { - for observer in observable.observers { - observer.value.observer?.medialibrary?(self, didAddPlaylists: playlists) + observable.notifyObservers { + $0.medialibrary?(self, didAddPlaylists: playlists) } } func medialibrary(_ medialibrary: VLCMediaLibrary, didModifyPlaylistsWithIds playlistsIds: [NSNumber]) { - for observer in observable.observers { - observer.value.observer?.medialibrary?(self, didModifyPlaylistsWithIds: playlistsIds) + observable.notifyObservers { + $0.medialibrary?(self, didModifyPlaylistsWithIds: playlistsIds) } } func medialibrary(_ medialibrary: VLCMediaLibrary, didDeletePlaylistsWithIds playlistsIds: [NSNumber]) { - for observer in observable.observers { - observer.value.observer?.medialibrary?(self, didDeletePlaylistsWithIds: playlistsIds) + observable.notifyObservers { + $0.medialibrary?(self, didDeletePlaylistsWithIds: playlistsIds) } } } @@ -658,25 +658,22 @@ extension MediaLibraryService { extension MediaLibraryService { func medialibrary(_ medialibrary: VLCMediaLibrary, didAdd mediaGroups: [VLCMLMediaGroup]) { - for observer in observable.observers { - observer.value.observer?.medialibrary?(self, - didAddMediaGroups: mediaGroups) + observable.notifyObservers { + $0.medialibrary?(self, didAddMediaGroups: mediaGroups) } } func medialibrary(_ medialibrary: VLCMediaLibrary, didModifyMediaGroupsWithIds mediaGroupsIds: [NSNumber]) { - for observer in observable.observers { - observer.value.observer?.medialibrary?(self, - didModifyMediaGroupsWithIds: mediaGroupsIds) + observable.notifyObservers { + $0.medialibrary?(self, didModifyMediaGroupsWithIds: mediaGroupsIds) } } func medialibrary(_ medialibrary: VLCMediaLibrary, didDeleteMediaGroupsWithIds mediaGroupsIds: [NSNumber]) { - for observer in observable.observers { - observer.value.observer?.medialibrary?(self, - didDeleteMediaGroupsWithIds: mediaGroupsIds) + observable.notifyObservers { + $0.medialibrary?(self, didDeleteMediaGroupsWithIds: mediaGroupsIds) } } } @@ -717,16 +714,16 @@ extension MediaLibraryService { extension MediaLibraryService { func medialibraryDidStartRescan(_ medialibrary: VLCMediaLibrary) { - for observer in observable.observers { - observer.value.observer?.medialibraryDidStartRescan?() + observable.notifyObservers { + $0.medialibraryDidStartRescan?() } } } extension MediaLibraryService { func medialibrary(_ medialibrary: VLCMediaLibrary, historyChangedOf type: VLCMLHistoryType) { - for observer in observable.observers { - observer.value.observer?.medialibrary?(self, historyChangedOfType: type) + observable.notifyObservers { + $0.medialibrary?(self, historyChangedOfType: type) } } } -- GitLab