The core of Swift We can understand Swift through the transitivity of equality:
You may be surprised by my title. I am not saying that subclasses have no value, especially when using single inheritance, classes and subclasses are certainly powerful tools. However, I am saying that the problem of daily iOS development is the overuse of classes and inheritance. As object-oriented programmers (OOP programmers, object-oriented programming is abbreviated as OOP), we always naturally tend to use reference types and classes to solve problems, but I personally think that we should turn it around and use value types instead of reference types. We still have to write modular, scalable and reusable code, and this will not change. The powerful value types in Swift can help us achieve this goal without having too strong a reliance on reference types. I think not only protocol oriented programming (POP) can help us achieve this, but also two other types of programming, which have the core idea of abstraction and simplification: value-oriented programming (VOP) and functional programming. Let me make it clear that I am by no means an expert in these types of programming (POP, VOP and functional programming). Like you, I have been an OOP programmer since the days of MMM (manual memory management). Through self-study, I have attached great importance to the idea of value abstraction and simplification since the beginning. I didn't realize that I was an OOP programmer who was inclined to functional programming, and I often used VOP and POP ideas. This is probably why I jumped on the Swift bandwagon on the first day. During the whole week of WWDC, I was filled with the feeling that the core concepts of Swift were so consistent with how I thought programming should be done. Through this article, I hope to help you (OOP programmer) open your mind and think about how to solve problems in a more Non-OOP way. The Problem with OOP (and Why I Had to Learn It) I'll be the first to say it: it's hard to make an iOS app without OOP. Cocoa is OOP at its core. You can't write an iOS app without OOP. Sometimes I fantasize that this isn't true. If you think differently, prove me wrong. I really need this, please, prove me wrong! No matter what, you will always encounter a situation where you have to use objects, use reference types to solve a problem, and then because of the rules of Cocoa, you are forced to use classes. In this case, you encounter the problems we all know and love:
POP Protocol Oriented Programming It's so easy to fall into OOP anti-patterns. Most of the time we (including me) are just too lazy to click File>New File. As a result, we don't want to create a new class from scratch because it's so easy to add a function to an existing class. If you keep doing this, and are too lazy to subclass a "very important" class, you'll end up with a God class/Death Star class. I actually did this before: I gave every view controller in an app the ability to present an error view that pointed to the navigationBar of the navigationController. Ugh, stupid me. When it came time to change the behavior of the Error God class, I had to change the entire app. Not a smart move, you should really look at the bugs. One class that controls everything = bugs everywhere If POP is used, this Error God class can be easily abstracted to a large extent, and it is also convenient to improve it in the future. (By the way, if you want to learn POP, I strongly recommend you to watch this video.) It's funny to think about it, because in this video Apple itself said: "Start with a protocol, not a class." - Dave Abrahams: The professor who ruins your worldview Here’s an example that shows how brutal this is:
As the project progressed it quickly became clear that not every UIViewController needed this error logic, or really needed every feature this class provided. Anyone on my team could easily change something in this superclass and affect the entire app. This made the code fragile. It also made the code polymorphic. While it should be up to the subclass to determine its own behavior, the superclass here helped decide. Here’s how we can better structure this code in Swift 2.0 using POP:
See, something cool is happening here. Not only have we eliminated the God class, but we've also made our code more modular and extensible. By creating an ErrorPopoverRenderer protocol, any class that conforms to it will have the ability to present an ErrorView. Not only that, our KrakenViewController class doesn't have to implement presentError because we extended UIViewController to provide a default implementation. But wait! There’s a problem! We have to implement each parameter every time we want to render an ErrorView. This is a bit annoying because we can’t provide default values for parameters in the protocol function declaration. I like these parameters! What’s worse is that we’ve introduced complexity in the process of making the code more modular. Let’s go ahead and use a little trick added in Swift 2.0 to compensate for it a bit:
Okay, now it's looking pretty good. Not only did we get rid of those annoying parameters, but we also used the new features of Swift 2.0 to give presentError a default implementation using Self at the protocol level. Using Self means that this extension will only be effective if and only if the protocol conformer inherits from UIViewController. This allows us to treat ErrorPopoverRenderer as a real UIViewController without even having to extend the latter! Even better, from now on, the Swift runtime calls the presentError() method with static dispatch rather than dynamic dispatch. Basically, we have enhanced the performance of the presentError() method at the function call point. Alas, there is still a problem. Our journey of POP has come to an end here, but we will not stop improving it. Our question is what if we only want to use default values for some parameters and not for the rest? POP can't help us in this regard, but we can find another way. Now, let's use VOP. #p# VALUE-ORIENTED PROGRAMMING You see, POP and VOP always go together. In the WWDC video link above, Crusty makes some bold claims: we can do everything that classes can do with struct and enum types. I agree with this to a large extent, but not to such an extreme. In my opinion, protocols are essentially the glue that holds VOP together, and I agree with Crusty on this point. In fact, since we are talking about the core concept of Swift and VOP, I want to show you a great interview with Andy Matuschak about VOP in Swift. An excellent picture taken from the topic: It can be seen that in Swift's standard library, only 4 classes and the remaining 95 struct and enum instances together construct the core of Swift's functions. Andy elaborated: When programming in Swift we have to think about using a thin layer of objects, and a thick layer of value types. Classes have their place, but I try to think of them as being at a very high level in the object layer, where we manage various behaviors by manipulating the logic in the value type layer. "Separate logic from behavior" - Andy Matuschak As you know, when a value type is assigned to a variable or constant, or passed to a function as an argument, its value is copied. This allows value types to have only one owner at any time, thus reducing complexity. Contrary to reference types, reference types can have many owners during the assignment process, some of which you may not even be aware of. Using a reference at any point in time can cause side effects: the owner of the reference can do mischief and change the reference behind your back. Class = high complexity, value = low complexity. By taking advantage of the simplicity of value types, let's implement the default parameter design mentioned earlier. We use Brian Gesiak's value options paradigm method: Using the above option type struct (value type!) gives our POP some VOP color, as follows:
As you can see, we have given it a completely abstract, scalable and modular way to use view controllers for error handling, without forcing all view controllers to inherit from a god class. This is especially helpful when you have a god class with different functionalities. In addition, when implementing other functionalities like the error functionality above in this way, you can put the code implementing the functionality anywhere without doing too much refactoring or changing the code framework.
Functional Programming Let's solve this. I'm new to functional programming as well, but I do know this: the paradigm calls for a style of programming that encourages programmers to avoid mutable data and changing state. Similar to mathematical functions, functional programming consists of functions whose output depends only on their input parameters, and whose output is not affected by dependencies outside of the function. This is known as "data in, data out", meaning that every time a value is passed in, it should always be the same when it goes out as when it came in. Think of unit testing! If we write code with a functional mindset, we can combine VOP with functional programming and take advantage of its many advantages, including but not limited to:
When to use subclasses When should you use subclassing? The answer is when you have no choice. For example:
in conclusion As OOP programmers we are used to solving problems with classes. Over time we have developed patterns to compensate for the drawbacks of reference types. My view is that a different way of thinking in programming can effectively mitigate the use of these compromises. If we really care about scalability and reusability, we have to accept that modular programming is the way to go. Using value types combined with the new and improved protocols in Swift 2.0 will easily achieve this goal. Although the OOP way of thinking makes it difficult for us to think in terms of VOP and POP, as we write more in Swift, VOP and POP patterns will begin to become second nature. It may take a few more lines of code for our brains to adapt to this way of thinking, but I believe that the iOS community as a whole will accept these practices and greatly reduce the difficulty of our daily problem solving. At the core of Swift is an extremely powerful value type system, and frankly, we should hone our minds in VOP thinking from the beginning to promote the advantages of this value system. I hope this article can help you write more detailed, inherently safe code every day. Happy programming, coders! |
>>: Exclusive interview with Qu Yi, Senior Technical Director of Qilekang: Notepad, Code and Crow5
Apple iPhone 6 has always been highly exposed, and...
Details determine success or failure. Do you agre...
Let me briefly explain to you the essence and log...
Introduction to the April training camp resources...
Due to the disappointment caused by iOS13 to Appl...
Have you seen the news recently about a certain b...
I'm here again, haha. Today I recommend to yo...
There are 6 common types of keywords : brand word...
Marketing often involves planning a series of act...
Content: Changsha New Tea website appointment arr...
With the arrival of 2021, it has become increasin...
As the saying goes, "eyes are windows to the...
Today we are going to talk about a topic that is ...
The author of this article mainly shares the appl...
Tianjin, March 6 (Xinhua) -- A good opportunity t...