I am having a problem trying to resolve a problem with an associated type in a protocol.
Here is the code stripped down to minimum for demonstration
protocol Protocol1
{
associatedtype DataItem
func protocolMethod(item : DataItem)
}
protocol Protocol2 {
associatedtype AType1: Hashable
//...
}
class Class1<Type1: Protocol2>: NSObject
{
typealias Item = Type1.AType1
var delegate : (any Protocol1)?
private func method1(item: Item)
{
delegate?.protocolMethod(item : item) //ERROR HERE
}
}
The error occurring at "ERROR HERE" is:
Member 'protocolMethod' cannot be used on value of type 'any Protocol1'; consider using a generic constraint instead
This all works if the item parameter is not defined on protocolMethod (and its invocation where the error occurs). And I think I get why it's happening, that it can't determine the type of item in the invocation. Is there a way to accomplish this? I have played with it quite a bit with generic params, etc. but still can't find the right formula to make it work. Am I just asking too much from Swift in this case?
Post
Replies
Boosts
Views
Activity
Currently pretty confused about a DiffableDatasource, FetchedResultsController, & CollectionView behavior. As a result of calling the method below, the NSFetchedResultsController delegate didChangeContentWith method is called with a snapshot that contains temporary NSManagedObjectIds. As a result, when cell registration vend block is called, it is given the temporary id as the item id which no longer is valid as the object has been saved. So trying to retrieve the object to create the configuration for the cell fails.
Here is snippet of the log produced by the code below (adding 2 new items):
pre-save
didChangeContentWith
Printing description of snapshot:
NSDiffableDataSourceSnapshot 0x2838cb660: numberOfSections:1 numberOfItems:5; generation=4EAC45D6-A145-4F4C-8220-F6EE212C3F88; sectionCounts=[_UIDataSourceSnapshotter - 0x283ab3fe0:(0:5)]
[d69e6c783a242772974cfc99189691b88e9d37c3: {0x94cd5e7b72fa7e83 x-coredata://988F6C04-1529-454C-BBCB-2DE610F7AFC0/PlaylistItem/p2 0x94cd5e7b729a7e83 x-coredata://988F6C04-1529-454C-BBCB-2DE610F7AFC0/PlaylistItem/p1 0x94cd5e7b72da7e83 x-coredata://988F6C04-1529-454C-BBCB-2DE610F7AFC0/PlaylistItem/p3 0x283a5a8e0 x-coredata:///PlaylistItem/t710323F2-7D5C-40C4-A055-F75F8E0D0C852 0x283aaf8a0 x-coredata:///PlaylistItem/t710323F2-7D5C-40C4-A055-F75F8E0D0C853}]
post save
getting cell for [0, 0] with objid: 0x94cd5e7b72fa7e83 x-coredata://988F6C04-1529-454C-BBCB-2DE610F7AFC0/PlaylistItem/p2
getting cell for [0, 1] with objid: 0x94cd5e7b729a7e83 x-coredata://988F6C04-1529-454C-BBCB-2DE610F7AFC0/PlaylistItem/p1
getting cell for [0, 2] with objid: 0x94cd5e7b72da7e83 x-coredata://988F6C04-1529-454C-BBCB-2DE610F7AFC0/PlaylistItem/p3
getting cell for [0, 3] with objid: 0x283a5a8e0 x-coredata:///PlaylistItem/t710323F2-7D5C-40C4-A055-F75F8E0D0C852
Fatal error: Managed object should be available: file Stoppage/PlaylistDetail2FRCViewModel.swift, line 118
2021-05-05 11:43:10.611464-0500 Stoppage[5055:2243531] Fatal error: Managed object should be available: file Stoppage/PlaylistDetail2FRCViewModel.swift, line 118
The datasource is passing the temporary id (which is no longer available post save) to the cell creation. I can fully accept that I might be being dim and not seeing my mistake, but I just can't see it. It seems to me that the snapshot generated from the save should have the real objectIds rather than the temps. The end result is that the fatalError() in the cell registration is called as it can't find the object with the temp id.
Insert items method
func addItemsToPlaylist(_ newItemCollection:MPMediaItemCollection)
{
guard let playlist = self.playlist else {fatalError()}
AppDelegate.appDelegate().persistentContainer.viewContext.performAndWait {
let pl = AppDelegate.appDelegate().persistentContainer.viewContext.object(with: playlist.objectID) as! Playlist
pl.addMediaItems(newItemCollection)
if AppDelegate.appDelegate().persistentContainer.viewContext.hasChanges {
do {
print("pre-save")
try AppDelegate.appDelegate().persistentContainer.viewContext.save()
print("post save")
} catch {
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
}
}
didChangeContent method
func controller(_ controller: NSFetchedResultsControllerNSFetchRequestResult, didChangeContentWith snapshot: NSDiffableDataSourceSnapshotReference) {
print("didChangeContentWith")
guard let datasource = diffableDataSource else {
assertionFailure("The data source has not implemented snapshot support while it should")
return
}
datasource.apply(snapshot as NSDiffableDataSourceSnapshotInt, NSManagedObjectID, animatingDifferences: false)
}
Cell Registration
let itemCellRegistration = UICollectionView.CellRegistrationPlaylistDetail2Cell, NSManagedObjectID { (cell, indexPath, itemId) in
guard let object = try? AppDelegate.appDelegate().persistentContainer.viewContext.existingObject(with: itemId) else {
fatalError("Managed object should be available")
}
cell.playlistItem = object as! PlaylistItem
cell.playlistItemId = object.objectID
}