How to create a calculator in Swift 5

In anticipation of the start of the basic course "iOS developer", we publish an article written by our freelance author.







Hello! More than a year has passed since the release of Swift 5, which brought a lot of new things to developers. In this article I want to talk about mobile development for IOS, how it works, what is needed for this, and much more. The article is intended for people who are just starting their programming in Swift 5 .



Operating system and hardware requirements



One way or another, in order to build an application for IOS of any version, you need a computer running the Mac OS operating system (and preferably the latest version, otherwise some part of the developer's tools and Xcode may start working completely unpredictable). The need for a system running Mac OS is the cause of controversy and hatred from other developers who are not used to being limited in their capabilities because of the operating system. Most often, there are several ways: buying or assembling a Hackintosh (however, in the case of self-assembly, I want to warn you that it will not be easy to assemble such a computer without a constant driver problem). I have seen both installing an operating system image into a virtual machine, and rolling Mac OS onto a regular laptop, without any driver problems.However, this path will require some hardware skills from you and threatens to lack 100% support for future versions of Mac OS.



An alternative way, of course, is to buy a computer originally from Apple. If you wanted a laptop, then you probably know what to do (but I want to warn you right away that Xcode immediately takes about 25 gigabytes, and it can easily take up all 44 gigabytes if you download additional simulators to devices. the size of 128 gigabytes should be only for IOS development without any additional things like node_modules, Pycharm and Unity cache, homebrew, and other stuff for developers, which takes up a ton of disk space. If you are going to do something else, you need a disk at least from 256 gigabytes or more).



Development environment options



In addition to the more or less classic way of developing applications in Xcode using Swift and using the Cocoa and CocoaTouch libraries, now there are a lot of other ways of developing almost without using Xcode (only without Xcode you can no longer build an application). There are several technologies:



  • Xamarin . Applications on this platform are written using C #. With Xamarin, you can create any native Android or IOS application. Development can be done using Visual Studio. Despite such advantages, most likely. some application fragments will need to be written separately for each platform
  • React Native. React , -. . , - , - . , .
  • Flutter. , Flutter Dart Google. , , . , Flutter β€” React Native, . Dart, -
  • PhoneGap/Cordova. Nitobi, Adobe. , PhoneGap, Apache Cordova, WebView,
  • Unity. IOS, . , . gamedev.




Apple recommends using the Swift programming language for developing applications. Swift is a relatively new programming language that was not officially released until 2014. It can be used for development for Mac OS, IOS, and there is also support for Linux (so if you have, say, not very specific Linux, you can safely download and try the language, for example, from this link).



Swift itself is a typical new generation language, such as Golang.

Initially, the language was conceived as an easier-to-read and error-resistant language for the programmer than Objective C. At the same time, Swift can work within the same project with both C and Objective C.



Instead of trying to give a description of this language (which at first glance is C ++, just modified to modern realities with a fashionable automatic typing function), I suggest the reader to study the very nice documentation from Apple, which describes in detail how the language works and what is its syntax. The English version can be found here , the Russian translation can be found here . After you get familiar with the basics of the Swift language, we can move on to what we are here for today - creating our simple calculator using Xcode.



Creating a calculator



To create an application, we need Xcode, which can be downloaded for free from the AppStore. Don't be intimidated by its rating - despite the fact that the first five reviews give 1 star, this does not mean that you will be shocked. Perhaps the syntax and hints are really not included too quickly when editing - but in general, Xcode left me many times more favorable impressions than the same Android Studio (although maybe I just don't know how to cook it). If you suddenly have a desire to try development outside of Xcode and you prefer JetBrains products, then you can try AppCode - it supports interoperability with Xcode, working with Swift and Objective C, and many other nice features. I personally have not tried it, but if you have a subscription to all the software from JetBrains - why not download and run it.



So you've installed Xcode. Now you can start developing. Start a new project and select Single Page Application:







After that, you will be prompted to enter data about your application. If this is your first time launching Xcode, you will need to enter Apple Id there. After that, you must fill in the information about the name of your project (in our case, just Calculator) and the name of your company and application. You can write whatever you want here if you do not intend to publish this application in the future. I chose Swift as the language, and Storyboard as the User Interface. I have thrown out the tests so far because I'm great , because there is really nothing to test here.







After we have created our application, you can go to the file inCalculator.xcodeprojand tweak any settings if you see fit. For now, I left everything as it is, developing for the latest version of IOS 13.6 for Iphone and Ipad. In principle, you can exclude the iPad for now - our interface will most likely not look very good on it. However, I want to warn you that if suddenly you publish - Apple employees are testing applications for the Iphone for verification, so that they are at least functional on the Ipad. But before that, you still have to spend $ 99 on developer keys).



After you've created the application, you can immediately call the emulator in order to track what happens. To do this, you can simply press the CMD + R key combination. At the top left, you can select the devices on which you run the emulator, and you can also connect your real physical device via a cable and test immediately on it).



There are many ways to create an interface and widgets in it, I will use the neutral option - create a main holder, place it on the entire screen, and then programmatically start positioning my widgets. Therefore, first we go to the file Main.storyboardand make the main View black, in order to more conveniently place our elements:







After that, we will add a View, with which we will mainly work. To do this, click on the plus sign on the top right, through which you can add widgets, and add a new widget, type uiview in the search :







After that, we drag this widget to the main screen, and we need to expand it to full screen. For this we need to work with constaint. To do this, click on the icon at the bottom left, which looks a bit like Darth Vader's ship, and assign 0 on each side:







After that, your new widget will expand to fit the entire screen. Next, just like last time, we need to change the color of our widget, only now to Clear Color so that it doesn't interfere with us and we can place widgets in it.



Now you can go to the fileViewController.swift, in which we will have all the rest of the programming. First, we need to use a special marker @IBOutletin order to be able to link the Storyboard to our code. To do this, we must write the following line:



@IBOutlet var holder: UIView!


Now we can link the code to the widget. To do this, in fact, you need to connect our holder with the Holder. To do this, right-click on viewControllerand drag holder onto our screen:







Finally, we have finished linking the code to the Storyboard and we can start programming.



Next, we will add two variables, the first of which will be just a number into which the first value can be written, and the second will be the resulting value. The third variable will be a little more specific, because we will use an optional declaration (you can read what kind of animal it is, you can read more here). Optional can contain any value or nil. Optionals also ensure that nil values ​​are explicitly processed. In addition, we will add from the very beginning a listing of the mathematical operations that the calculator supports:



    var firstNumber = 0
    var resultNumber = 0
    var currentOperations: Operation?
        enum Operation {
        case add, subtract, multiply, divide
    }


Next, we have to create a Label, in which we will show the numbers and the result of calculations. By default, there will be 0 and a fairly large font. Everything else, I think, is perfectly clear:



    private var resultLabel: UILabel = {
        let label = UILabel()
        label.text = "0"
        label.textColor = .white
        label.textAlignment = .right
        label.font = UIFont(name: "Helvetica", size: 100)
        return label
    }()



After that, skipping the built-in method that calls us rendering (I'm talking about viewDidLoad), we need to call a method that will call a function that will draw all the buttons on which the handler functions will hang.



    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()

        setupNumberPad() //,      
    }


After that, we have the function setupNumberPad. First, I will set a constant for the size of our font, so that later, if anything, you can immediately increase / decrease the font size in the application, because I work without a layout. After that I will create a button size - its width will be equal to a quarter of the screen size of our application.



    private func setupNumberPad() {
        let FontSize:CGFloat = 25 
        //      
        let buttonSize: CGFloat = view.frame.size.width / 4 
        //    1/4
        let zeroButton = UIButton(frame: CGRect(x: 0, y: holder.frame.size.height-buttonSize, width: buttonSize*3, height: buttonSize))
        //  UIButton     
        zeroButton.setTitleColor(.black, for: .normal) 
        //    
        zeroButton.backgroundColor = .white
        //   
        zeroButton.setTitle("0", for: .normal) 
        //    0
        zeroButton.titleLabel?.font = UIFont(name: "Helvetica", size: FontSize)
        // , family    
        zeroButton.tag = 1 
        //         
        holder.addSubview(zeroButton)  //    holder 
        zeroButton.addTarget(self, action: #selector(zeroTapped), for: .touchUpInside) 
        //       
 


0 takes up a third of the screen so that we can go to the right column for mathematical operands. Next, we need to render all the buttons in some way. Of course, it would be possible to draw them one by one, but then it will turn out to be long and dreary. Because we will just have a series of numbers from 1 to 9, then the decision to use cycles is quite on the surface. I will give the first cycle with comments, and since the other two are essentially a repetition, I will give them just under the cut:



        for x in 0..<3 {
            let button_row_1 = UIButton(frame: CGRect(x: buttonSize * CGFloat(x), y: holder.frame.size.height-(buttonSize*2), width: buttonSize, height: buttonSize))
            //   x     x
            button_row_1.setTitleColor(.black, for: .normal) //
            button_row_1.backgroundColor = .white // 
            button_row_1.setTitle("\(x+1)", for: .normal) //  
            holder.addSubview(button_row_1) //    
            button_row_1.tag = x+2 // .. 1  ,   2
            button_row_1.addTarget(self, action: #selector(numberPressed(_:)), for: .touchUpInside)
            // 
        }


The rest of the code of our numbers




       for x in 0..<3 {
            let button_row_2 = UIButton(frame: CGRect(x: buttonSize * CGFloat(x), y: holder.frame.size.height-(buttonSize*3), width: buttonSize, height: buttonSize))
            button_row_2.setTitleColor(.black, for: .normal)
            button_row_2.backgroundColor = .white
            button_row_2.setTitle("\(x+4)", for: .normal)
            button_row_2.addSubview(button_row_2)
            button_row_2.tag = x+5
            button_row_2.addTarget(self, action: #selector(numberPressed(_:)), for: .touchUpInside)
        }
        
        for x in 0..<3 {
            let button_row_3 = UIButton(frame: CGRect(x: buttonSize * CGFloat(x), y: holder.frame.size.height-(buttonSize*4), width: buttonSize, height: buttonSize))
            button_row_3.setTitleColor(.black, for: .normal)
            button_row_3.backgroundColor = .white
            button_row_3.setTitle("\(x+7)", for: .normal)
            holder.addSubview(button_row_3)
            button_row_3.tag = x+8
            button_row_3.addTarget(self, action: #selector(numberPressed(_:)), for: .touchUpInside)
        }
    




After that, we need to place our CE button, on which we will reset the data that was entered. We will place it at the top, and we will describe its functional load a little later. For now, we only need to position it and connect the handlers:



        let clearButton = UIButton(frame: CGRect(x: 0, y: holder.frame.size.height-(buttonSize*5), width: view.frame.size.width - buttonSize, height: buttonSize))
        clearButton.setTitleColor(.black, for: .normal)
        clearButton.backgroundColor = .init(red: 0, green: 2, blue: 0.8, alpha: 1) //       rgb
         clearButton.titleLabel?.font = UIFont(name: "Helvetica", size: FontSize-4) //     
        clearButton.setTitle("CE", for: .normal)
        holder.addSubview(clearButton) //     holder
        clearButton.addTarget(self, action: #selector(clearResult), for: .touchUpInside) //  


We are done with this boring repeating part, now we are ready for another thing - our operands with which we can perform mathematical operations. To begin with, we put the necessary operands inside the array, from where we will take them. We will place the operand buttons themselves in a column and add a handler function that will react to pressing our operands. I will make the buttons in a pleasant color of childish surprise, yellow, and the size is a little larger than our numbers.



        let operations = ["=","+", "-", "x", "Γ·"] //  

        for x in 0..<5 {
            let button_operand = UIButton(frame: CGRect(x: buttonSize * 3, y: holder.frame.size.height-(buttonSize * CGFloat(x+1)), width: buttonSize, height: buttonSize))
            button_operand.setTitleColor(.black, for: .normal)
            button_operand.backgroundColor = .init(red: 2, green: 0.8, blue: 0, alpha: 1) // 
            button_operand.setTitle(operations[x], for: .normal)
            holder.addSubview(button_operand)
            button_operand.tag = x+1 
            // ,       
            button_operand.titleLabel?.font = UIFont(name: "Helvetica", size: FontSize)
            button_operand.addTarget(self, action: #selector(operationPressed(_:)), for: .touchUpInside)
        }


After these global operations, we just need to position the Label, in which we will write the result, and close the function:



    resultLabel.frame = CGRect(x: 20, y: clearButton.frame.origin.y - 110.0, width: view.frame.size.width - 40, height: 100)
    holder.addSubview(resultLabel)
} //    


Now you can move on to the handlers:



Working with handlers



All this was essentially just a layout, now we have to breathe logic into the application. To do this, we will use methods from the Objective C runtime to simplify our code. If you do not understand what is happening, I can recommend this article for you to read.



So, here are our functions:



    @objc func clearResult() {
        resultLabel.text = "0" //    0
        currentOperations = nil //    
        firstNumber = 0 //      0
    }
    
    @objc func zeroTapped() {
        //    
        if resultLabel.text != "0" {
            if let text = resultLabel.text {
                resultLabel.text = "\(text)\(0)" //  
            }
        }
    }


Next, we need to add a handler function to our buttons:



    @objc func numberPressed(_ sender: UIButton) {
        let tag = sender.tag - 1
        
        if resultLabel.text == "0" {
            resultLabel.text = "\(tag)"
        }
        else if let text = resultLabel.text {
        //   
            resultLabel.text = "\(text)\(tag)"
        }
    }



Next up is the most important business logic of our application. We'll use the switch construct to control our math operations:



 @objc func operationPressed(_ sender: UIButton) {
        let tag = sender.tag
        
        if let text = resultLabel.text, let value = Int(text), firstNumber == 0 {
            //   
            firstNumber = value
            resultLabel.text = "0"
        }
        
        if tag == 1 {
            if let operation = currentOperations {
                var secondNumber = 0
                if let text = resultLabel.text, let value = Int(text) {
                    secondNumber = value
                }
                
                switch operation {
                case .add:
                    
                    firstNumber = firstNumber + secondNumber
                    secondNumber = 0 //  
                    resultLabel.text = "\(firstNumber)" 
                    currentOperations = nil
                    firstNumber = 0 //     Label 
                    
                    break
                    
                case .subtract:
                    firstNumber = firstNumber - secondNumber
                    secondNumber = 0
                    resultLabel.text = "\(firstNumber)"
                    currentOperations = nil
                    firstNumber = 0
                    
                    break
                    
                case .multiply:
                    firstNumber = firstNumber * secondNumber
                    secondNumber = 0
                    resultLabel.text = "\(firstNumber)"
                    currentOperations = nil
                    firstNumber = 0
                    
                    break
                    
                case .divide:
                    firstNumber = firstNumber / secondNumber
                    secondNumber = 0
                    resultLabel.text = "\(firstNumber)"
                    currentOperations = nil
                    firstNumber = 0
                    break
                }
            }
        }
        else if tag == 2 {
            currentOperations = .add 
            //     .    ,    
        }
        else if tag == 3 {
            currentOperations = .subtract
        }
        else if tag == 4 {
            currentOperations = .multiply
        }
        else if tag == 5 {
            currentOperations = .divide
        }
    }
}



That's all! The source code for this application can be found at this link. As a result, the appearance turned out like this:







By tradition, I will give several useful resources that may be useful to a beginner IOS developer:








A quick start to iOS development. Free webinar







All Articles