swiftlang / swift

The Swift Programming Language
https://swift.org
Apache License 2.0
67.04k stars 10.32k forks source link

[SR-7045] Cannot instantiate UICollectionViewLayout's invalidationContextClass #49593

Open karwa opened 6 years ago

karwa commented 6 years ago
Previous ID SR-7045
Radar None
Original Reporter @karwa
Type Bug
Environment Xcode 9.2
Additional Detail from JIRA | | | |------------------|-----------------| |Votes | 0 | |Component/s | Compiler | |Labels | Bug | |Assignee | None | |Priority | Medium | md5: f87bd12334e974b8fb93a8a9889509df

Issue Description:

UICollectionViewLayout exposes a "invalidationContextClass" property, which should be a class which is a subtype of UICollectionViewLayoutInvalidationContext.

There are a couple of (related) issues with how this is imported in to Swift:

1) Poor importing. The property is of type "AnyClass". It should be "UICollectionViewLayoutInvalidationContext.Type".

2) Not possible to instantiate an object of the correct type. There isn't a whole lot of documentation about this API, but I think you're supposed to instantiate objects of this exact type (e.g. https://github.com/Instagram/IGListKit/blob/master/Source/IGListAdapter.m#L1080).

I've been trying to do the same thing in Swift, but it doesn't seem possible. Again, this appears to be an issue with the Swift-ObjC bridging:

let collectionView: UICollectionView = ...

let clazz = (type(of: collectionView.collectionViewLayout).invalidationContextClass as! UICollectionViewLayoutInvalidationContext.Type)

// None of these work.
let context = clazz.init()
let context = clazz.new()
belkadan commented 6 years ago

Hm. Objective-C supports doing this with protocols but not classes. I'll talk to the UIKit folks.

nevil commented 5 years ago

Sorry if I misunderstand the issue, but this seems to be working now?
I tried with Swift 4.2 Xcode 10.1:

class MyUICollectionViewLayoutInvalidationContext: UICollectionViewLayoutInvalidationContext {
    override init() {
        print("MyUICollectionViewLayoutInvalidationContext init")
        super.init()
    }
}

final class MyUICollectionViewLayout: UICollectionViewLayout {
    override class var invalidationContextClass: AnyClass {
        return MyUICollectionViewLayoutInvalidationContext.self
    }

  func afunc() {
        let clazz = type(of: collectionView!.collectionViewLayout).invalidationContextClass as! UICollectionViewLayoutInvalidationContext.Type
        print("Before clazz.init()")
        let z = clazz.init()
        print("After clazz.init()")
  }
}

The output is:

Before clazz.init()
MyUICollectionViewLayoutInvalidationContext init
After clazz.init()

AnyClass type is also used by the layerClass property on UIView.

    open class var layerClass: AnyClass { get }

Thanks