Several people have complained to me about why there are so many question marks in Swift. And the exclamation mark (!). . Cha-ha, I faced the same problem when I first started writing swift.

Yesterday a friend sent me a line of code to show me how to write it:

let pageiid = (self.pageid? .intValue)! +1
Copy the code

This code looks pretty fucked up, but sadly, I wrote worse code when I first wrote Swift.

Since you all had this problem when you first started writing Swift. Let’s take a look today at how this code should be written to make us feel better.

As we all know, there are question marks. And the exclamation mark (!) What is the cause of? – Optional

I’m sure those of you who are going to try swift have at least seen or heard this is a big difference between SWIFT and OC. In my opinion, the biggest difference between SWIFT and OC, other than syntax changes, is optional. To take care of the newbie (I’m a newbie myself, after all). Let’s talk about it briefly.

What is Optional

There’s nothing to say about that, but in Swift Optional is actually an enumeration. If we were to implement something like this ourselves, the core code would look like this:

// This code is not important
public enum SYOptional<Wrapped> {
    
    case none
    case some(Wrapped)}Copy the code

This code is just telling you that there are only two cases of this enumeration. None means that this optional has no value, which means that it is nil. Another value. Some indicates that this optional has a value.

Why Apple introduced optional won’t be discussed here. Look at the following:

“Optional is a great feature of Swift. It completely solves the two philosophies of ‘have’ and ‘nothing’ that have plagued Objective-C for a long time, and also makes code more secure.”

Excerpt from: Wang Wei (Onevcat). “Swifter – Swift essential Tips (4th edition)”. iBooks.

I think optional is really a nice new feature in Swift.

Next, look at the Optional action symbols:?? /! /?

These are just some of the syntactic sugar in Swift. What does that mean? Let’s go back and forth.

?

When declaring a variable or attribute:

var optionalString: String?
Copy the code

The final? Indicates that this optionalString is an optional type. The String here? That means Optional

.

When using variables:

If you write it this way the compiler will give you an error,

optionalString.lowercased()
Copy the code

And the compiler will tell you to add one after the Option String, okay?

The question mark tells the compiler that this option String is an optional type.

class Person {
    var name: String!
    var son: Son!
}

class Son {
    var name: String?
}

var p: Person?

print(p? .son.name)// Playground: nil
Copy the code

This code right here says, if there’s nil somewhere in a line of code, that line of code is going to return nil. (This is a bit like sending messages to nil in OC). One of the nice things about this is that when you’re maintaining your code, you see, okay? I know that this thing is optional. That’s telling us that this thing could be empty while the program is running.

!

What’s next! . What does this have to do with? The same.

When declaring a variable or attribute:

var something: String!
Copy the code

There’s a name for this usage: implicit unpacking optional types. This is a special optional type that the compiler automatically unpacks when accessing its members or methods. The compiler will automatically add it for us! This notation. In our own words, it can be understood as follows:

** When declaring a variable or property, its value must not be empty if we know that the variable or property will be accessed during execution. You can then use implicit unpacking of optional types. ** If I had to give an example: I think I would give the example of XIB. Controls dragged from SB or XIB are declared this way.

When accessing a variable or attribute:

For an optional type, sometimes the compiler will remind us to add it after the object! Like the code my friend sent me in the beginning:

let pageiid = (self.pageid? .intValue)! +1
Copy the code

If a method needs to pass in an optional type as an argument. If you force an optional type to be passed. The compiler will report an error and remind us to add one after the optional type variable! . This is forced unpacking. This is equivalent to accessing the.some of the optional type directly.

??

This is just one sentence away, and this is the default value for this optional.

var optionalString: String?
var defaultValue = optionalString ?? "defaultValue"
Copy the code

DefaultValue is the value of the option String if it has a value. The reverse is “defaultValue”.

How to write Optional

I think I’ve covered some basic concepts. So how do you avoid all kinds of things in your code? The \! In the case. For beginners, actually. Almost all because the compiler prompts, and then automatically adds to the various? And! . I have to say, this code is pretty ugly. To solve this problem, it is of course important to know how Optional works.

Avoid Optional

After writing about it for a while, I realized that many times the use of optional didn’t make sense. Like the example my friend gave me. We can avoid using optional by setting an initial value

var pageid: Int = 0
Copy the code

This way you can avoid using optional and the following would not have happened. You can also use lazy loading:

lazy var tableView = UITableView(a)Copy the code

Make sure the property is initialized the first time it is used.

Of course, you can use implicit unpacking of optional types to avoid them in later code, right? The \!

But that’s not really encouraged.

Do not implicitly unpack optional types by default. You’ll probably forget about it in most scenarios. But there are special cases where this should be done to reduce compiler stress. And we need to understand the logic behind it.

How to access Optional

Since Optional is designed, it must be used in the coding process. So what can you do to avoid a situation like the one you started with Optional?

Again, look at this line of code:

let pageiid = (self.pageid? .intValue)! +1
Copy the code

If pageID is empty, forced unpacking will crash. How do I write this case? In addition to setting the initial value of the declaration, there is also a default value. There is also an Optional Map method to access Optioal:

if let optionalVal = optional {
 // do someThing
}
/ / equivalent to the
optional.map{ // do someThing }
Copy the code

There are also some snippets THAT I collected online that work very well: Add an extension for Optional:

extension Optional {}Copy the code

Add some methods: basically all from the GitHub library

require

You can force an Optional line not to be empty, otherwise an exception will be raised. This is equivalent to optimizing the exception message for forced unpacking:

    /// force this optional not to be empty
    ///
    /// This method returns the value of optional, or raises an error if optional is empty
    ///
    ///
    /// - Parameters:
    /// -hint: error message thrown for null
    ///
    /// - Returns: specifies the optional value.
	func require(hint hintExpression: @autoclosure(a) -> String? = nil,
                 file: StaticString = #file,
                 line: UInt = #line) -> Wrapped {
        guard let unwrapped = self else {
            var message = "required value was nil \(file), at line \(line)"
            if let hint = hintExpression() {
                message.append(". Debugging hit: \(hint)"#)}if! os(Linux)
            let exception = NSException(name: .invalidArgumentException,
                                        reason: message,
                                        userInfo: nil)
            exception.raise()
            #endif
            
            preconditionFailure(message)
        }
        return unwrapped
    }
Copy the code

or

    /// it is used instead of?? Operator, which makes writing more readable
    ///
    /// - Sample:
    // var a: String? = nil
    // let res = a.or("b")
    func `or`(value: Wrapped?) -> Optional {
        return self ?? value
    }
Copy the code

hasSome

/// check if the Optional is empty.
var hasSome: Bool {
    switch self {
    case .none: return false
    case .some: return true}}Copy the code

ifSome ifNone

    If optional is not empty, execute the closure and return the optional
	@discardableResult
    func ifSome(_ handler: (Wrapped) -> Void) - >Optional {
        switch self {
        case .some(let wrapped): handler(wrapped); return self;
        case .none: return self}}If optional is empty, execute the closure and return the optional
    @discardableResult
    func ifNone(_ handler: (a)- > () - >Optional {
        switch self {
        case .some: return self;
        case .none: handler(); return self}}Copy the code

conclusion

In order to avoid writing it all over, right? And! The basic knowledge of optional types in Swift is essential. It is also important to understand why the concept of optional types was introduced in Swift. When writing Swift code, we programmers need to be aware of the logic of the program at all times. When designing a class, we need to be aware of which properties are likely to be empty during its lifetime. Avoid using Optional options when you don’t have to, both to make your code logic more manageable and to make your code more beautiful. At least the compiler won’t have to make those nasty things step by step. It is a very happy thing to think clearly about logic, reasonable circumvention, and some small measures to make the code more beautiful. Optional can make code logic clearer and reduce the number of unnecessary crashes that can occur if improperly used.

Finally, I’ve always felt that if you know what Optional is and how to use Optional best, you’re basically getting into Swift.

Right friend code:

var pageiid: NSString?   // This is an attribute declaration
let pageiid = (self.pageid? .intValue)! +1  // This is the code inside a method
Copy the code
  • Why do I use NSString?
  • Why Optional
  • Why force unpacking?

Why NSString? I don’t know, he just said interface wants a string; Why Optional? I don’t know about that either; Why force unpacking? This I know, must be Xcode automatically help him to change 😂

Then I changed it to this:

var pageid: Int = 0 
self.pageid +=1
"\ [self.pageid)"
Copy the code

The default value for initialization is 0, avoiding Optional use and forcing unpacking later.

Int instead of NSString. One, I don’t want to use NSString, and two, in business logic, this value should be int

Where the interface assembles parameters, int is converted to a string. This logic should be interface business, not business layer logic.