In this post I want to talk to you about my recent transition from Objective-C to Swift. I will try to give you some advice, point out some misconceptions and compare the differences between the two languages. Without further ado, let’s get straight to the point. Note: The development environment discussed in this article is Xcode 6 beta 2. Single file structure vs interface-implementation The most noteworthy change is that the file structure of "[interface].h/[implementation].m" in Objective-C has been abolished. In fact, I personally support this file structure, because the way to obtain and share class characteristics through interface files is quite safe and simple, but now we have to face the reality that it no longer exists. In Swift, there is no interface and implementation split into two files. We only need to build a class based on the implementation (and it is not even possible to add accessibility changes when writing). If you feel that this change is unbearable, you should pay attention to the following: The most obvious: rely on intuition. We can use nice documentation to improve the readability of the class. For example, we can move all the elements that we want to be public to the beginning of the file, or we can use extensions to distinguish between public and private. Another very practical way is to add an underscore '_' as a prefix before the names of private methods and variables. Here is an example that mixes the above two approaches:
Although we cannot modify the visibility of elements in a class, we can try to make certain accesses "more difficult". A special method is to use nested classes to hide the private part (at least automatically), the following is an example:
We put the private implementation into an instance of a private constant, and then use the "normal" class implementation as the interface. However, the private part is not really hidden, but you need to add a private keyword when accessing it:
The question is: is it worth writing the code so weird just to hide these private parts? My suggestion is that until visibility changes are made (Apple is working on this), we should use detailed documentation or some extensions to accomplish this. Constants and variables When writing Objective-C, I rarely use the const keyword, even when I know that some data will not change (ok, don't complain about me). However, in Swift, Apple recommends that developers spend more time using constants (let) instead of variables (var). So please pay attention to figure out what your variables are doing. You will use constants more frequently than you ever thought. A simpler way to write Take a look at the following two lines of code and compare the differences:
I forced myself not to add semicolons to every line of code in the first two weeks of my Swift experience, and now my life is complete (although I don’t add semicolons when writing Objective-C now). Type inference can assign types to variables directly based on their definitions. Compared to verbose languages like Objective-C, this is quite remarkable. We should use consistent naming, otherwise it will be difficult for other developers (including yourself) to guess the type from extremely poorly named code:
A more reasonable naming would be:
Another change is regarding brackets, they no longer need to be matched:
But remember, the part we write between the brackets is considered an expression, which does not always mean it is correct. We cannot use brackets when binding variables like this:
Using type checks and removing semicolons and parentheses is not strictly necessary, but it is recommended that you consider writing Swift code in the manner suggested above. This will improve readability and save you some typing. Optional Values How many times have we been confused about how to set the return value of a function? I have used NSNotFound, -1, 0, and custom return values to indicate that the return is empty. Now with the emergence of optional values, the problem of empty return values has been solved well. We only need to add a question mark after the data type. We can write it like this:
This is an example of using an optional value to describe "someone has a car", which means that the feature car can be None, because it means that someone does not have a car. Then we can use optional binding or unwrap to get its value. If a property is not set as an optional value and we don't assign a value to it, the compiler will immediately be unhappy. There is no opportunity to set non-optional properties once initialized. So we should consider in advance how the attributes of a class relate to other parts and how they change when the class is instantiated. These improvements completely change the way to think about a class. Unpacking optional values You may find optional values confusing because you won’t understand why the compiler would prompt you to unwrap them before using them. Mark.car? I suggest you think of optional values as a structure (it's easier to understand if you think of it as a structure), which contains a value you set. But it wraps something else (wrap). If the value inside is defined, you can unwrap it and get the value you want. Otherwise, you get a null value (nil). Using the exclamation mark "!" to force unpacking regardless of whether the value is defined is risky because the application will crash if the value is not defined. Delegation Mode After years of writing Objective-C and Cocoa code, I think most people have developed a habit of using the delegate pattern. Attention! We can still keep this habit, here is a very simple example:
Here we use a simple @optional to replace the use of respondToSelector to detect whether the delegate method exists.
Please note that we must add the @obj prefix before the protocol because @optional is used later. The compiler will also report a warning message here in case you do not add @obj. To implement the protocol, we need to build a class to implement it and then assign it in the same way we did in Objective-C.
Goal-Action Pattern Another commonly used design pattern: target-action pattern. We can still implement it in Swift just like we use it in OC.
The only difference here is how to define a selector. We can transform and use a string like the following to write the method prototype:
Singleton Mode It's a love-hate relationship. The singleton pattern is still one of the most commonly used patterns in design patterns. We can use GCD and dispatch_once to implement it, and of course we can use the let keyword to achieve thread safety.
Let's take a quick look at this code: 1. sharedReader is a static composite property (we can also replace it with a method). 2. Static properties do not allow refactoring when the class is implemented, so since inner types are allowed, we can add a structure here. 3._instance is a constant, it will not be overwritten and is thread safe. You can refer to the following usage of DataReader singleton:
Structures and Enumerations Structures and enumerations in Swift are simply amazing, you won’t find anything like them in any other language. They support methods:
As you can see here the structure uses an initializer, and this is automatically created by Swift (we can add some custom implementations). The syntax for enumeration types is a little more difficult than what we are used to. Its definition requires the keyword case:
And enumerations are not limited to int type:
It can also be more complex:
Above, we added an internal type Vitamin and a compound mainVitamin to the Fruit enumeration class, and such a structure can also initialize the elements inside according to the value of the enumeration... Are you already dazzled? Mutable and Immutable Classes In Objective-C we always use mutable and immutable classes, for example NSArray and NSDictionary. In Swift we no longer distinguish data like this, we just use constant and variable definitions instead. Data variables can be changed while the value of array constants cannot be changed. So please write down this formula: "let = immutable. var = mutable". Blocks and Closures I really like the block syntax because it is fairly simple and easy to remember.
By the way, because I have been using Cocoa for many years, I sometimes prefer to use blocks instead of simple delegation tasks. This is a very flexible and fast way, and it is very practical. The Swift counterpart to blocks are closures. Closures are extremely powerful and Apple has done a great job of making them simple and easy to implement. The examples in the official documentation leave me speechless. It is defined like this:
Then reconstructed like this:
So, thanks to type judgment we can implement a closure, shorthand parameters ($0, $1) and direct operation functions (>) in different ways. In this post I plan to go over the usage of closures but first I want to say a few words about how to get the value of a closure. In Objective-C, we define a variable like _block in case we want to push it into a block. But this is not necessary in closures. We can use and modify surrounding values. In fact, closures are designed to be smart enough to get external elements for internal use. Each element obtained is either a copy or a reference. If the closure will modify its value, a reference is created, otherwise a copy is generated. If a closure references an instance that contains or calls the closure itself, we have a strong reference cycle. Let’s look at an example:
This agePotion closure references itself, which in turn maintains a strong reference to the current instance. At the same time, the instance maintains a reference to the closure. BOOM~~~ We have entered a strong reference cycle. To avoid this situation, we need to use the Capture List. This list maintains unowned weak references to the instances we want to use. The syntax is very simple, just add [unowned/strong self] before the closure definition, and then you will get an unowned weak reference to replace the previous strong reference.
Unowned Weak References We know how weak references work in Objective-C. It is the same in Swift, with basically no changes. So what is an unowned reference? I looked carefully at the introduction of this keyword because it well explains the definition of the relationship between classes. Let's briefly describe the relationship between a person Person and a bank account BankAccount: 1. A person can have a bank account (optional). 2. A bank account belongs to one person (required).
This relationship will create a reference cycle. The first solution adds a weak reference to the "BankAccount.owner" property. However, it also uses an unowned reference as a constraint: this property must have a value and cannot be null (the second point in the previous list is satisfied). Well, there is not much more to say about unowned references. It is just like a weak reference that does not add any effect to the reference, but guarantees a non-null value for it. Summarize I have to admit that I occasionally look at a compiler error and think: WTF. The more I spend experimenting and testing with Swift the clearer its value becomes. It takes a lot of interest to get started with Swift development and training away from Objective-C before we can feel comfortable using it. Link to this article: http://www.cocoachina.com/ios/20141011/9884.html |
<<: How to make programmers happy at work: details determine success or failure
>>: How to implement Touch ID verification in iOS 8 using Swift
Every time a revolutionary technology comes, it w...
As we all know, cloud computing, big data, mobili...
The United Nations World Population Prospects 202...
In this fast-paced, information-based society, yo...
WeChat Mini Program is an application that users ...
The app icon plays a very important role in the c...
【Mobile software: Bo Ke Yuan】Since the Apollo moo...
As a representative of short video platforms, Dou...
The same applies to SEM bidding. Don’t use dilige...
Many friends who are engaged in website SEO optim...
Donatello, who invented the layered carving techn...
Different from the internal combustion engines of...
[[155877]] background The concept of Code Kata wa...
Paralysis refers to the reduction or loss of volu...
South Korea's insistence on deploying the THA...