페이지

2017년 2월 17일 금요일

Swift mutating

Modifying Value Types from Within Instance Methods Structures and enumerations are value types. By default, they cannot be modified from within its instance Methods However, if you want, you can opt in to "mutating" keyword. mutating The mutating keyword is added to its definition to enable it to modify its properties.


struct RectST {
    var x : Double = 0
    func minus(x dx:Int ){
       x -= dx     error: Left side of mutating operator isn't mutable: 'self' is immutable
    }
    mutating func move (x dx:Double){
        x += dx
    }
    mutating func moveSelf(x dx:Double){
        self = RectST(x:dx)
    }
}

class Rect {
    var x : Double = 0
    func move (x dx:Double){
        x += dx
    }
}

var c01 = RectST()
c01.minus(x:3)
c01.move(x:222) 

enum TriStateSwitch {
    case off,low,high
    mutating func next(){
        switch self {
            case .off:
                self = .low
            case .low:
                self = .high
            case .high:
                self = .off
                
        }
    }

}

Swift Lazy, Computed, Observers Properties

//1. Lazy Stored Properties

class DataImporter {
    var fileName = "data.txt"
}

class DataManager {
    lazy var importer = DataImporter()
    var data = [String]()
}



var m = DataManager()
m.data.append("data 1 ")
m.data.append("data 2 ")
//m.importer has not yet been created.
print( m.importer.fileName )
//m.importer has been created now.









//2. Computed Properties

struct Point {
    var x = 0.0, y = 0.0
}

struct Size {
    var width = 0.0, height = 0.0
}



struct Rect {
    var origin = Point()
    var size = Size()
    var center : Point {

        get {
            let tmpx = origin.x + size.width/2
            let tmpy = origin.y + size.height/2
            return Point(x:tmpx,y:tmpy)

        }

        // set {
        //     origin.x = newValue.x - size.width/2
        //     origin.y = newValue.y - size.height/2
        // }

     

        // renaming newCenter as newValue
        set ( newCenter ){
            origin.x = newCenter.x - size.width/2
            origin.y = newCenter.y - size.height/2
        }
    }
}



var r = Rect(origin:Point(x:10,y:10), size:Size(width:20,height:20))
print( r.center)



// 3. setter, getter

class Test {
   var _power : Double = 0.0
   var power : Double {
        get {
            return _power
        }

        set (newValue){
            _power = newValue
        }
    }
}







/* 4.Property Objservers


willSet is called just before the value is stored.
didSet is called immediately after the new value is stored.”

*/



class Sample {
    var force : Int = 0 {
        willSet(newV){
            print("\(force) -> \(newV)")
        }

        didSet {
            print("\(oldValue) -> \(force)")
        }
    }
}


var s = Sample()
print(s.force)
s.force = 12
print(s.force)

swift class and struct

Class have additional capablities that sturctures do not
 - Inheritance enables one class to inherit the characteristics of another. 
- Type casting enables you to check and interpret the type of a class instance at runtime. 
- Deinitializers enable an instance of a class to free up any resources it has assigned. 
- Reference counting allows more than one reference to a class instance. 

 Structures are always copied when they are passed around in your code, and do not use reference counting.

struct Resolution {
    var width = 0
    var height = 0
}

class VideoMode {
    var resolution = Resolution()
    var interlaced = false
    var framerate = 0.0
    var name: String?
}


var hd = Resolution(width:30,height:100)
var tmpHd = hd
tmpHd.width = 120


//sturct and enumeration are value types
print("sturct  \(hd.width) != \(tmpHd.width). copied")
var c = VideoMode()
c.resolution.width = 200
c.resolution.height = 300

var tmpC = c
tmpC.resolution.width = 120



/*
class is reference type
 identical operator : === , !==
*/

print("class \(c.resolution.width) == \(tmpC.resolution.width). reference")

if c === tmpC { 
    print ("class identical operator. equal")
}
// else if c !== tmpC






As a general guideline, consider creating a structure when one or more of these conditions apply:
- The structure’s primary purpose is to encapsulate a few relatively simple data values.
- It is reasonable to expect that the encapsulated values will be copied rather than referenced when you assign or pass around an instance of that structure.
- Any properties stored by the structure are themselves value types, which would also be expected to be copied rather than referenced.
- The structure does not need to inherit properties or behavior from another existing type. Examples of good candidates for structures include:
- The size of a geometric shape, perhaps encapsulating a width property and a height property, both of type Double.
- A way to refer to ranges within a series, perhaps encapsulating a start property and a length property, both of type Int. - A point in a 3D coordinate system, perhaps encapsulating x, y and z properties, each of type Double.”

Swift Enumerations : Raw value, Initializing, indirect


// Enumerations : Raw value

enum ASCIICharacterControl: Character {
    case tab = "\t"
    case lineFeed = "\n"
    case carriageReturn = "\r"
}

print("test\(ASCIICharacterControl.tab.rawValue)tabtab\(ASCIICharacterControl.lineFeed.rawValue)...")

enum Planet:Int {
    case sun=1,mercury,earth,mars,neptune,jupiter
}

print("\(Planet.sun),\(Planet.earth.rawValue)..")

enum CompassPoint: String {
    case east,west,south,north
}

print("\(CompassPoint.east)..\(CompassPoint.west.rawValue)")

// Enumerations : Initializing

var position = 3
if let planetTmp = Planet(rawValue: position) {
    switch planetTmp {
        case .earth:
            print("you choose \(planetTmp)")
        default:
            print("you choose other except earth:\(planetTmp)")
    }
} else {
    print("there is no planet with rawValue:\(position)")
}



//Recursive Enumerations : indirect

indirect enum ArithmethicExpression {
    case number(Int)
    case addition( ArithmethicExpression, ArithmethicExpression )
    case multiply( ArithmethicExpression, ArithmethicExpression )
}

let one = ArithmethicExpression.number(1)
let three = ArithmethicExpression.number(3)
let sum = ArithmethicExpression.addition(one,three)
let multi = ArithmethicExpression.multiply(sum,three)

func calculate(_ val: ArithmethicExpression ) -> Int {
    var ret : Int = 0
    switch val {
        case .number( let n ):
            ret = n
        case let .addition( a, b ):
            ret = calculate(a) + calculate(b)
        case let .multiply ( a, b ):
            ret = calculate(a) * calculate(b)
        default:
            print("nothing \(val)")
    }
    return ret
}
print( calculate(sum))
print( calculate(multi))

Swift Enumeration,Associated values

//1. Enumerations



enum SomeEnumeration {

}

enum CompassPoint {
    case north
    case south
    case east
    case west
}

enum Planet {
    case Sun,Mercury,Earth,Mars,Jupiter,Neptune
}

var directionToHead = CompassPoint.north
print(directionToHead)
directionToHead = .west
print(directionToHead)

switch directionToHead {
    case .north:
        print("switch: \(directionToHead)")
    case .south:
        print("switch: \(directionToHead)")
    case .east:
        print("switch: \(directionToHead)")
    case .west:
        print("switch: \(directionToHead)")
}


//2. Associated Values

enum BarCode {
    case upc(Int,Int,Int,Int)
    case qrCode(String)
}

var bCode = BarCode.upc(1,3,4,66)
print(bCode)
bCode = .qrCode("hi hello")
print(bCode)

switch bCode {
    case .upc(let leftPos,let topPos,let rightPos,let bottomPos):
        print ("upc \(leftPos), \(topPos), \(rightPos), \(bottomPos)")
    case let .qrCode(name):
        print ("hey \(name)")
}

Swift autoclosure

// 1. Closure - Autoclosure
“An autoclosure is a closure that is automatically created to wrap an expression that’s being passed as an argument to a function. It doesn’t take any arguments, and when it’s called, it returns the value of the expression that’s wrapped inside of it. This syntactic convenience lets you omit braces around a function’s parameter by writing a normal expression instead of an explicit closure.”





var customersInLine = ["james","kim","lee","richard","micheal","blondes","linda"]
let customerProvider = { customersInLine.remove(at:0) } // autoclosure : ()->String
print( customersInLine.count )
print( customerProvider() )
print( customersInLine.count )



//not autoclosure

func serve(customer: ()->String){
    print("serve:\(customer())")
}

serve(customer: { customersInLine.remove(at:0) } )
print (customersInLine.count)


//autoclosure
func serveAutoclosure(customer: @autoclosure ()->String ){
    print("serve by Autoclosure:\(customer())")
}
serveAutoclosure(customer: customersInLine.remove(at:0))
print (customersInLine.count)



// + escaping
var tempClosures : [()->String] = []
func collectClosures(itemClosure: @autoclosure @escaping ()->String){
    tempClosures.append(itemClosure)
}
collectClosures(itemClosure: customersInLine.remove(at:0))
collectClosures(itemClosure: customersInLine.remove(at:0))
for i in tempClosures {
    print("customer:\(i()), count:\(customersInLine.count)")
}


Swift closure : Capturing value, Escaping Closures

//1. Closure : Capturing value


func makeIncrement( forIncrement amount: Int) -> ()->Int {
    var sum = 0 // this is captured value
    func add () -> Int {
        sum += amount
        return sum
    }
    return add
}

let incrementBy5 = makeIncrement(forIncrement:5)
print(incrementBy5())
print(incrementBy5())
let incrementBy3 = makeIncrement(forIncrement:3)
print(incrementBy3())
print(incrementBy3())


//Closures are Reference Type
let incrementTemp = incrementBy3
print(incrementTemp())


//2. Closure : Escaping Closures
/*
A closure is said to escape a function when the closure is passed as an argument to the function, but is called after the function returns.
*/

var completionHandlers: [() -> Void] = []
func someFunctionWithEscapingClosure(completionHandler: @escaping  () -> Void) {
    completionHandlers.append(completionHandler)    
    // closure is not called in this scope. @escaping required
    // completionHandler() // closure is called in this scope. @escaping not required
}

func someFunctionWithNonescapingClosure(closure: () -> Void) {
    closure()
}

class SomeClass {
    var x = 10
    func doSomething() {
        someFunctionWithEscapingClosure { self.x = 100 }
        someFunctionWithNonescapingClosure { x = 200 }
    }
}

let instance = SomeClass()
instance.doSomething()
print(instance.x)
// Prints "200"
completionHandlers.first?()
print(instance.x)
// Prints "100”