2018년 3월 30일 금요일

토요일 아침 고덕동 산책

날씨가 워낙 따뜻해서 산책 다니고 좋습니다. 댕댕이 데리고 토요일은 한시간 이상(약 4킬로 미터) 산택을 다닙니다.
미세먼지가 없다면 라이딩도 최고의 날씨인데 뭐 무시하고 탑니다. ㅋㅋ
고덕동으로 이사온지 일년정도 되었는데 이 동네는 조용합니다. 숲세권으로도 불리는 작은 동산과 산책로가 많아서 산책하기 좋은 곳입니다.













역삼역 근처 진배 족발

멀티 캠퍼스 근첯에서 회식할 때 강사들과 몇번 가본 곳입니다.
진배 족발이라는 곳인데 맛납니다. ㅋㅋ
가격은 38000원 정도 합니다. 족발이 부들부들한게 먹을만 합니다. 역삼역 근처에 딱히 맛집이라고 할만한 곳이 많지 않은데 그래도 동료들과 같이 가는 아지트 같은 곳입니다.




2018년 3월 28일 수요일

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)
```

2018년 3월 1일 목요일

최근에 스팀잇에도 글을 올리고 있습니다.

드림위즈에 처음 블로그 둥지를 열고, 다시 구글 블로거를 사용하고 최근에는 스팀잇에도 조금씩 글을 올리고 있습니다.
요즘에는 마크다운도 지원하고 스팀잇이 핫하네요. 아래는 제 주소입니다.

https://steemit.com/@papasmf1

요즘 많이 들리는 RAG에 대한 멋진 정리가 있어서 공유합니다. ㅎㅎ

 작년에는 ChatGPT가 크게 유행을 했는데 올해는 Gen AI, LLM, 랭체인등이 유행하고 있습니다. ㅎㅎ  RAG라는 단어도 상당히 많이 들리고 있습니다. 멋진 정리의 링크입니다.  https://brunch.co.kr/@ywkim36/146?...