적당한 고통은 희열이다

- 댄 브라운 '다빈치 코드' 중에서

Swift iOS 앱 개발/Swift 튜토리얼

[Stanford iOS] Lecture 8. Gestures JSON

hongssup_ 2021. 4. 12. 12:02
반응형

SwiftUI Lecture 8.

  • UserDefaults
    Lightweight persistent store
  • Gestures
    Getting input from the user into your app

 

Storing Data Permanently

numerous ways to make data “persist” in iOS

simplest UserDefaults

In a SQL database (CoreData for OOP access or even direct SQL calls).

iCloud (interoperates with both of the above)

CloudKit (a database in the cloud)

 

UserDefaults

- Using UserDefaluts

UserDefaults instance 생성

let defaults = UserDefaults.standard

- Storing Data

딕셔너리 형식으로 저장. 

defaults.set(object, forKey: “SomeKey”) // object must be a Property List

- Retrieving Data

let i: Int = defaults.integer(forKey: “MyInteger”)
let b: Data = defaults.data(forKey: “MyData”)
let u: URL = defaults.url(forKey: “MyURL”)
let strings: [String] = defaults.stringArray(forKey: “MyString”)
// etc.

String이 아닌 배열을 가져오기에는 좀 더 복잡할 수 있다. 

let a = array(forKey: “MyArray”)  //는 Array<Any>를 반환한다...

따라서 Swift의 'as' 연산자를 이용해 이 Array element들을 "type cast" 해주어야 하는데, (*typecasting?)

혹은 data(forKey:) 를 사용하여 이를 Codable로 쉽게 해결할 수도 있다. 

 

Gestures

: Getting Input from the User

사용자의 손가락 '제스처' (= multitouch)를 감지하는 SwiftUI

우리는 이러한 제스처들이 감지되면 어떻게 다루어야 할까. 

- How to make Views recognize Gestures  

To cause your View to start recognizing a certain gesture, you use the .gesture View modifier.

myView.gesture(theGesture) // theGesture must implement the Gesture protocol

- Creating a Gesture

var theGesture: some Gesture {
 return TapGesture(count: 2)
}

- Handling the Recognition of a Discrete Gesture

감지된 제스터를 어떻게 처리하는가는, 그 제스터가 discrete한가 아닌가에 따라 달라진다. 

Discrete Gesture :

It happens “all at once” and just does one thing when it is recognized. (e.g. TapGesture)

(반면 pinch나 drag는 happening overtime)

discrete gesture를 감지하고 처리하기 위해서는 .onEnded { } 를 사용한다. 

var theGesture: some Gesture {
    return TapGesture(count: 2)
        .onEnded { /* do something */ }
}

더욱 편리한 버전으로 사용하기 위해서는 다음과 같은 방식으로 많이 사용된다. 

myView.onTapGesture(count: Int) { /* do something */ }
myView.onLongPressGesture(...) { /* do something */ }

- Handling Non-Discrete Gestures

조금 더 복잡한 non-discrete gestures 다루기 

처음 제스처가 감지되었을 때 뿐만아니라, 제스처가 끝났을 때도 감지해줘야함. 

need to handle the gesture while it is in the process of happening (fingers are moving)

(e.g. DragGesture, MagnificationGesture(pinch), RotationGesture 등)

LongPressGestrure도 non-discrete으로 취급될 때가 있다? (fingers down and fingers up)

var theGesture: some Gesture {
    DragGesture(...)
    .onEnded { value in /* do something */ }
}

여기서도 .onEnded { }를 사용해 제스처가 끝날 때 실행할 것들을 알려줘야 하는데, 

discrete gestures와 다른 점은, 해당 제스처가 끝났을 때의 state를 알려주기 위해 클로저에 value 인자를 같이 넘겨준다는 것! 

여기서 넘겨줘야할 value 인자는 해당 제스처 마다 다르다. 

For a DragGesture, it’s a struct with things like the start and end location of the fingers.

For a MagnificationGesture it’s the scale of the magnification (how far the fingers spread out).

For a RotationGesture it’s the Angle of the rotation (like the fingers were turning a dial).

또한, non-discrete gesture 에서는 제스처가 일어나는 동안 변화하는 state를 감지하고 update해야하는 경우가 있을 수 있다. 

이러한 변화 중의 state는 @GestureState을 이용해 다음과 같이 저장할 수 있다. 여기서 var는 어떤 type 이던 상관없다. 

@GestureState var myGestureState: MyGestureStateType = <starting value>

@GestureState is only the state while the Gesture is active. 

This var will always return to <starting value> when the gesture ends.

제스처가 이루어지고 있는 중에만 state의 변화를 저장할 수 있도록, 제스처가 끝난 후에는 시작 value로 돌아가도록 되어있다. 

@GestureState var의 상태(손가락 움직임)는 .updating을 사용해 다음과 같이 계속해서 업데이트해줄 수 있다.

var theGesture: some Gesture {
    DragGesture(...)
        .updating($myGestureState) { value, myGestureState, transaction in
            myGestureState = /* usually something related to value */
        }
        .onEnded { value in /* do something */ }
}

@GestureState 없이 .onChanged 를 사용해서 좀더 심플하게 다음과 같이 구현해줄 수도 있다.

var theGesture: some Gesture {
    DragGesture(...)
        .onChanged { value in
            /* do something with value (which is the state of the fingers) */
        }
        .onEnded { value in /* do something */ }
}

그림그리기 같은 실제 손가락의 위치를 받아오는 경우 이렇게 .onChanged 를 사용해 더 간단하게 구현해줄 수 있지만, 

보통의 경우 실제 값이 아닌 상대적인 위치를 비교하여 제스처를 인식하는 경우가 많은데, 그럴 때에는 .updating()을 이용해서 구현해주어야 한다.   

 

 

 

참고 : Stanford iOS SwiftUI

728x90
반응형