Skip to content

Instantly share code, notes, and snippets.

@kingori
Created July 10, 2014 17:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kingori/cc5882aee892438b43a8 to your computer and use it in GitHub Desktop.
Save kingori/cc5882aee892438b43a8 to your computer and use it in GitHub Desktop.
WWDC 2014 advanced swift 정리

#Advanced swift ##Taking control of Syntax

텍스트 머드 기반으로 설명을 하네~

class Thing {
  init(location: Thing?, name: String,
  longDescription: String) { ... }


  weak var location: Thing?
  var name: String
  var longDescription: String
}

###argument name

객체 생성하려면 인자 이름(argument name)을 넘겨야 한다.

let wallWestOfHouse = Thing(location: westOfHouse,
        name: "wall",
        longDescription: "The plaster has crumbled " +
                "away, leaving the wood beneath to rot.")

다음 둘은 동일하다.

class Thing {
  init(location: Thing?, name: String,
  longDescription: String) { ... }
}

class Thing {
  init(location location: Thing?, name name: String,
  longDescription longDescription: String) { ... }
}

뭔가, 이름은 넣어야 하지만 쓸 일은 없다면 그냥 _ 로 퉁 칠 수 있다. (스칼라랑 비슷하네)

for (key, _) in dictionary { //key와 value 로 구성된 tuple 자리이지만, value에 관심없음
  println(key)
}

var red, blue: Int
(red, _, blue, _) = color.rgba //rgba 4 값 중 red, blue만 관심있음

인자 이름도 지워버리고 싶다면 _ 를 사용하자.

class Thing {
  init(_ location: Thing?, _ name: String,
  _ longDescription: String) { ... }
}

let wallWestOfHouse = Thing(westOfHouse, "wall",
    "The plaster has crumbled away, leaving the " +
    "wood beneath to rot.")

###protocol

당길 수 있는 객체라면 뭔가 특별한 처리를 하고 싶다!

// The parser will call this. 
func performPull(object: Thing) { 
	if /* object is pullable */ {
	 /* pull it */
	} else {
	  /* complain */
	}
}

그렇담 protocol 만들어.

protocol Pullable {
  func pull()
}

적용은 마치 class extends 하듯이. 자바의 interface처럼 protocol에 정의된 function 은 구현해야 해.

class Boards: Thing, Pullable {
	func pull() {
	    if location === westWallOfHouse {
	      println("They come off with little effort.")
	      location = westOfHouse
	    } else {
	      println("Think of the splinters!")
		} 
	}
}

protocol 타입 확인은 if let xxx = yyy as protocol_type {...} 형식으로.

func performPull(object: Thing) {
 if let pullableObject = object as Pullable {
	 pullableObject.pull()
 } else {
	 println("You aren't sure how to print a \(object.name).")
 }
}

####special protocols

그냥 literal이 아니라 special protocol이라 칭하는 이유가 있나?

type ex.
LogicValue if logicValue {
Printable "(printable)"
Sequence for x in sequence
IntegerLiteralConvertible 65536
FloatLiteralConvertible 1.0
StringLiteralConvertible "abc"
ArrayLiteralConvertible [ a, b, c ]
DictionaryLiteralConvertible [ a: x, b: y ]

####printable

string interpolation에 쓰는 녀석. 즉, interpolation 시 출력되는 내용을 지정하고 싶다면 이 protocol을 extends(맞나?)하자. java의 toString() method override 같음.

protocol Printable {
  var description: String { get }
}

extension Thing: Printable {
  var description: String { return name }
}	

출력 내용을 꾸며보자.

extension Thing {
  var nameWithArticle: String {
    return "a " + name
  }
}

println("You aren't sure how to pull \(an ~ object).")

연산자 오버로딩

//연산자 오버로딩 하려면 operator 선언을 해야 한다고 함. 아직 이 부분을 문법 책에서 못봐서리...
operator infix ~ {}

func ~ (decorator: (Thing) - String,
        object: Thing) -> String {
	return decorator(object)
}

func an(object: Thing) -> String {
  return object.nameWithArticle
}

####enum

enum Direction {
  case North, South, East, West
}

class Place: Thing {
  init(_ name: String, _ longDescription: String) { ... }
  var exits: Dictionary<Direction, Place>
}	

//enum 타입 추정 가능한 위치엔 . 만 찍어서
westOfHouse.exits[.South] = gardenPath

westOfHouse[.South] = gardenPath     // [] 도 빼버리고 싶다면?
//subscript 새용

extension Place {
  subscript(direction: Direction) -> Place? {
    get {
  	  return exits[direction]
	}
    set(destination: Place?) {
      exits[direction] = destination
	} 
  } 
}

####a word of caution

  • Keep it natural
  • Work by analogy
  • New idioms should pay for themselves

##Generic programming func peekString(interestingValue: String) { println("[peek] (interestingValue)") }

func peekInt(interestingValue: Int) {
  println("[peek] \(interestingValue)")
}


func peekFloat(interestingValue: Float) {
  println("[peek] \(interestingValue)")
}

==>

func peek(interestingValue: Any) {
	println("[peek] \(interestingValue)")
}

//반환값 가지고 뭘 더 하고싶다면? generic
func peek<T>(interestingValue: T) -> T {
	println("[peek] \(interestingValue)")
	return interestingValue
}

###protocol types vs. generics

  • Protocol types like Any or Pullable throw away type information
    • Great for Dynamic Polymorphism
  • Swift Generics conserve type information
    • Great for type safety
    • Great for performance

type relationships

func swap<T>(inout x: T, inout y: T) { 
	let tmp = x
	x=y
	y = tmp
}

###protocol constraints

// ": 타입"
func indexOf<T : Equatable>(sought: T, inArray array: T[]) -> Int? {
  for i in 0..array.count {
    if array[i] == sought {
      return i
} }
return nil }

protocol Equatable {
  func == (lhs: Self, rhs: Self) -> Bool
}

###implementing memoization using generics 순수 재귀함수는 너무 오래걸려

func fibonacci(n: Int) -> Double {
  return n < 2 ? Double(n) : fibonacci(n - 1) + fibonacci(n - 2)
}

수동 memoization -> 안이뻐

var fibonacciMemo = Dictionary<Int, Double>() // implementation detail

// Return the nth fibonacci number: 0, 1, 1, 2, 3, 5, 8, 13, 21, ...
func fibonacci(n: Int) -> Double {
 if let result = fibonacciMemo[n] {
   return result
 }
 let result = n < 2 ? Double(n) : fibonacci(n - 1) + fibonacci(n - 2)
 fibonacciMemo[n] = result
 return result
}

generic, closure를 이용해 구현한 자동 memoization

func memoize<T: Hashable, U>( body: (T)->U ) -> (T)->U {
  var memo = Dictionary<T, U>()
  return { x in
    if let q = memo[x] { return q }
    let r = body(x)
    memo[x] = r
    return r
  } 
}

초기값이 있다면?

func memoize<T: Hashable, U>( body: ((T)->U, T)->U ) -> (T)->U {
  var memo = Dictionary<T, U>()
  var result: ((T)->U)!
  result = { x in
    if let q = memo[x] { return q }
    let r = body(result, x)
    memo[x] = r
    return r
  }
  return result
}

let factorial = memoize { factorial, x in x == 0 ? 1 : x * factorial(x - 1) }

####synergy of powerful features

  • Type deduction for concision:
    • let fibonacci = memoize { fibonacci, n in
  • Trailing closure syntax for expressivity
    • let fibonacci = memoize { fibonacci, n in
  • Generic functions for generality with safety and performance
    • func memoize<T: Hashable, U>( body: ((T)->U, T)->U ) -> (T)->U

###generic types struct Stack { mutating func push(x: T) { items += x }

  mutating func pop() -> T {
    return items.removeLast() }
  var items: T[]
}

var intStack = Stack<Int>()
intStack.push(42)

근데... 다음과 같은 처리를 해 주고 싶다면?

func peekStack(s: Stack<T>) {
  for x in s { println(x) }
}


for...in loop 는 내부적으로 다음과 같이 처리됨

for x in someSequence {
	...
}

-->

var __q = someSequence.generate()
while let x = __g.next() {
 ...
}

이러려면 Generator protocol을 extends해야.

protocol Generator {
	typealias Element
	mutating func next() -> Element?
}

protocol Sequence {
  typealias GeneratorType : Generator
  func generate() -> GeneratorType
}

struct StackGenerator<T> :Generator {	
	mutating func next() -> T? {
	    if items.isEmpty { return nil }
	    let ret = items[0]
	    items = items[1..items.count]
	    return ret
	}

	var items: Slice<T>
}

extension Stack : Sequence {
  func generate() -> StackGenerator<T> {
    return StackGenerator( items[0..item.Count] )
  }
}

//이제 동작
func peekStack(s: Stack<T>) {
  for x in s { println(x) }
}

####Summary of Swift Generics and Protocols

  • Protocols are your hooks into the Swift core language
  • Swift generics combine abstraction, safety, and performance in new ways
  • Read, experiment, and have fun. There’s plenty to discover!

##The Swift model

  • The Minimal Model
    • Statically compiled //동적 언어 아니야!
    • Small runtime
  • Simple Interoperation
    • Transparent interaction with C and Objective C
    • Can deploy to previous versions of iOS and Mac OS X
  • Predictable Behavior
    • You control the code that runs
    • Comprehensible compilation with inspectable results
    • No non-deterministic JITs or garbage collection pauses
  • Efficient Execution
    • Native code instantly ready to run
    • No artificial abstraction barriers //generic 같은 정보가 사라지지 않음을 얘기하는 듯?
    • Predictable model enables bare-to-the-metal programming //low level code를 생성한다?
  • High-Level Optimization
    • Removing abstraction penalties : struct를 사용해도 overhead 0
      • Global analysis of your app
      • Using a struct has no runtime penalty
      • Even Int and Float are structs
    • Generic specialization : 다른 언어같이 extension 하지 않음 <- 컴파일 과정에서 generic 정보를 풀어헤치지 않음
      • Swift can run generic code directly
      • Optimizer can produce specialized versions of generic code at will
        • Separate compilation of generics
        • Faster compiles
        • Flexibility to trade code size for speed
    • Devirtualization
      • Resolving dynamic method calls at compile-time
        • If Swift can see where you constructed the object
        • If Swift knows that a class doesn't have any subclasses
        • If you've marked a method with the @final attribute
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment