Showing posts with label syntax. Show all posts
Showing posts with label syntax. Show all posts

Saturday, May 27, 2017

How to Sort Array, Dictionary, and Array of Tuples

The code below shows how to sort an array, a dictionary or an array of tuples in Swift 3.1 with Xcode 8.3.1 Playground. Sorting can be done in ascending or descending order. A dictionary can be sorted by key or by value.

Note: When sorting a dictionary, the returned type is an array of tuples.

//Array
let array = [3, 5, 9, 7, 4, 1, 2]

let arrayInc = array.sorted()
let arrayDec = array.sorted(by: >)

//Dictionary
let dict = ["A": 123, "B": 789, "C": 567, "D": 432]

print(dict)

let dictKeyInc = dict.sorted(by: <)
let dictKeyDec = dict.sorted(by: >)

print(dictKeyInc)
print(dictKeyDec)

let dictValInc = dict.sorted(by: { $0.value < $1.value })
let dictValDec = dict.sorted(by: { $0.value > $1.value })

print(dictValInc)
print(dictValDec)

for item in dictValDec {
    print("key:\(item.key) value:\(item.value)")
}

//Array of Tuples
let tupleArray = [("A", 123), ("B", 789), ("C", 567), ("D", 432)]

let tupleArrayInc = tupleArray.sorted(by: { $0.1 < $1.1 })


print(tupleArrayInc)


Result:

["B": 789, "A": 123, "C": 567, "D": 432]
[(key: "A", value: 123), (key: "B", value: 789), (key: "C", value: 567), (key: "D", value: 432)]
[(key: "D", value: 432), (key: "C", value: 567), (key: "B", value: 789), (key: "A", value: 123)]
[(key: "A", value: 123), (key: "D", value: 432), (key: "C", value: 567), (key: "B", value: 789)]
[(key: "B", value: 789), (key: "C", value: 567), (key: "D", value: 432), (key: "A", value: 123)]
key:B value:789
key:C value:567
key:D value:432
key:A value:123
[("A", 123), ("D", 432), ("C", 567), ("B", 789)]

Reference

Sort Dictionary by Key Value
cannot assign value of type '[(string, string)]' to type '[string : string]'

Monday, May 22, 2017

Dictionary of Arrays in Swift 3

The code below shows how to include an array in a dictionary in Swift 3.1 with Xcode 8.3.1 Playground.

dictionarySemitones["abc"]=[1,2,3]
dictionarySemitones["def"]=[4,5,6]

print(dictionarySemitones)
print(dictionarySemitones["abc"]!)

Reference:

A Dictionary of Arrays in Swift

Sunday, May 21, 2017

Convert an Integer Array to a String

The code below shows how to convert an integer array to a string in Swift 3.1 with Xcode 8.3.1 Playground.

let arrayInt = [1, 2, 3, 4, 5]
let string = "\(arrayInt)"
print(string)

Reference:

How can I convert an Int array into a String? array in Swift

Conversion from Numbered Musical Notation to Musical Note Letters

The code below converts Numbered Musical Notation (簡譜) to musical note letters using Xcode 8.3.2 playground in Swift 3.1. Techniques used in the code involves:

1. Separating a string into an array
2. Type casting each array element into an integer

3. Converting the numerical notation into a matched letter
4. Joining all letters into a single string

//Twinkle, Twinkle, Little Star 一閃一閃亮晶晶
let numberedNotation = "1 1 5 5 6 6 5"

//1. Separating a string into an array let numberedNoteArray = numberedNotation.components(separatedBy: " ")

let lookupTable = ["C","D","E","F","G","A","B"]

var noteArray = [String]()

for note in numberedNoteArray {
    //2. Type casting each array element into an integer
    let noteInt = Int(note)!

    //3. Converting the numerical notation into a matched letter
    let noteChar = lookupTable[noteInt-1]
    noteArray.append(noteChar)
}

//4. Joining all letters into a single string let noteString = noteArray.joined(separator: " ")

print("\(noteString)")

Result:

C C G G A A G

Monday, July 11, 2016

Reverse Array in Swift 2.2/3.0

To reverse an array in Swift 2.2 with Xcode 7.3.1:

var array = ["a","b","c","d","e","f","g"]
        
array = array.reverse()
        

print(array)

To reverse an array in Swift 3 with IBM Swift Sandbox (Swift 3.0 June 20, 2016):

var array = ["a","b","c","d","e","f","g"]

array = array.reversed()


print(array)

Result:


Monday, May 16, 2016

Enumerations

The code below is tested with IBM Swift Sandbox (version 3.0-dev).

enum Numbers: Int {
    case zero, one, two, three, four, five
}

//show string
print(Numbers.one)
print(Numbers.three)
print(Numbers.five)
print("\n")

//show value
print(Numbers.one.rawValue)
print(Numbers.three.rawValue)
print(Numbers.five.rawValue)
print("\n")

//value to string
print(Numbers(rawValue: 3)!)
print(Numbers(rawValue: 4)!)
print(Numbers(rawValue: 5)!)
print("\n")

//Without the Int type
enum Names {
    case Tom, Jerry, Mickey, Donald
}

print(Names.Tom)
print(Names.Jerry)
print("\n")

//enumeration with function
func showName(name: Names) {
    print("I like \(name).")
}

showName(Names.Mickey)
showName(Names.Donald)

Console output:

one
three
five

1
3
5

three
four
five

Tom
Jerry

I like Mickey.
I like Donald.

Thursday, May 12, 2016

Swift Tip: Prevent code execution using #if false and #endif

To disable several lines of code in Swift, a useful method alternative to comment characters /* and */ is to use the # (number/hash/pound) sign plus if false and endif as below:

#if false
...
....code to be disabled....
... 
#endif

For example:

print("123")
#if false
print("456")
#endif

Result:

123

Tuesday, May 10, 2016

How to call functions in a separate Swift file

Update - May 22, 2017. The code below still works with Xcode 8.3.1 (Swift 3.1).

The code below shows how to call functions in a separate Swift file. Xcode 7.3 (Swift 2.2) is used. Two examples are shown in the following steps:

1. Create a new Swift file with any name such as MyFile.swift.

2. Modify the file as:


import Foundation

//Example 1
class MyClass {
    func myFun() {
        print("myFun!!")
    }
    static let myInstance = MyClass()
}

//Example 2
class AnotherClass {
    class func anotherFun() {
        print("anotherFun!!")
    }
}

3. Modify ViewController.swift as:


import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        MyClass.myInstance.myFun()
        
        AnotherClass.anotherFun()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}

Result of Debug Console:


myFun!!

anotherFun!!

Tuesday, March 29, 2016

Array of arrays - Multidimensional array

The following code has been tested with Xcode 7.3 playground:

let array : [[Int]] = [[1, 2, 3],[4, 5, 6]]

let element = array[0]

let digit1 = element[0]

let digit2 = array[0][1]

Result:


Monday, March 28, 2016

UIButton - Selector Warning (Update with Swift 3.1)

Update:
May 1, 2017:
Swift 3.1 with Xcode 8.3.2.

May 29, 2016:
The class name in the selector may be removed. Use #selector(buttonPressed) instead of #selector(ViewController.buttonPressed) for code simplicity.

On March 21, 2016, Apple released Xcode 7.3 with Swift 2.2. This new version of Swift is the first official release after the programming language became open source on December 3, 2015. The official Swift.org blog says that 212 non-Apple programmers have contributed to this release. Below is the first issue I face with Swift 2.2.

After I updated Xcode to Version 7.3, a warning appears with the UIButton code I normally use:

let button = UIButton()
.
.
button.addTarget(self, action: "buttonPressed", forControlEvents: UIControlEvents.TouchUpInside)

A warning is shown in front of the line number:


If I ignore the warning and continue to build the code, the UIButton still works perfectly.

By clicking the warning triangle, the warning description says that Use of string literal for Objective-C selectors is deprecated; use '#selector' instead.


Select the Fix-it Replace option.



Then the warning is disappeared as below:

button.addTarget(self, action: #selector(ViewController.buttonPressed), forControlEvents: UIControlEvents.TouchUpInside)


Update May 1, 2017 (Swift 3.1):

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        let button = UIButton(frame: CGRect(x: 0, y: 0, width: 200, height: 40))
        button.center = view.center
        button.setTitle("Press", for: UIControlState.normal)
        button.setTitleColor(UIColor.blue, for: UIControlState.normal)
        button.setTitleColor(UIColor.cyan, for: UIControlState.highlighted)
        button.addTarget(self, action: #selector(buttonPressed), for: UIControlEvents.touchUpInside)
        view.addSubview(button)
    }
    
    func buttonPressed() {
        print("button pressed!!")
    }

}

Update May 29, 2016 (Swift 2.2):

Remove the class name in the selector: #selector(ViewController.buttonPressed)and the complete UIButton code now becomes:


override func viewDidLoad() {
    super.viewDidLoad()
        
    let button = UIButton(frame: CGRectMake(0, 0, 200, 200))
    button.center = view.center
    button.setTitle("Press", forState: UIControlState.Normal)
    button.setTitleColor(UIColor.blueColor(), forState: UIControlState.Normal)
    button.setTitleColor(UIColor.cyanColor(), forState: UIControlState.Highlighted)
    button.addTarget(self, action: #selector(buttonPressed), forControlEvents: UIControlEvents.TouchUpInside)
    view.addSubview(button)
}
    
func buttonPressed() {
    print("button pressed!!")
}

Here is more explanation about the modification of Objective-C selectors in Swift 2.2:

Referencing the Objective-C selector of a method

More Information about modifications in Swift 2.2:

Swift 2.2 Released!(Official Swift.org blog)

Reference:

UIButton - Update button label when pressed

Tuesday, November 3, 2015

Using completion block to detect dismissViewControllerAnimated of ViewControllerB in ViewControllerA

Update: August 3, 2017 (Swift 3.1 + Xcode 8.3.3)
Original Post: November 3, 2015 (Swift 2)

If I have a default ViewControllerA, which presents ViewControllerB with 'OverCurrentContext' UIModalPresentationStyle, then I face a problem that 'viewWillAppear' in ViewControllerA is not called after ViewControllerB is dismissed. Consequently, it would be difficult for me to run some codes in ViewControllerA since I don't know when ViewControllerB is dismissed. 

Here is my original description to this problem:

iOS: Detect dismissViewControllerAnimated while using UIModalPresentationStyle.OverCurrentContext

In order to run some codes in ViewControllerA right after ViewControllerB is dismissed, a completion block is created in ViewControllerB. Then function myFuncInViewControllerA() in ViewControllerA can be executed at the right moment. The solution is as below:

Update: August 3, 2017 (Swift 3.1 + Xcode 8.3.3)

Remember to select ViewControllerA.swift as a custom class in the identify inspector in the storyboard after renaming ViewController.swift as ViewControllerA.swift.



ViewControllerA.swift:


import UIKit

class ViewControllerA: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let button = UIButton(frame: CGRect(x: (view.frame.width-200)/2, y: 50, width: 200, height: 20))
        button.setTitle("Button", for: UIControlState.normal)
        button.setTitleColor(UIColor.blue, for: UIControlState.normal)
        button.setTitleColor(UIColor.cyan, for: UIControlState.highlighted)
        button.contentMode = UIViewContentMode.center
        button.addTarget(self, action: #selector(btnPressed), for: UIControlEvents.touchUpInside)
        view.addSubview(button)
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        print("viewWillAppear")
    }
    
    func btnPressed() {
        let controllerB = ViewControllerB()
        controllerB.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
        controllerB.modalTransitionStyle = UIModalTransitionStyle.crossDissolve
        
        controllerB.dismissVCCompletion(){ () in
            self.myFuncInViewControllerA()
        }
        
        present(controllerB, animated: true, completion: nil)
    }
    
    func myFuncInViewControllerA() {
        print("Back to ViewControllerA!")
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}

ViewControllerB.swift:


import UIKit

class ViewControllerB: UIViewController {
    
    typealias typeCompletionHandler = () -> ()
    var completion : typeCompletionHandler = {}
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = UIColor(white: 0, alpha: 0.5)
        
        let viewB = UIView(frame: CGRect(x: 0, y: 0, width: view.frame.width*0.6, height: view.frame.height*0.6))
        viewB.center = view.center
        viewB.backgroundColor = UIColor.orange
        
        let buttonBack = UIButton(frame: CGRect(x: (viewB.frame.width-200)/2, y: 100, width: 200, height: 20))
        buttonBack.setTitle("Back", for: UIControlState.normal)
        buttonBack.setTitleColor(UIColor.blue, for: UIControlState.normal)
        buttonBack.setTitleColor(UIColor.cyan, for: UIControlState.highlighted)
        buttonBack.contentMode = UIViewContentMode.center
        buttonBack.addTarget(self, action: #selector(btnBackPressed), for: UIControlEvents.touchUpInside)
        viewB.addSubview(buttonBack)
        
        view.addSubview(viewB)
    }
    
    func btnBackPressed() {
        dismiss(animated: true, completion: {
            self.completion()
        })
    }
    
    func dismissVCCompletion(completionHandler: @escaping typeCompletionHandler) {
        self.completion = completionHandler
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

}

Result:


Original Post: November 3, 2015 (Swift 2)

ViewControllerA.swift:


class ViewControllerA: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        let button = UIButton(frame: CGRectMake(50, 100, 200, 20))
        button.setTitle("Button", forState: UIControlState.Normal)
        button.setTitleColor(UIColor.blueColor(), forState: UIControlState.Normal)
        button.setTitleColor(UIColor.cyanColor(), forState: UIControlState.Highlighted)
        button.addTarget(self, action: "btnPressed:", forControlEvents: UIControlEvents.TouchUpInside)
        view.addSubview(button)
        
    }
    
    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        print("viewWillAppear")
    }
    
    func btnPressed(sender: UIButton) {
        let controllerB = ViewControllerB()
        controllerB.modalPresentationStyle = UIModalPresentationStyle.OverCurrentContext
        controllerB.modalTransitionStyle = UIModalTransitionStyle.CrossDissolve
        
        controllerB.dismissVCCompletion(){ () in
            self.myFuncInViewControllerA()
        }

        presentViewController(controllerB, animated: true, completion: nil)
    }
    
    func myFuncInViewControllerA() {
        print("Back to ViewControllerA!")
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}


ViewControllerB.swift:

class ViewControllerB: UIViewController {

    typealias typeCompletionHandler = () -> ()
    var completion : typeCompletionHandler = {}
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = UIColor(white: 0, alpha: 0.5)
        
        let viewB = UIView(frame: CGRectMake(0,0,view.frame.width*0.6,view.frame.height*0.6))
        viewB.center = view.center
        viewB.backgroundColor = UIColor.orangeColor()

        let buttonBack = UIButton(frame: CGRectMake(30, 100, 200, 20))
        buttonBack.setTitle("Back", forState: UIControlState.Normal)
        buttonBack.setTitleColor(UIColor.blueColor(), forState: UIControlState.Normal)
        buttonBack.setTitleColor(UIColor.cyanColor(), forState: UIControlState.Highlighted)
        buttonBack.addTarget(self, action: "btnBackPressed:", forControlEvents: UIControlEvents.TouchUpInside)
        viewB.addSubview(buttonBack)
        
        view.addSubview(viewB)
    }
    
    func btnBackPressed(sender: UIButton) {
        dismissViewControllerAnimated(true, completion: {
            self.completion()
        })
    }
    
    func dismissVCCompletion(completionHandler: typeCompletionHandler) {
        self.completion = completionHandler
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

}

References: