-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Remove IGListSectionType protocol and absorb methods into IGListSectionController superclass #168
Comments
@yusuftor I wonder if Swift interop is messing up here. The interface is declared as: - (__kindof IGListSectionController <IGListSectionType> * _Nullable)sectionControllerForObject:(id)object; I wonder if the |
I'm not strong on Objective-C, but I guess it must be a Swift interop problem if it works fine in Objective-C. The other protocol functions aren't accessible either, but the properties seem to be accessible, e.g. scrollDelegate, workingRangeDelegate. |
@rnystrom -- I'm gonna say this is a bug. Let's see if we can adjust the return type to be more Swift-friendly. |
@rnystrom @jessesquires Seems that a type can't be both a protocol and a concrete type at the same time in Swift. Is it possible to expose |
Ah, right. @zhubofei is correct. Currently, Swift does not have a way to express "concrete type + protocol". I think we'll have to live with this for now. |
I'm going to leave this open as a bug for now for future reference. |
Actually, going to close this since there's nothing actionable. This won't be expressible in Swift for awhile. We can revisit then -- if ever. |
@rnystrom @jessesquires I came across this issue when I went through the code of Spotify's HubFramework today. I was wondering if we can use the same approach by merging |
@zhubofei yeah, it's an interesting idea. Our goals with this design were:
But, perhaps the trade-offs are not really worth it here. Having only a superclass would simplify the design for ObjC too. Asserting on unimplemented methods isn't that bad, I guess. There is precedent for this type of design in UIKit. (And we are mostly mimicking One benefit of absorbing 🤷♂️ 🤷♀️ cc @rnystrom |
Ok I took a day to let this sink in and form some thoughts around it. I'm still really opposed to only subclassing We designed the class+protocol so we can combine compiler safety along w/ the convenience of the base class implementing stuff. The nice part is that the The original goal of IGListKit was to prevent the same user-errors from happening within an app the size (both code and team) of Instagram, and that was back when we had like 20 iOS engineers (now we have over 50!). So relying on the compiler as much as possible is incredibly important to us stopping bugs at ⌘-B. I agree there is a lot of boilerplate, but for the most part, its all required:
Not to mention adding Thoughts? |
I think there's still a strong case for removing the protocol. (And it would be safest to have However, one thing to call out is that we're basically discussing a change that's a reaction to deficiencies in Swift — that really weakens the argument for me. If Swift could express |
Oh shit — I think I have a solution. It's kind of hacky, but not really that bad. Check it out: So the issue is that in Swift we only get the Here's what we can do: add Then @protocol IGListSectionType <IGListSectionControllerProtocol> When clients conform to Now, we simply return Bam. 💥 |
Ok. Just hacked the above together at #412. Good news: it works! Bad news: |
@jessesquires still think we should work on this? |
@rnystrom - Not sure. Did you checkout #412 ? It's ugly and hacky, but just a proof-of-concept WIP. But there are still some issues to work out. Honestly, even though subclassing is terrible™️ — it would simplify a lot of things and vastly improve inter-op with Swift. We could provide reasonable defaults where possible ( Either way, I think we should choose:
Though I think (2) is the best path forward — simpler for the library and for clients. If this were pure Swift, our design space would be much more vast and we would have all kinds of options. But 😢 EDIT: Another point in favor of subclassing: we already require subclassing section controllers. So I think we gain very little by introducing the |
So, I think my vote would be for:
|
@rnystrom - What's our decision here? |
I'm on board to kill the protocol! |
@rnystrom 💯 We should probably do this task internally. There will be lots of fix up. |
Alright after internal discussion I'm back to being on the fence about this issue. I do worry that once we make this decision it'll be irreversible, both b/c of internal usage growth and external churn. I'm starting to lean back towards not doing this, and waiting until there is some real pressure (internal/external) to drive this being necessary. Thoughts @jessesquires? |
That is absolutely true. We can't go back, so we should consider this carefully. Let's discuss on chat. |
Ok I think I'm finally on board w/ this. @ryanolsonk mentioned something today that got me thinking, we could use ObjC generics and get a lot of stuff for free:
I put together a quick demo simulating our IGListSectionController setup: @protocol Object // aka IGListDiffable
@end
// can't use id I guess?
@interface ObjectUpdater<__covariant ObjectType:NSObject<Object> *> : NSObject
@property (nonatomic, strong, nullable, readonly) ObjectType object;
- (void)didUpdateToObject:(nonnull ObjectType)object __attribute__((objc_requires_super));
@end
@implementation ObjectUpdater {
NSObject<Object> *_object;
}
- (NSObject<Object> *)object {
return _object;
}
- (void)didUpdateToObject:(NSObject<Object> *)object {
_object = object;
}
@end Then let's create another model + updater @interface User : NSObject<Object>
@property (nonatomic, strong) NSString *name;
@end
@interface UserUpdater : ObjectUpdater<User *>
@end
@implementation UserUpdater
- (void)didUpdateToObject:(User *)object {
[super didUpdateToObject:object];
NSLog(@"%@", self.object.name); // auto casted as User
}
@end And Swift? class Post: NSObject, Object {
var title = "title";
}
class PostUpdater: ObjectUpdater<Post> {
override func didUpdate(to object: Post) {
print(object.title) // again, casted
}
} @jessesquires what do you think? Should we bundle this w/ 3.0 or hold on it for 4.0? |
@rnystrom I'm down. This sounds awesome to me. I say we should put this in 3.0 — we have a ton of breaking changes already, especially #593 — we might as well "re-arrange all the deck chairs" in a single release 😊 However, I think we should try to push out multiple 3.x releases and hold off on 4.0 (more breaking changes) for awhile, if possible. |
Alright, I'm going to PR this tomorrow. cc @amonshiz not sure how this will conflict w/ the table view stuff |
Probably make everything easier. |
It's not possible to access the numberOfItems() function on an IGListSectionController unless it is type cast to a specific IGListSectionController subclass. Is there a reason for this?
For example:
let sectionController = adapter.sectionController(for: content.last!)
let numberOfItems = sectionController.numberOfItems()
<- Doesn't worklet numberOfItems = (sectionController as! SectionControllerSubclass).numberOfItems()
<- WorksThe text was updated successfully, but these errors were encountered: