Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Expose ListGenericSectionController.object and ListSectionController.…
…collectionContext as implicitly-unwrapped optionals Summary: These methods are currently correctly annotated as `nullable`, because they can return `nil`. However, this is not practical for writing actual Swift code that uses the APIs. Overrides of `cellForItem(at:)` //must// return a `UICollectionViewCell`. Without a collection context, there's no good way to get one, so callsites must either: - Force-unwrap the `collectionContext`. - `guard let`/`else fatalError` the `collectionContext`. - Return a default `UICollectionViewCell`, which just hides the bug. None of these are good: we don't want to encourage things force-unwraps and `fatalError` in idiomatic product code, because people will see them and get the idea that these patterns are okay to use elsewhere, and they are not. This also happens with `IGListGenericSectionController`'s `object` value: to use it when creating a cell, it must be explicitly unwrapped. We could make these `nonnull`, since there's no enforcement of the annotations in Objective-C, that feels a bit too far, and it would break existing code that uses the optional API, because you can't force-unwrap (etc.) a non-optional value. Instead, we can use `null_resettable` explicitly. [While it's not covered by name in the Apple docs](https://developer.apple.com/documentation/swift/objective-c_and_c_code_customization/designating_nullability_in_objective-c_apis): > Without a nullability annotation or with a null_resettable annotation—Imported as implicitly unwrapped optionals ...it bridges the property to Swift as an implicitly-unwrapped optional. I suppose it's implied as the equivalent of "without a nullability annotation". This works even for `readonly` properties that can't be reset, and it solves both issues: it feels like less of a "100% `nonnull`" guarantee, and it's backwards-compatible with code using optionals. To demonstrate that this is backwards-compatible with existing Swift code, this test code, which runs through various optional/non-optional APIs, compiles: ``` final class TestSectionController: ListSectionController { override func cellForItem(at index: Int) -> UICollectionViewCell { let cell = collectionContext.dequeueReusableCell(for: self, at: index) let optional = collectionContext?.dequeueReusableCell(for: self, at: index) if let _ = collectionContext {} return optional ?? cell } } final class TestGenericSectionController: ListGenericSectionController<NSString> { override func cellForItem(at index: Int) -> UICollectionViewCell { let label = UILabel() // imagine it's from a cell label.text = object as String label.text = (object as String) + "Suffix" // wouldn't work with optional label.text = object.map { $0 as String } if let object = self.object { label.text = object as String } return collectionContext.dequeueReusableCell(for: self, at: index) } } ``` Reviewed By: patters, lorixx Differential Revision: D23603716 fbshipit-source-id: e4750dcfe0072d482951dbf2e9efb1ee3de46884
- Loading branch information