반응형
- 기존에 만들어온 Memorize 데모앱 대신 새로운 EmojiArt 를 만들어 볼 것이다.
- 앞으로 나올 강의에서는 EmojiArt를 기준으로 수업한다.
Collections of Identifiable
- Memorize 앱에서 다음과 같은 코드를 사용해본 경험이 있을 것이다.
func choose(_ card: Card) {
if let index = cards.firstIndex(where: { $0.id == card.id }) {
cards[index].isFaceUp = true
}
}
- 카드 배열에서 선택된 카드를 찾아서 isFaceUp 혹은 isMatch 와 같은 것들을 설정해줘야하기 때문이다.
- 카드는 구조체이고 구조체는 값 타입이며 값타입은 복사되기 때문에 배열에서 바로 변경해야한다.
- 위와 같은 행위를 extension을 통해 손쉽게 사용하도록 구현할 수 있다.
func index(matching element: Element) -> Int? {
return firstIndex(where: { $0.id == element.id })
}
- 위와 같은 함수를 작성해주면 다음과 같이 사용할 수 있으며 읽기에도 쉬워진다.
func choose(_ card: Card) {
if let index = cards.index(matching: card) {
cards[index].isFaceUp = true
}
}
- index(matching:) 함수를 어디에 추가하면 좋을까?
- Identifiable을 만족하는 배열에 추가하면 된다!
extension Array where Element: Identifiable {
func index(matching element: Element) -> Int? {
return firstIndex(where: { $0.id == element.id })
}
}
- 만약 위 코드를 Set에서 사용하고 싶다면 Set에서도 별도의 index(matching:)을 추가해줘야 하는 것일까?
- 사실 Array와 Set은 Collection 프로토콜을 만족하고 있기 때문에 Collection에 확장시켜주면 된다.
extension Collection where Element: Identifiable {
func index(matching element: Element) -> Self.Index? {
firstIndex(where: { $0.id == element.id })
}
}
- 이제 Collection 프로토콜을 만족시키는 것에서 위 메서드를 호출할 수 있게 되었다.
- 이것이 프로토콜 지향 프로그래밍에서 하는 일이며 프로토콜에 기능을 추가할 수 있다.
- 반환 타입을 보면 특이하게도 Self.Index이다.
- Collection 프로토콜의 Index는 제네릭이며 Set과 Array는 Index로 Int를 사용할 뿐이다.
- String은 Character의 Collection이며 Int를 사용하여 인덱싱하지 않는다.
- String의 요소는 Character이며 identifiable하지 않다. 위 코드는 String에서 동작하지 않는다.
- where clause를 추가함으로써 위 기능이 String에서 동작하지 않도록 할 수 있다.
extension Collection where Element: Identifiable {
mutating func remove(_ element: Element) {
if let index = index(matching: element) {
remove(at: index)
}
}
}
- 특정 Element를 컬렉션에서 제거하는 기능을 추가할 수 있을 것이다.
- 입력받은 element와 동일한 자료가 컬렉션에 있다면 제거시켜주는 기능이다.
- 불행이도 Collection에는 remove 메서드가 존재하지 않기 때문에 위 코드는 동작하지 않는다.
extension RangeReplaceableCollection where Element: Identifiable {
mutating func remove(_ element: Element) {
if let index = index(matching: element) {
remove(at: index)
}
}
}
- 대신에 RangeReplaceableCollection을 사용하면 remove 메서드를 사용할 수 있게 된다.
- Array와 Set 모두 RangeReplaceableCollection를 만족한다.
- 따라서 Collection에서 Identifiable을 제거하는기능을 RangeReplaceableCollection에 추가할 수 있다.
- RangeReplaceableCollectiondms Collection을 상속받기 때문에 Collection도 만족한다.
- Collection과 RangeReplaceableCollection의 차이점은 수정할 수 없는가? 수정할 수 있는가이다.
- RangeReplaceableCollection에 Subscript(배열 첨자[])를 추가할 수 있다.
cards[card].isFaceUp = true
- 식별 가능한 Array 혹은 Set의 subscript에 대하여 Identifiable하도록 만들 수 있다.
- Int 인덱스가 아닌 card를 넣어서 인덱싱을 수행할 수 있다.
- subscript를 사용했을 때 장점: 변수를 수정할 수 있다.
- 위 코드는 cards 배열에서 card의 id를 subscript하고 있기 때문에 배열 값을 변경할 수 있다.
- 정리하자면 프로토콜 확장을 통해 기능을 추가할 수 있으며 subscript를 통해 변경할 수 있다는 점을 알아두자!
- Emoji Art 데모 코드에서 한번더 확인해보자! 강력한 기능이다.
Color vs. UIColor vs. CGColor
- Color에 관련된 3가지 자료구조가 있다. Color, UIColorm, CGColor
- 결론적으론 Apple Document에서 어떤 기능을 제공해주는지 확인하게 될 것이다.
Color
- Color은 정말 익숙하다. 다양한 맥락(context)로 사용될 수 있다.
- 우선 color-specifier 측면에서 색상을 지정하는데 사용할 수 있다. (예를 들어: .foregroundColor(Color.green))
- ShapeStyle처럼 행동하도록 사용할 수 있다. (예를 들어: .fill(Color.blue))
- View처럼 행동하도록 사용할 수 있다. (예를 들어: Color.white)
UIColor
- UIColor은 color을 수정(manipulating)하기위한 더 많은 API를 제공한다.
- UIColor에게 Red, Green, Blue 값이 무엇인지 물어볼 수 있다.
- 색조(Hue), 채도(Saturation), 밝기(Brightness) 값이 무엇인지 물어볼 수 있다.
- UIColor에서 채도를 높이고 색상을 변경하는 등 수정 작업을 할 수 있다.
- Color에는 수정하는 API가 없기 때문에 수정할 수 없다.
- UIColor을 통해 수정 작업이 끝났다면 Color 생성자를 통해 Color로 변환시킬 수 있다.
- 위 두가지는 서로 교환 관계가 성립해서 자신의 역할이 끝났다면 상대방의 생성자를 통해 변환시킬 수 있다.
CGColor
- Core Graphic System(CG)에서의 기본적인 색상 표현법이다.
- 제한된 API를 제공하며 그림을 그릴때 색상을 어떻게 표현하는지에 관한 것이다.
- color.cgColor을 사용하여 color에서 CGColor로 변환시킬 수 있다. (optional 타입이다.)
- color로 표현되는 것들이 CGColor로 반드시 표현될 수 있음을 보장할 수 없기 때문이다.
- SwiftUI에 있는 다른 API를 사용하여 생성한 경우 99.99% CGColor 표현 가능한 색상을 생성한다.
Image vs. UIImage
- Image 및 UIImage와 같은 또다른 쌍이 존재한다.
Image
- Image는 이미지를 보여주는 View이며 image 값을 갖는 변수의 type이 아니다.
- Xcode에서 Assets.xcassets를 통해 이미지에 접근할 수 있으며 (첫번째 강의에 언급하였다)
- 위 폴더에 jpeg 이미지를 가져다 두고 Image(_ name: String)을 통해 불러올 수 있다.
- SFSymbol 이미지에 접근하려면 Image(systemName:)을 통해 불어올 수 있다.
- System 이미지의 크기는 .imageScale() View modifier를 통해 조정할 수 있다.
- System 이미지의 경우 .font modifier에 영향을 받는다. 즉, 폰트 크기를 키우면 이미지도 커진다.
- System 이미지는 마스크(예를 들어 Gradient)하는데 유용하다. 색상, 모노크롬 형태로 변경할 수 있다.
UIImage
- 실제 JPEG, TIFF와 같은 이미지이다.
- 크기 조정 및과 같은 것들이 UIImage를 통해 가능하다.
- Image(uiImage:)를 통해 이미지를 표시할 수 있다.
- Color와 UIColor 관계와 정확히 동일하다.
- UIImage type을 통해 변수에 이미지를 담을 수 있으며 이미지를 보여주고 싶다면 Image View를 사용하면 된다.
Drag and Drop
- EmojiArt 데모에서는 Drag and Drop 기능을 사용할 것이다.
- Drag and Drop은 하나의 앱에서 다른 앱으로 자료를 전송하는 기능이다.
- NSItemProvider 라는 핵심 Class가 사용된다.
- 프로세스간의 데이터 전송이 이루어지며 과정의 범위를 벗어나기 때문에 깊게 다루지는 않는다.
- 보안 문제와도 연관지을 수 있으며 다중 스레드와 관련되어있다.
- 두 앱의 UI 중 하나가 중단되는 것을 바라지 않으며 여튼 복잡하다 ㅎㅎㅎ
- SwiftUI와 NSItemProvider 간의 상호 작용을 관리하는 코드가 제공될 것이다.
- 본질적으로 NSItemProvider가 할 수 있는 것은 다양한 type의 데이터 전송을 용이하게 해주는 것이다. 예시는 다음과 같다.
- NSAttributedString (a String with formatting) and NSString
- NSURL (https://cs193p.stanford.edu/something)
- UIImage and UIColor
- 위와 같은 것을 UI로부터 Drag and Drop할 수 있다.
- 불행이도 "NS" 시리즈들이 Swift에서 사용되고 있으며 Swift 이전에 사용되온 것들이다.
- NSItemProvider를 사용할 때 귀찮기는 하지만 다음과 같이 Swift타입을 과거의 타입으로 연결(bridging)해줘야 한다.
- Objective-C에 대하여 자세하게 언급하지는 않을 것이다.
String as NSString
다음편에서는 Demo 앱 구현에 관하여 포스팅할 것이다!
반응형
' Apple > Stanford iOS Programming (SwiftUI)' 카테고리의 다른 글
Lecture 9 Review Part 2: EmojiArt Drag and Drop Multithreading (0) | 2021.09.25 |
---|---|
Lecture 7 Review Part 2: ViewModifier Animation (0) | 2021.09.09 |
Lecture 7 Review Part 1: ViewModifier Animation (0) | 2021.09.04 |
Lecture 6 Review Part 3: Protocols Shapes (0) | 2021.08.26 |
Lecture 6 Review Part 2: Protocols Shapes (0) | 2021.08.26 |