Manjusaka

Manjusaka

Good and Bad, A Comprehensive Look at Swift Part 2

Not long ago, in my article Good and Bad, A Comprehensive Look at Swift Part 1, I introduced some tips on how to write excellent code in Swift. In the two years since Swift was released, I have spent a long time mastering the best practices. For more details, please read this article: Good and Bad, A Comprehensive Look at Swift Part 1.

In this series of articles, I will try to extract the good and bad parts of the Swift language. Well, I also hope to have excellent Swift in the future to help me conquer Swift (well, young man, don't look, the central government has decided it's you, recite a poem quickly). If you have any ideas or want to share some life experiences as a developer, please contact me on Twitter. My account is ksmandersen.

Enough nonsense, let's start today's lesson.

guard is great for guarding your code#

In Swift 2.0, Swift introduced a set of features that may be unfamiliar to developers. The guard statement plays a significant role in defensive programming. (Translator's note 1: Defensive programming is a specific embodiment of defensive design, which is to ensure that the program will not be damaged by unforeseen use of the program. It can be seen as an idea to reduce or eliminate the effectiveness of Murphy's Law. Defensive programming is mainly used in programs that may be abused, pranked, or inadvertently cause catastrophic effects. Sourced from Wikipedia). Every Objective-C developer may be familiar with defensive programming. By using this technique, you can ensure that your code does not throw exceptions when dealing with unexpected input data.

The guard statement allows you to set conditions and rules for the following code, and you must specify how to handle these conditions (or rules) when they are not met. In addition, the guard statement must return a value. In early Swift programming, you may use if-else statements to handle these cases in advance. However, if you use the guard statement, the compiler will help you handle exceptional data when you forget to consider certain situations.

The following example is a bit long, but it is a very good example of the use of the guard statement. The didPressLogIn function is called when the button on the screen is clicked. We expect that when this function is called, if there are additional requests in the program, no additional logs will be generated. Therefore, we need to do some preprocessing of the code. Then we need to validate the log. If this log is not what we need, we don't need to send it. But more importantly, we need to return an executable statement to ensure that we don't send this log. The guard statement will throw an exception when we forget to return.

    @objc func didPressLogIn(sender: AnyObject?) {
            guard !isPerformingLogIn else { return }
            isPerformingLogIn = true

            let email = contentView.formView.emailField.text
            let password = contentView.formView.passwordField.text

            guard validateAndShowError(email, password: password) else {
                isPerformingLogIn = false
                return
            }

            sendLogInRequest(ail, password: password)
    }

When let is used in conjunction with guard, it works wonders. In the following example, we will bind the result of the request to a variable user, and then use it in the finishSignUp method. If result.okValue is empty, the guard statement will take effect. If it is not empty, this value will be assigned to user. We use where to restrict the guard statement.

    currentRequest?.getValue { [weak self] result in
      guard let user = result.okValue where result.errorValue == nil else {
        self?.showRequestError(result.errorValue)
        self?.isPerformingSignUp = false
        return
      }

      self?.finishSignUp(user)
    }

To be honest, guard is very powerful. Well, if you haven't used it yet, then you should really consider it.

Declare and configure subviews at the same time.#

As mentioned in the previous articles, when developing views, I am more accustomed to generating code. Because I am familiar with the configuration of views, I can quickly locate the problem when there are layout issues or improper configurations.

During the development process, I found it important to put different configuration processes together. In my early Swift programming experience, I usually declared a configureView function and put the configuration process here during initialization. But in Swift, we can use property declaration code blocks to configure views (actually I don't know what to call this (escape)).

Well, in the example below, there is an AwesomeView view that contains two subviews, bestTitleLabel and otherTitleLabel. The configuration process for both subviews is done in one place. We integrate the configuration process in the configureView method. Therefore, if I want to change the textColor property of a label, I know exactly where to make the modification.

    class AwesomeView: GenericView {
        let bestTitleLabel = UILabel().then {
            $0.textAlignment = .Center
            $0.textColor = .purpleColor()tww
        }

        let otherTitleLabel = UILabel().then {
            $0.textAlignment = .
            $0.textColor = .greenColor()
        }

        override func configureView() {
            super.configureView()

            addSubview(bestTitleLabel)
            addSubview(otherTitleLabel)

            // Configure constraints
        }
    }

For the above code, I don't like the type label when declaring the label, and then initializing and returning a value in the code block. By using the Then library, we can make a small improvement. You can use this small function to associate code blocks with the declaration of objects in your project. This reduces redundant declarations.

    class AwesomeView: GenericView {
        let bestTitleLabel = UILabel().then {
            $0.textAlignment = .Center
            $0.textColor = .purpleColor()tww
        }

        let otherTitleLabel = UILabel().then {
            $0.textAlignment = .
            $0.textColor = .greenColor()
        }

        override func configureView() {
            super.configureView()

            addSubview(bestTitleLabel)
            addSubview(otherTitleLabel)

            // Configure constraints
        }
    }

Classify class members by different access levels.#

Well, recently, something important happened to me. I combined the members of classes and structures using a special method. This is a habit I developed when developing with Objective-C. I usually put private methods at the bottom, followed by public and initialization methods. Then I place the properties in the order of public properties to private properties in the code. Well, you can organize your code according to the following structure.

  • Public properties
  • Inline properties
  • Private properties
  • Initialization container
  • Public methods
  • Inline methods
  • Private methods

You can also sort them by static/class properties/constants. Different people may add different things based on this. But for me, I always program according to the above method.

Well, that's the end of this issue. If you have any good ideas or something to say, please feel free to contact me through the contact information below the screen. Of course, you are welcome to use this method to tip me with coins or bananas and subscribe to my articles (heavy fog).

Next episode preview: I will continue to talk about the bits and pieces in Swift. Don't go away, the next episode will be even more exciting.

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.