15

I have this code working fine in Swift 2.

extension PHFetchResult: Sequence {
     public func makeIterator() -> NSFastEnumerationIterator {
         return NSFastEnumerationIterator(self)
     }
}

Since I upgraded to Swift 3

Extension of a generic Objective-C class cannot access the class's generic parameters at runtime

I have no idea on how to fix this. Any help is much appreciated!

rgoncalv
  • 5,825
  • 6
  • 34
  • 61

4 Answers4

1

Problem was reported here: https://bugs.swift.org/browse/SR-1576

But in the end you can't use for in with PHFetchResult in Swift 3.0. Let's see some examples:

let collections = PHAssetCollection.fetchAssetCollections(with: .album, subtype: .any, options: nil)
let collectionLists = PHCollectionList.fetchCollectionLists(with: .momentList, subtype: .momentListYear, options: nil)
let assets = PHAsset.fetchAssets(with: .image, options: nil)

You can either use the built-in enumeration of PHFetchResult (my recommended solution):

collections.enumerateObjects(_:) { (collection, count, stop) in
    //...
}
collectionLists.enumerateObjects(_:) { (collectionList, count, stop) in
    //...
}
assets.enumerateObjects(_:) { (asset, count, stop) in
    //...
}

Or access each object by its index:

for idx in 0 ..< collections.count {
    let collection = collections[idx]
    // ...
}
for idx in 0 ..< collectionLists.count {
    let collectionList = collectionLists[idx]
    // ...
}
for idx in 0 ..< assets.count {
    let asset = assets[idx]
    // ...
}
Cœur
  • 37,241
  • 25
  • 195
  • 267
1

Pulling from Realm, you may be able to get around this by extending a subclass of what you want to conform to Sequence and put the makeIerator function there.

// Sequence conformance for ClassA is provided by ProtocolX's `makeIterator()` implementation.
extension ClassA: Sequence {}

extension ProtocolX {
    // Support Sequence-style enumeration
    public func makeIterator() -> RLMIterator {
        return RLMIterator(collection: self)
    }
}

You can see the full code at https://github.com/realm/realm-cocoa/blob/master/Realm/Swift/RLMSupport.swift

Maxwell
  • 6,532
  • 4
  • 37
  • 55
0

You can use a wrapper type as suggested by Swift engineer Jordan Rose on the bug report:

import Photos

struct ResultSequence<Element: AnyObject>: Sequence {
  var result: PHFetchResult<Element>
  init(_ result: PHFetchResult<Element>) {
    self.result = result
  }
  func makeIterator() -> NSFastEnumerationIterator {
    return NSFastEnumerationIterator(self.result)
  }
}


func test(_ request: PHFetchResult<PHCollection>) {
  for elem in ResultSequence(request) {
    print(elem)
  }
}
JAL
  • 41,701
  • 23
  • 172
  • 300
-1

There is no way to fix that, you might need to refactor your code or use some other techniques.

you can refer to this:

How to use a swift class with a generic type in objective c

docs:

https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html#//apple_ref/doc/uid/TP40014216-CH10-XID_78

Community
  • 1
  • 1
eNeF
  • 3,241
  • 2
  • 18
  • 41