이 SwiftUI 튜토리얼에서, 여러분은 뷰 선언과 수정을 통해서 UI를 배치하는 방법과 상태 병수를 사용해서 UI를 업데이트하는 방법을 배우게 될 것입니다. Xcode의 새로운 미리보기와 실시간 미리보기를 사용할 것이고, 동기화를 유지하는 코드와 WYSIWYG(what you see is what you get: 화면에 표시된대로 만드는 문서 작성 방식) 레이아웃의 기쁨을 경험할 것입니다.
SwiftUI는 2014년에 Apple이 Swift를 발표한 이후로 가장 흥미로운 뉴스입니다. 모든 사람에게 코딩을 시키겠다는 Apple의 목표를 향한 엄청난 발걸음이며, 기본사항을 단순화함으로써 사용자에게 기쁨을 주는 사용자정의 기능에 더 많은 시간을 할애할 수 있도록 해줍니다.
몇몇 개발자들은 SwiftUI가Sherlocked(버림받게)될지 모른다는 농담(?)을 했습니다.
SwiftUI를 사용하면 UI 레이아웃을 위한 단계별 상세 지침을 작성할 필요없이 인터페이스빌더(IB: Interface Builder)와. 스토리보드를 무시할 수 있습니다. IB와 Xcode는 Xcode 4 이전에 분리된 앱이었고, 코드에서IBAction이나IBOutlet의 이름을 편집하거나 삭제할때마다 연결부분이(seams) 항상 보이고, IB가 코드에서 변경된 것을 알지 못하기 때문에 앱이 크래쉬(crashes)납니다. 또는 코드에서 사용해야하는 세그웨이(segues)나 테이블 뷰 셀에 대한 문자열 타입의 식별자에 대해 열받아있지만, Xcode는 문자열이기 때문에 확인할 수가 없습니다. 그리고, WYSIWYG 편집기에서 새 UI를 디자인하는 것이 더 빠르고 쉬울수 있으며, 코드로 작성된 UI를 복사하거나 편집하는 것이 훨씬 더 효율적입니다.
이를 위한(rescue) SwiftUI입니다! 코드로 단계별로 SwiftUI 뷰를 미리보기 할 수 있습니다. - 한쪽을 변경하면, 다른쪽이 업데이트 될것이며, 항상 동기화됩니다. 잘못될수 있는 식별 문자열이 없습니다. 그리고 이는 코드이지만, UIKit을 작성하는 것보다 훨씬 적으며, 이해하고, 편집, 디버깅하는것이 더 쉽습니다. 사랑할수밖에 없어요.
SwiftUI는 Swift와 Objective-C 처럼 UIKit을 대체하지 않으며, 같은 앱에서 둘 다 사용할 수 있습니다. macOs에서 SwiftUI iOS 앱을 실행할 수 없을 것입니다. - 그것이Catalyst(촉매제)입니다. 하지만 SwiftUI API는 플랫폼간에 일관성이 있으므로, 각각 동일한 소스코드를 사용해서 여러 플랫폼에서 동일한 앱을 개발하는 것이 더 쉬워질 것입니다.
이 튜토리얼에서, 여러분은 SwiftUI를 사용해서iOS Apprentice에서 유명한 BullsEye 게임을 변형해서 만들것입니다. 뷰를 선언하고 수정해서 UI를 배치하는 방법과, 상태 변수를 사용해서 UI를 업데이트하는 방법을 배우게 될 것입니다. Xcode의 새로운 도구 중 일부, 특히 미리보기와 실시간 미리보기를 사용할 것이고, 동기화 상태를 유지하는 코드와 WYSIWYG 레이아웃의 기쁨을 경험하게 될 것입니다.
시작하기(Getting Started)
이 튜토리얼에 대한 프로젝트를 다운로드하는 것부터 시작합니다 - 이 튜토리얼의 위쪽이나 아랫쪽에 다운로드 링크를 찾을 수 있습니다.RGBullsEyeStarter폴더에 있는 UIKit 앱을 빌드하고 실행합니다. 이 게임은 3개의 슬라이더를 대상(target) 색상과 일치시키는데 사용합니다 - RGB 색상 값인 - 빨간색(red), 녹색(green), 파란색(blue) 값.
RWDevCon 2016에 이 앱을 작성했고 이 튜토리얼에 대해 Swift5로 코드를 업데이트 했습니다. 이 프로젝트는 Xcode 10과 Xcode 11 베타에서 실행합니다. 이 튜토리얼에서, 이 게임의 기본 버젼을 만들기 위해 SwiftUI를 사용할 것입니다.
Xcode 11 beta에서, 새로운 Xcode 프로젝트를 생성(Shift-Command-N)하고,iOS > Single View App을 선택하고, 프로젝트 이름을RGBullsEye로 주고,Use SwiftUI체크박스를 체크합니다.
RGBullsEye-Starter폴더외부(outside)에 저장합니다.
SwiftUI의 새로운 세계로 들어가기(Entering the New World of SwiftUI)
프로젝트 네비게이터에서, 무엇이 있는지 보기 위해RGBullsEye그룹을 엽니다: 예전 AppDelegate.swift는AppDelegate.swift와SceneDelgate.swift로 분리되었고SceneDelegate는window를 가지고 있습니다.
SceneDelegate는 SwiftuUI에만 국한되지는 않지만, 해당 줄은 다음과 같습니다.
struct ContentView: View {
var body: some View {
Text("Hello World")
}
}
이는Hello World를 보여주는Text뷰를 포함하는ContentView의body를 선언한 SwiftUI입니다.
DEBUG블럭 안쪽에,ContentView_Previews는ContentView의 인스턴스를 포함하는 뷰를 생성합니다.
#if DEBUG
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
#endif
여기에서 미리보기에 대한 샘플 데이터를 지정할 수 있습니다. 하지만 미리보기가 어디에 있다고 들었나요?
이는 맨 위에 있는 코드 옆에 큰 공백이 있습니다.
Resume를 클릭하고, 미리보기가 보여지는 동안에 기다립니다.
주의 Resume버튼이 보이지 않는 경우에는,editor options버튼을 클릭하고,Editor and Canvas를 선택합니다.
여전히Resume버튼이 보이지 않는 경우에는,macOS 10.15 beta에서 실행하고 있는지 확인합니다.
여러분의 UI 윤곽잡기(Outlining Your UI)
목록에서 보지 않은 파일 하나는Main.stroryboard입니다 - SwiftUI 코드에서 UI를 만들 것이며, 어떻게 보이는지 보기위해 미리보기를 계속 봅니다. 하지만 걱정마세요 - 뷰를 만들기 위해서 수백 줄의 코드를 작성하지 않을 것입니다!
SwiftUI는선언합니다(declarative): UI를 어떻게 보이게 할지 선언하고 SwiftUI는 선언을 효율적인 코드로 변환해서 그 일을 마무리 합니다. Apple은 코드를 쉽게 읽고 유지할수 있도록, 원하는만큼의 많은 뷰를 만드는 것을 권장합니다. 재사용가능한, 매개변수 뷰를 특히 권장됩니다 - 이는 함수에서 코드를 추출하는것과 같고, 이 튜토리얼에서 나중에 하나를 만들것입니다.
RGBullsEys의 UI는 많은 서브뷰를 가지고 있으므로, 먼저Text뷰를 리(placeholders)처럼outline을 만들 것입니다.
Text("Hello World")를 다음과 같이 교체하는 것으로 시작합니다.
Text("Target Color Block")
필요한 경우, 미리보기를 새로고침하기 위해서Resume를 클릭합니다.
이제미리보기에 있는Text뷰를Command-Click하고,Embed in HStack을 선택합니다.
코드가 일치하도록 업데이트되는지 확인합니다.
HStack {
Text("Target Color Block")
}
여기에서 타겟(target)과 추측(guess) 색상 블록을 나란히 보여주기 위해서수평스택(horizontal stack)을 사용합니다.
Text문장을 복사하고 붙여넣기 하고나서HStack이 다음과 같이 보이도록 편집합니다. 두개의 문장을 쉼표(comma)로 구분하지 않는 것을 주의하세요 - 각각 자기 줄에 작성합니다.
HStack {
Text("Target Color Block")
Text("Guess Color Block")
}
미리보기에서는 다음과 같습니다.
VStack안에HStack을 포함시켜 슬라이더 자리리placeholders)을 추가할 준비를 합니다 - 이번에는,코드(code)에 있는Hstack을Command-Click합니다.
Embed in VStack선택; 새 코드가 나타나지만, 미리보기는 변경되지 않습니다 - 색상 블록 아래에 뷰를 추가해야 합니다.
HStack클로져 아래에 새로운 줄을 열고,Library를 열기위해 툴바에 있는+버튼을 클릭하고 나서 새로운 줄에Vertical Stack을 드래그합니다.
예상했던 것처럼, 코드와 미리보기가 업데이트합니다.
주의 미니맵은 숨겨져 있기 때문에 스크린샷에서는 보이지 않습니다:Editor > Hide Minimap
윤곽(outline)을 완성하면 다음과 같이 보입니다.
VStack {
HStack {
Text("Target Color Block")
Text("Guess Color Block")
}
Text("Hit me button")
VStack {
Text("Red slider")
Text("Green slider")
Text("Blue slider")
}
}
새VStack은 3개의 슬라이더를 포함할 것이고, 색상 블록과 슬라이더 사이에 버튼이 있을 것입니다.
윤곽 채우기(Filling in Your Outline)
이제 새로운 SwiftUI 기술을 습득해서 색상 블록HStack을 채우면 다음과 같이 보입니다.
각 색상은 블록은Rectangle를 가집니다. 타겟(target) 색상 블록은 직사각형(rectangle) 아래에 하나의Text뷰를 가지며, 추측(guess) 색상 블록은 3개의Text뷰를 가지고 있습니다 - 이 튜토리얼의 뒷부분에서, 각xxx를 현재 슬라이더 값이 보이도록 교체할 것입니다.
장면을 넘겨받는 검은색 직사각형에 대해서 걱정하시 마세요 - 그것들은 슬러이더에 대한 공간을 만들것이고 여러분은 전경(foreground)색을 설정할 것입니다.
@State 변수 사용하기(Using @State Variables)
SwiftUI에서일반적인(normal)상수와 변수를 사용할 수 있지만, 값을 변경할 때마다 UI를 업데이트해야하는 경우 변수를@State로 지정합니다. 이 게임은 모두 색상에 대한 것이므로, 추측 직사격형의 색상에 영향을 주는 모든 변수는@State변수입니다.
body클로져 위에 있는,struct ContentView의 맨 위에 다음에 오는 줄들을 추가합니다.
let rTarget = Double.random(in: 0..<1)
let gTarget = Double.random(in: 0..<1)
let bTarget = Double.random(in: 0..<1)
@State var rGuess: Double
@State var gGuess: Double
@State var bGuess: Double
R, G, B 값은 0과 1 사이입니다.타겟(target)값은 랜덤값으로 초기화 합니다. 또한,추측(guess)값은 0.5로 초기화할 수 있지만, 몇개의 변수를 초기화하지 않은 경우에, 여러분이 무엇을 해야하는지 보여주기 위해서 초기화하지 않았습니다.
DEBUG블록으로 스크롤을 내리고, 미리보기에서 보여주기 위해ContentView를 인스턴스화 합니다. 초기화는 추측 값에 대한 매개변수 값이 필요합니다.ContentView()를 다음과 같이 변경합니다.
주의 미리보기는Resume를 클릭하거나 라이브 미리보기(곧 살펴 볼것입니다) 버튼을 클릭할때뿐만 아니라, 주기적으로 새로고침하며, 타겟(target) 색상이 스스로, 너무자주 변경되는 것을 보고 놀라지 마세요.
재사용가능한 뷰 만들기(Making Reusable Views)
이 게임을 몇몇 사람들에게 보여주었고, 게임이 매우 중독성이 있는 것을 알았습니다 - 특히 그래픽 디자이너. 그리고 그들은YUV와 같은, 다른 색상 공간 구현을 요청했습니다. 하지만 RGB는 슬라이더가 기본적으로 동일하기 때문에, 이 튜토리얼에서는 좋은 선택이므로, 슬라이더 뷰1개(one)를 정의하고, 다른 슬라이더에서 그것을재사용(reuse)할 것입니다.
우선, 재사용에 대해서 생각하지 않은체하고, 빨간 슬라이더를 만듭니다. 슬라이더VStack에서,Text("Red slider")자리(placeholder)를 다음에 오는HStack으로 교체합니다.
텍스트 색상을 빨간색으로 변경하기 위해서Text뷰를 수정합니다. 그리고Slider를from과through값 사이에 있는 값으로 초기화 합니다.
$가 무엇일까요? 여러분은 옵셔널에 대해?와!가 편해졌으며, 이제는$?
그 작은 기호(symbol)는 실제로 매우 멋지고 강력합니다.rGuess는 스스로가 읽기 전용(read-only) 값입니다.$rGuess는 읽고 쓰는(read-write)바인딩(binding)입니다 - 여기에서 사용자가 슬라이더의 값을 변경하는 동안 추측(guess) 직사각형의 전경색을 업데이트하는 것이 필요합니다.
차이를 확인하려면, 추측(guess) 직사각형 아래에 있는 3개의Text뷰에 값을 설정합니다.
주의 너무 자주Resume를 클릭하는 것을 알아챘을 수 있습니다. 키보드에서 손을 때지 않는게 좋은 경우,Option-Command-P는 가장 유용한 단축키 중 하나가 될것입니다 ;]
앱이 거의 완료되었습니다. BullsEye를 만들때를 생각해보고, RGBullsEye를 얼마나 더 빨리 만들었는지 놀랄것입니다. 학생들에게 BullsEye를 가르칠때, Auto Layout과 스택 뷰(stack views)를 사용하는 경우에도 UI를 설정하는데 몇 시간이 걸릴 수 있습니다. 그리고 여전히 많은 코드를 작성했습니다! SwiftUI를 가르치키 시작할때, 수업 시간을 채우는데 앱의 기능이 부족할 수도 있습니다 ;]
이제 재미있는 것을 보세요; 미리보기 기기의 오른쪽 아래 있는live preview버튼을 클릭하세요.
라이브 미리보기는 앱이 시뮬레이터에서 실행하는 것과 똑같이 미리보기에서 상호작용을 할 수 있습니다 - 훌륭합니다!
Preview spinner가 멈출때까지 기다리세요; 필요한 경우Try Again을 클릭합니다.
이제 슬라이더들을 색생에 맞게 움직이세요!
훌륭합니다!WWDC 키노트의 Goodnight Developers 비디오의 프로그래머 같은 기분이 드나요? 부엌으로 가서 빅토리 랩(victory lap: 경기후 한번 더 도는 것)을하고 가장 좋아하는 음료와 간식을 가지고와서 마지막 단계로 돌아가세요! 여러분의 점수를 알고 싶지 않나요? 그렇죠?
알림창 띄우기(Presenting an Alert)
슬라이더를 사용해서 맞는 색상을 얻은 후에, 사용자들은 원래 BullsEye 게임처럼,Hit Me버튼을 누릅니다. BullsEye에서 그랫던 것 처럼,Alert이 나타날것이며, 점수를 보여줄 것입니다.
우선, 점수를 비교하기 위해ContentView에 메소드를 추가합니다.@State변수와body간에 다음에 오는 메소드를 추가합니다.
func computeScore() -> Int {
let rDiff = rGuess - rTarget
let gDiff = gGuess - gTarget
let bDiff = bGuess - bTarget
let diff = sqrt(rDiff * rDiff + gDiff * gDiff + bDiff * bDiff)
return Int((1.0 - diff) * 100.0 + 0.5)
}
diff값은 3차원 공간의 두 점간의 거리일 뿐입니다 - 사용자의 오류. 점수를 구하기 위해, 1에서diff를 빼주고 나서 100을 곱해줍니다.diff가 작을수록 더 높은 점수를 받습니다.
다음으로,Text("Hit me button")자리를Button뷰로 교체합니다.
Button(action: {
}) {
Text("Hit Me!")
}
Button은UIButton처럼, 하나의 동작과 하나의 라벨을 가지고 있습니다. 원하는 동작은Alert뷰가 나타나는 것입니다. 하지만Button동작에서Alert를 만들기만해서는 아무 소용이 없습니다.
대신,ContentView의 하위 뷰들 중에 하나로Alert을 만들고Bool타입의@State변수를 추가합니다. 그리고나서,Alert이 나타나길 원할때,true를 변수 값으로 설정합니다 - 이 경우에는,Button에 있는 동작입니다. 사용자가Alert을 닫을때 그 값을false로 재설정합니다.
따라서@State변수를 추가하고false로 초기화 합니다.
@State var showAlert = false
그리고나서Button동작으로 다음에 오는 줄을 추가합니다.
self.showAlert = true
showAlert이 클로져 내부에 있기 때문에self가 필요합니다.
마지막으로,Button에persentation수식어를 추가함으로써Button뷰는 아래와 같이 보입니다.
이봐요, 라이브 미리보기가 있는데, iOS 시뮬레이터가 필요할까요? 시뮬레이터에서 앱을 실행하는 경우, 가로모드로 회전 할 수 있습니다.
여기에서 어디로 가야하나요?(Where to Go From Here?)
이 튜토리얼의 상단과 하단 링크를 사용해서 마지막 프로젝트를 다운로드 할 수 있습니다.
튜토리얼은 SwiftUI의 겉핥기 정도이지만, 이제 새로운 Xcode 툴을 사용해서 뷰를 배치(layout)하고 미리보기(preview) 하는 방법과 UI를 업데이트된 상태로 유지하기 위해@State변수를 사용하는 방법을 알고 있습니다. 훌륭한Alert은 말할 필요도 없습니다!
여러분은 Apple의 풍부한 자원에대해 자세히 알아볼 준비가 되었습니다 - 즉 튜토리얼과 WWDC 세션.튜토리얼과 WWDC 세션은 다른 샘플 프로젝트로 작업했습니다. 예를 들어,Introducing SwiftUI(#204)는 미팅룸에 대한 목록 앱을 만들었습니다 - 튜토리얼의 Landmarks 앱보다는 간단합니다.SwiftUI Essentials(#216)은Form컨테이너 뷰를 사용해서 iOS 폼의 모양과 느낌을 쉽게 가져오는 방법을 보여줍니다.
이 튜토리얼을 간단하게 유지하기 위해서, RGB 색상에 대한 데이터 모델을 만들지 않았습니다. 하지만 대부분의 앱은 데이터 구조를 구조체나 클래스로 모델링합니다. SwiftUI는 모델의 인스턴스의 변경된 것을 추적하는 것이 필요한 경우,BindableObject를 준수하기 위해서, 변경 이벤트를 보내는didChange속성을 구현합니다. Apple의 샘플 프로젝트를 보고 특히Data Flow Through SwiftUI(#226)을 보세요.
SwiftUI로 스스로 편해지지 위해서, 기존 앱에 SwiftUI 뷰를 추가할 수 있습니다 - 이를 어떻게 빠르고 쉽게 하는지 보기위해서Intergrating SwiftUI(#231)을 보세요.
또한, 무얼 사용할 수 있는지 보기 위해서 SwiftUI 문서를 살펴보세요. - 많이 있습니다!