sunshinejr / sunshinejr.github.io

Statically generated frontend for my website. Using Hugo.
https://sunshinejr.com
4 stars 1 forks source link

Stop using IBOutlets. Today. #10

Open sunshinejr opened 4 years ago

sunshinejr commented 4 years ago

🚨

briancordanyoung commented 4 years ago

I’m all for removing implicitly unwrapped optionals. But, isn’t the reason for that to create more safety? This technique moves the exact same crash to a different place. The advantages are that you have control over making the fatal error message and the properties are no longer decorated with the dreaded ‘!’. But, sadly, it doesn’t improve safety. Unless, i’m missing something?

That said, it is fun to see how everyone is using property wrappers. Thank you for the posts.

sunshinejr commented 4 years ago

@briancordanyoung I think this improves safety, at least a bit, by using a Type instead of a Type! - you avoid optionals, you also avoid availibility to nil a value that shouldn’t be niled at all. This property wrapper is for the cases where you don’t really have an optional value, but you have to specify the type as that because of some limitations (either Swift’s or any framework’s).

Also I think utility is much bigger gain in this case (type change) than the safety improvement. But again, your mileage may vary.

briancordanyoung commented 4 years ago

you also avoid availibility to nil a value that shouldn’t be niled at all.

That is something I didn't consider. So, yes, a little safer.

angelolloqui commented 4 years ago

If you do not have the @IBOutlet, does it show up inside Interface Builder? I would say it does not, but if that is the case, how are you using it?

david-grigoryan-dev commented 4 years ago

You have slightly removed 'weak' from the outlets? Do you use them always as strong? Did you try with property wrapper on a weak property? 🤓

sunshinejr commented 4 years ago

@angelolloqui yes it doesn't as I guess they are hardcoded the IBOutlet annotation inside IB. I just create the bindings as you would normally do and then remove IBOutlet and replace it with the @Delayed @objc. Tiresome but I like the benefits. I guess there could be a build-phase script (before building your files) that would replace all IBOutlet occurrences with @Delayed @objc and that way we could automate it a little bit more.

sunshinejr commented 4 years ago

@david-grigoryan-dev ah seems like property wrappers can't be used with weak properties? Sad limitation but probably only temporary. Also, strong is the recommended binding type in IBOutlets (though there are cases where weak makes sense but I don't remember last time I needed a weak outlet).

angelolloqui commented 4 years ago

It is an interesting use of wrappers but I do not see the benefit if you lose the ability to link from IB. Too much hazle for nearly no gain (IMHO) which as far I can see it is only the protection against assigning nils (who and why would do that by the way?). Anyway, the idea is pretty nice for other usages I guess! Thanks for sharing!

sunshinejr commented 4 years ago

@angelolloqui fair enough! There are a lot of people that share the same feelings and that's completely fine. I, personally, really dislike the force-unwrapped IBOutlets and was looking for a cure for many months so, naturally, I was really hyped when I found out a solution.

But as you've said this can be used in many other places - I especially love it in convenience initializers in ViewControllers to. I'm just a big fan of this property wrapper, really, and I hope you will enjoy it as much as I do.

MKGitHub commented 4 years ago

Some thoughts IMHO. @Delayed sounds like something to do with time. And the underscore convention is ... strange ...

shaps80 commented 4 years ago

Agree with most of the comment above but I also wanted to highlight that the use of ! isn't just a hold-over from Objc-C code. Its also a valid approach to inform the API consumer.

Marking a variable as optional, tells the consumer it can be nil. Marking it as explicitly unwrapped tells the consumer it might be nil during instantiation, however it should NEVER be nil afterwards – It would've been great if this was literally prevented by the compiler, the same way let only allows a variable to be set once, but that's another topic.

It makes sense with @IBOutlet since it is late-binding. The use of ! here tells the consumer that the variable MUST not be nil after init has occurred.

––

Side note: @LateBinding might have been a better name for your property wrapper. Not a perfect name still, but perhaps a little better.