Question 1- Swift 1.0 or later
What is the optional type, and what problem is it designed to solve?
The optional type is used to indicate that any type of variable can indicate a missing value. In Objective-C, variables that reference types are allowed to miss values, and nil is used as the missing value. Basic data types such as int or float do not do this.
Swift extends the concept of missing values in base data types and reference types with Optional. A variable of type Optional that can hold a value or be nil at any time.
Question 2- Swift 1.0 or later
In Swfit, when do you use structs and when do you use classes?
Answer: There has always been a debate about whether classes are better than structures or whether structures are better than classes. Functional programming favors value types, object-oriented programming favors classes.
In Swift, classes and structures have many different properties. Here’s a summary of the differences:
Classes support inheritance, structs do not.
Classes are reference types and structs are value types
There are no general rules for deciding which structure or class is more useful. The general advice is to use minimal tools to accomplish your goals, but a good rule of thumb is to use structures unless you use inheritance and reference semantics.
To learn more, click here.
Note: At run time, structs are better than classes in terms of performance because structs’ method calls are statically bound, while classes’ method calls are dynamically implemented. This is another good reason to use structs instead of classes whenever possible.
Question 3- Swift 1.0 or later
What are generics? What problems are generics designed to solve?
Answer: Generics are a type used to make types and algorithms work safely. In Swift, generics can be used in both functions and data structures, such as classes, structures, and enumerations.
Generics are generally used to solve the problem of code reuse. A common situation is that you have A function that takes A parameter of type A, and when the parameter type changes to B, you have to copy the function.
For example, the second function in the following code copies the first function — it simply replaces the Integer type with String.
func areIntEqual(x: Int, _ y: Int) -> Bool { return x == y} func areStringsEqual(x: String, _ y: String) -> Bool { return x == y} areStringsEqual("ray", "ray") // trueareIntEqual(1, 1) // true
Copy the code
An Objective-C developer might come up with the NSObject class to solve this problem, as follows:
import Foundation func areTheyEqual(x: NSObject, _ y: NSObject) -> Bool { return x == y} areTheyEqual("ray", "ray") // trueareTheyEqual(1, 1) // true
Copy the code
This code works as expected, but it is not secure at compile time. It allows strings to be compared to integers, like this:
areTheyEqual(1, "ray")
Copy the code
The application will not crash, but allowing strings to be compared to integers may not be the desired result.
By using generics, you can combine the two functions into one while maintaining type safety. Here is the code implementation:
func areTheyEqual(x: T, _ y: T) -> Bool { return x == y} areTheyEqual("ray", "ray")areTheyEqual(1, 1)
Copy the code
The above example tests the equality of two parameters whose types are constrained by the Equatable protocol. The above code achieves the desired result and prevents passing different types of parameters.
Question 4- Swift 1.0 or later
When do you have to use implicit unpacking? Explain why.
Answer: The most common reasons for using implicit unpacking for optional variables are as follows:
1. Object properties cannot be nil when initialized, otherwise they cannot be initialized. A typical example is a property of type Interface Builder Outlet, which is always initialized after its owner has initialized it. In this particular case, make sure it’s not nil, assuming it’s configured correctly in the Interface Builder — before an outlet is used.
Solve the loop problem of strong references – when two instance objects refer to each other and the value of the referenced instance object cannot be nil. In this case, one side of the reference can be marked as unowned and the other side uses implicit unpacking.
Suggestion: Do not use implicit unpacking for option types unless necessary. Improper use increases the likelihood of run-time crashes. In some cases, crashes may be intentional behavior, but there are better ways to achieve the same result, for example, by using the fatalError() function.
Question 5- Swift 1.0 or later
How many ways can I unpack an optional variable? And evaluate it in terms of safety.
The answer:
- Forced unpacking! Operator — unsafe
- Implicit unpacking variable declarations – unsafe in most cases
- Optional binding – Security
- Optional chaining — Safe
- Nil coalescing operator (null value merge operator) — security
- Swift 2.0 features guard statements — security
- Swift 2.0 optional Pattern — Security (supported by @kametrixom)
The intermediate
Question 1- Swift 1.0 or later
Is Swift an object-oriented programming language or a functional programming language?
Answer: Swift is a hybrid programming language that includes both programming modes. It implements three basic principles of object orientation:
- encapsulation
- inheritance
- polymorphism
Speaking of Swift as a functional programming language, we have to talk about what is functional programming. There are many different ways to define functional programming languages, but they all mean the same thing.
The most common definition comes from Wikipedia:… It’s a programming specification… It treats computer operations as mathematical functions, avoiding state changes and data changes.
Swift is hardly a full-fledged functional language, but it already has the basics.
Question 2- Swift 1.0 or later
Are the following features included in Swift?
1. Generic classes
2. Generic structures
3. Generic protocols
The answer:
- Swift includes features 1 and 2. Generics can be used in classes, structures, enumerations, global functions, or methods.
- 3 is implemented through the TypeAlias section. Typealias is not a generic type; it is just a placeholder name. It is usually referenced as an association type and is defined only when the protocol is referenced by a type.
Question 3- Swift 1.0 or later
In Objective-C, a constant can be defined like this:
const int number = 0;
A similar Swift is defined like this:
let number = 0
Is there any difference between the two? If yes, please explain why.
A const constant is a variable that is initialized at compile time or compile-parse time. What is created through the let is a runtime constant that cannot be changed. It can be initialized using either the stattic or dynamic keyword. Remember that its value can only be assigned once.
Question 4- Swift 1.0 or later
To declare a static property or function, we often use the static modifier of the value type. Here is an example of a structure:
struct Sun {
static func illuminate() {}
}
For a class, either the static or class modifier is acceptable. They have the same effect, but are fundamentally different. Can you explain why it’s different?
The answer:
Static modified properties or modified functions cannot be overridden. But with the class modifier, you can override properties or functions.
When static is applied to a class, static becomes an alias for class final.
For example, in the code below, the compiler emits an error when you try to override illuminate() :
class Star { class func spin() {} static func illuminate() {}} class Sun : Star { override class func spin() { super.spin() } override static func illuminate() { // error: Class method overrides a 'final' class method super.illuminate()}}Copy the code
Question 5- Swift 1.0 or later
Can you save an attribute with extension? Please explain why.
Answer: No. Extensions can add new behavior to the current type, but cannot change the type or its interface. If you add a new storable property, you need extra memory to store the new value. Extensions do not accomplish this task.
senior
Question 1- Swift 1.2
In Swift1.2, can you explain the problem with using generics to declare enumerations? For example, the Either enumeration has two generic types, T and V. T is used when the associative type is left, and V is used when the associative value is rihgt:
enum Either{ case Left(T) case Right(V)}
Copy the code
Tip: verify the above conditions in the Xcode project, not in Playgroup d. Also note that this issue is related to Swift1.2, so Xcode must be at least 6.4.
Answer: The above code generates a compilation error:
unimplemented IR generation feature non-fixed multi-payload enum layout
Copy the code
The problem is that the memory size of T cannot be determined upfront because it depends on the T type itself, but the enum case requires a fixed size payload.
The most common workaround is to wrap generic types around reference types, usually called boxes, as follows:
class Box{ let value: T init(_ value: T) { self.value = value }} enum Either{ case Left(Box) case Right(Box)}
Copy the code
This problem occurred in Swift1.0 and later versions, but was resolved in Swift2.0.
Question 2- Swift 1.0 or later
Are closures a reference type?
A closure is a reference type. If a closure is assigned to a variable that is copied to another variable, they reference the same closure and their capture list is copied.
Question 3- Swift 1.0 or later
The UInt type is used to store unsigned integers. The following code implements an initializer for a signed integer conversion:
init(_ value: Int)
Copy the code
However, in the following code, it generates a compile-time error when you give a negative value:
let myNegative = UInt(-1)
Copy the code
We know that the internal structure of a negative integer is a positive number using the binary complement. How can we convert a negative integer into an unsigned integer while keeping the memory address of the negative integer unchanged?
Answer: Use the following initialization methods:
UInt(bitPattern: Int)
Copy the code
Question 4- Swift 1.0 or later
Describes a situation where circular references occur in Swift, and how to resolve it.
A circular reference occurs when two instance objects have strong references to each other, causing a memory leak because neither object can be freed. As long as an object is strongly referenced by another object, that object cannot be released, and each object keeps the other due to strong references.
The solution to this problem is to break the loop by replacing a strong reference with an weak or unowned reference.
Question 5- Swift 2.0 or later
Swift2.0 adds a new keyword to enable recursive enumeration. The following example is an enumerated type that has two associated value types T and List under the Node condition:
enum List{ case Node(T, List) }
Copy the code
What keywords allow recursive enumeration?
The indirect key values can allow recursive enumerations as follows:
enum List{ indirect case Cons(T, List) }
Copy the code
Where To Go From Here?
Congratulations on making it to the end of the article, and don’t feel bad if you don’t know the answers to all the questions.
Because some of the questions above are complicated, and Swift is an expressive language, we still have a lot to learn. Plus, Apple keeps improving Swift with new features, so even the best learners won’t know everything.