2018년 3월 7일 수요일

iOS앱을 개발할 때 사용하는 Xcode 9.2 툴의 Swift 4에 추가된 새로운 특징들입니다.

저도 공부하면서 조금씩 시간을 내서 정리하고 있습니다. 가끔식 서점에 가보면 iOS는 신간 책들이 나오는 일이 많이 줄어들었습니다. ㅠㅠ 파이썬 책들을 늘어나는데 iOS, Swift는 신간들이 거의 없네요. 천상 블로그 글들을 검색하고 영문 책들을 보면서 짬짬이 정리하고 있습니다.

###Codable은 Encodable과 Decodable을 합쳐놓은 프로토콜입니다.
```
//Codable프로토콜
struct DemoType: Codable {
    let name: String
    let value: Int
    let hasJob: Bool
    let secondName: String?
}
```


Swift 3에서는 JSON데이터를 사용할 때 JSONSerialization이라는 클래스를 사용해서 사전형 등의 표준 타입으로 변경한 후 이를 다시 구조체에 수동으로 넣어주는 작업을 했습니다.
Swift 4에서는 Codable을 따르는 구조체는 JSONDecoder를 이용해 바로 분해해서 정리할 수 있습니다.Codable은 일종의 JSON설계도 프로토콜이라고 할 수 있습니다.
```
let inputData = """
{ "name": "kim",
  "value": 100,
  "hasJob": false,
  "secondName": "is not myname"
}
""".data(using: .utf8)

let decoded = try JSONDecoder().decode(DemoType.self,
                                       from: inputData!)
decoded.name
decoded.value
decoded.hasJob
decoded.secondName
```


옵셔널 형식인 secondName을 비워두면 어떻게 처리되는지 확인해 봅니다.
```
let inputData2 = """
{ "name": "lee",
  "value": 200,
  "hasJob": false
}
""".data(using: .utf8)

let decoded2 = try JSONDecoder().decode(DemoType.self, from: inputData2!)
decoded2.secondName //nil
```


JSONEncoder
반대로 DemoType을 JSON으로 인코딩하려면 JSONEncoder를 사용할 수 있습니다.
```
let outputData = try JSONEncoder().encode(decoded2)
let outputString = String(data: outputData, encoding: .utf8)
print(outputString!)
//"{"name":"lee","value":200,"hasJob":false}\n"
```


###One-sided range(단방향 범위)
Swift4에서는 RangeExpression이 새롭게 소개되었습니다.
플레이그라운드를 Xcode 9.2에서 만들고 실행하면 아래와 같이 실행됩니다.
```
let esports = ["스타크래프트", "LOL", "오버워치", "스타크래프트2","수퍼 마리오"]

esports[3...]
//["스타크래프트2", "수퍼 마리오"]
//기존 Swift3에서는 esports[3..<esports.endIndex]
//와 같이 자기성했습니다.

esports[...2]
//["스타크래프트", "LOL", "오버워치"]
```

..<연산자는 자기는 제외하고 그 앞까지 리턴합니다.
```
esports[..<2]
//["스타크래프트", "LOL"] 을 리턴합니다.
```


Infinite sequence
One-side range는 infinite sequence를 생성하는데 사용됩니다.
아래의 예제를 돌려보면 배열을 zip으로 합치면서 65이후의 숫자지만 4개의 문자까지만 합친 결과가 출력됩니다.
```
let uppercase = ["A","B","C","D"]
let asciiCodes = zip(65..., uppercase)
print(Array(asciiCodes))
[(65, "A"), (66, "B"), (67, "C"), (68, "D")]
```


one-side range를 패턴 매칭에 사용하면 간편하게 처리할 수 있습니다.
```
func gameRank(_ index: Int) -> String {
    switch index {
    case ...1:
        return "상위권"
    case 3...:
        return "하위권"
    default:
        return "중간정도"
    }
}

gameRank(2)
```



문자열 처리가 Swift4에서는 보다 쉽고 강력해졌습니다. 가장 큰 변경은 String이 이제는 Collectoin이라는 것입니다.
```
let text = "swift powerful"
let unicodeText = "스위프트는 강력함"
text.count      //14
text.isEmpty    //false
"".isEmpty      //true
String(text.reversed()) //"lufrewop tfiws"

//문자열을 각각의 문자로 반복출력하는 것도 쉬워졌습니다.
for c in unicodeText {
    print(c)
}
```

문자열의 부분추출을 할 경우 String.Index 또는 Range(<String.Index>를 사용합니다.
"swift powerful"에서 문자의 방번호 6번은 p를 가리킵니다. 여기서부터 끝까지 추출하면 powerful이 됩니다. 뒤에서 부터 -1, -2, -3으로 접근하면 자기 자신을 제외하고 swift를 추출할 수 있습니다.
```
var index = text.index(text.startIndex, offsetBy: 6)
text[index]     //p
var lastword = text[index...]
//"powerful"
index = text.index(text.endIndex, offsetBy: -9)
let firstword = text[..<index]
//"swift"
```


Substring에 대한 소개
Swift는 문자열과 연관된 버퍼를 관리할 때 효율적이 되도록 시도합니다. 예를 들면 원래 문자열 버턴의 위치의 뷰를 리턴하는 서브스트링 작업과 같은 경우 입니다. 이 경우 버퍼의 참조 카운트를 증가시킵니다.
Swift standard library는 새로운 형식을 소개함으로 이 문제를 해결합니다. Substring은 부분추출 작업으로 리턴되는 문자열의 형식입니다. Standard library에서는 새로운 프로토콜인 StringProtocol도 소개하고 있습니다. 대부분의 String API는 StringProtocol로 이동되며 String과 Substring은 이 새로운 프로토콜을 준수합니다.
```
//Substring형식이 추가됨
print(type(of: lastword))
//Substring
print(lastword.uppercased())
//POWERFUL
let lastWordAsString = String(lastword)
print(type(of: lastWordAsString))
//String

//Unicode 사용
let c: Character = "🇯🇵"
print(Array(c.unicodeScalars))
//["\u{0001F1EF}", "\u{0001F1F5}"]

print("🇬🇧🇨🇦🇸🇴".count)
//3

let demoword = "🇬🇧🇨🇦🇸🇴🇮🇪🇦🇪🇮🇴"
demoword.count
//6

var nsRange = NSRange(demoword.startIndex...,
                      in: demoword)
demoword.utf16.count
let display = NSMutableAttributedString(string: demoword,
                                        attributes: [.font: UIFont.systemFont(ofSize: 20)])
```


다중 라인에 대한 처리
파이썬에서 사용하는 것처럼 """   """을 앞뒤에 사용하면 다중 라인을 하나의 문자열 변수에 담을 수 있습니다.


###딕셔너리 향상
딕셔너리 형식을 코딩할 때 자주 사용하는 내장 형식입니다.

시퀀스 기반의 생성자
시퀀스 관련 key-value을 바로 생성할 수 있습니다.
```
let groceries = Dictionary(uniqueKeysWithValues: zip(
    1..., ["삼겹살", "피자", "치킨", "감자칩", "오렌지", "양파"]))
print(groceries)
//[5: "오렌지", 6: "양파", 2: "피자", 3: "치킨", 1: "삼겹살", 4: "감자칩"]

//아니면 튜플로 묶을 수 있습니다.
let deviceTotals = [("아이폰", 5), ("아이패드", 10), ("안드타블렛",20)]

//머징을 할 수 있습니다.
let duplicates = [("a", 1), ("b", 2), ("a", 3), ("b", 4)]
let oldest = Dictionary(duplicates) { (current, _) in
    current
}
print(oldest)
//["b": 2, "a": 1] 키가 충돌이 나서 2개만 출력됨
```


아래의 코드를 보면 각 학급별로 이름들을 묶어주는 것을 볼 수 있습니다.
```
let sortingHat = [
    ("Gryffindor", "Harry Potter"), ("Slytherin", "Draco Malfoy"),
    ("Gryffindor", "Ron Weasley"),
    ("Slytherin", "Pansy Parkinson"),
    ("Gryffindor", "Hermione Granger"),
    ("Hufflepuff", "Hannah Abbott"),
    ("Ravenclaw", "Terry Boot"), ("Hufflepuff", "Susan Bones"),
    ("Ravenclaw", "Lisa Turpin"),
    ("Gryffindor", "Neville Longbottom")
]
let hourses = Dictionary(
    sortingHat.map { ($0.0, [$0.1]) },
    uniquingKeysWith: { (current, new) in
        return current + new
})
print(hourses)
//["Ravenclaw": ["Terry Boot", "Lisa Turpin"], "Hufflepuff": ["Hannah Abbott", "Susan Bones"], "Slytherin": ["Draco Malfoy", "Pansy Parkinson"], "Gryffindor": ["Harry Potter", "Ron Weasley", "Hermione Granger", "Neville Longbottom"]]
```


어떤 글자를 몇번 사용했는지 filter와 map함수를 사용해서 정리합니다.
```
let spell = "오늘은 스위프트와 파이썬을 정리합니다.그렇게 학습을 합니다."
var frequencies: [Character: Int] = [:]
let baseCounts = zip(
    spell.filter { $0 != " "}.map { $0 },
    repeatElement(1, count: Int.max))
frequencies = Dictionary(baseCounts, uniquingKeysWith: +)
print(frequencies)
//["합": 2, "게": 1, "파": 1, "렇": 1, "오": 1, ".": 2, "습": 1, "프": 1, "을": 2, "트": 1, "썬": 1, "위": 1, "리": 1, "스": 1, "다": 2, "그": 1, "이": 1, "와": 1, "학": 1, "정": 1, "은": 1, "니": 2, "늘": 1]
```


새로 추가된 merge메서드를 통해 병합하는 작업을 할 수도 있습니다. 
```
let defaultStyling: [String: UIColor] = [
    "body": .black, "title": .blue, "byline": .green
]
var userStyling: [String: UIColor] = [
    "body": .purple, "title": .blue
]
userStyling.merge(defaultStyling) { (user, _) -> UIColor in
    user
}
print(userStyling)
```

댓글 없음:

댓글 쓰기

참고: 블로그의 회원만 댓글을 작성할 수 있습니다.

5월 14일 새벽에 chatGPT 4o가 발표되었습니다. 옵티마이즈, 옴니라는 의미인데 실시간 통역, 다자간 회의, 멀티모달 기능의 강화등이 보이네요.

  초격차로 OpenAI진영이 다시 앞서가는 모양을 보여주고 있습니다. 저도 새벽에 일어나자 마자 올라온 영상들과 글을 정리하고 있습니다. ㅎㅎ 영화 HER의 사진이 새벽에 많이 올라왔었는데 저도 안본 영화입니다. 주말에 한번 봐야 할 것 같습니다....