콘텐츠로 건너뛰기
Home » Development » iOS - Cocoa Touch » Page 2

iOS – Cocoa Touch

(Swift) UIDynamic 예제

이전에 작성했던 UIDynamics 데모를 재작성했다.

  • swift3 문법을 적용했고,
  • 별도의 Xcode 프로젝트가 아니라 Playground 용으로 만들어서 바로 확인할 수 있게 했다.

UIDynamics를 적용하는 방법은 UIDynamicAnimator 객체를 만들고 여기에 애니메이션에 고려될 물리학적 요소 (중력이나 마찰등)를 behaivor로 설정해주면 된다. 애니메이터는 기준이 되는 레퍼런싱 뷰를 참조하면서 생성되고, 이후 해당 뷰 내의 뷰 계층 구조에 대해서 동역학을 계산하게 된다.
더 보기 »(Swift) UIDynamic 예제

UIDynamics를 사용하여 뷰들에 물리 시뮬레이션을 적용하기 – Swift

iOS 7.0부터 UIDynmic이라는 새로운 기술이 UIKit에 도입되었다. 이 기술은 UIView요소에 대해서 키 프레임 애니메이션등으로 구현하기 힘든 자연스러운 움직임을 쉽게 구현할 수 있게 해주는데, 대략 다음과 같은 것들이 있다.

이는 마치 2차원 UIView에 대해 각 뷰가 질량을 가지는 강체로 가정하고 중력, 질량가속도, 밀도, 탄성등을 적용한 물리 엔진에 의한 애니메이션 계산을 가능케 하는 것이다.더 보기 »UIDynamics를 사용하여 뷰들에 물리 시뮬레이션을 적용하기 – Swift

OpaquePointer

OpaquePointer OpaquePointer는 Swfit2.x 에서 COpaquePointer가 이름이 바뀐 타입으로 불투명한1 C 포인터를 감싸는 래퍼 타입이다.1 타입을 반입할 수 있는 구조체의 포인터라면 원 구조체 Tc타입을 Swift 로 반입할 수 있고, 이 경우에는 UnsafePointer<Tc> 의 형태로 쓸 수 있다. 하지만 원 타입을 Swift가 이해할 수 없다면, 그 타입의 크기를 결정할 수 없으므로 이에 대한 포인터 역시 Swift 내부에서 결정하는 것은 어렵다. 물론 UnsafePointer<Void> 타입을 이용하는 것도 가능하다 생각할 수 있지만, 이 경우에는 C에서 void * 타입이며, 어찌됐든 pass 시점에 캐스팅해야 하는 한계가 있다.… 더 보기 »OpaquePointer

SKNode를 이름으로 찾기 – SpriteKit / Swift

SKNode의 트리탐색

씬의 노드트리에서 어떤 노드를 탐색하고 특정하는 일이 종종 필요한데, 상위 노드에 대한 참조만 가지고 하위 노드를 찾기 위해서는 각 노드에 미리 이름을 부여하는 것이 필요하다. 노드의 .name 프로퍼티는 노드의 이름을 저장하며 알파벳과 숫자로만 이루어지며 공백이나 구두점등은 포함해서는 안된다.
노드의 이름은 중복되어도 상관없다.

playerNode.name = "player"
monsterNode1.name = "goblin"
monsterNode2.name = "ogre"

위 예에서 게임에 등장하는 고블린이 여러마리라면 이 고블린 노드의 이름은 제각각 유니크하기가 힘들것이며, "goblin"이라는 공통의 이름을 갖게 된다. 하지만 플레이어 캐릭터는 게임내에서 유니크하므로 다른 노드와 이름이 중복되지 않아야 한다.
더 보기 »SKNode를 이름으로 찾기 – SpriteKit / Swift

gcd in swift3

GCD in Swift3 iOS/OSX에서 동시성을 처리하기 위해서는 NSThread로부터 NSOpaerationQueue에 이르는 방법이 있었고, 시스템 레벨에서 모든 걸 관리해주는 GCD가 나오기에 이르렀다. 하지만 GCD는 libdispatch의 API를 그대로 사용했기 때문에 Swift에서는 가장 번거로운 문법을 이용해야 했었으나, Swift3에서 API를 전면적으로 개선했다. dispatch_async 이전에는 동기/비동기 여부를 결정한 후 어떤 큐를 쓸 것인지를 결정하는 순서로 코드가 작성되었는데, 이제는 이 순서가 바뀌었다. 왜냐면 dispatch_async, dispatch_sync는 자유함수에서 큐의 메소드로 편입되었기 때문이다. DispatchQueue.global(attributes:[.qosDefault]).async { // 백그라운드 작업 DispatchQueue.main.async(execute: { /* … */ }) } 큐의 속성은 생성시점에 지정될 수… 더 보기 »gcd in swift3

UIDynamics 예제

예전에 관련된 내용을 작성한 적이 있는데, 여기서는 내용과 예제를 좀 더 보강한 버전이다. 또한 해당 예제들은 모두 Swift3 버전으로 작성되었다.

UIDynamicAnimator

다이내믹 애니메이터는 물리연산과 관련된 계산이나 애니메이션을 다이내믹 아이템에 적용하고, 그 결과로 계산된 애니메이션 컨텍스트를 제공한다.
더 보기 »UIDynamics 예제

날짜와 시간을 다루기 – Swift Date/Time

날짜와 관련된 계산은 사실 알고보면 굉장히 복잡하고 어려운 작업이다. 날짜와 시간의 상관관계에 대해서 몇 가지 규칙들을 나열해보면 우리가 일상적으로 사용하는 날짜나 시간에 관한 규칙이 사실은 엄청나게 복잡하다는 것을 알게 된다. 기본적으로 초(second)를 가장 기본적인 시간의 단위로 생각한다. (더 작은 단위로 밀리초나 나노초가 있지만, 이들은 10진법 기반이므로 따로 생각하지 않아도 된다.) 초와 분은 60도법으로 계산된다. 60초는 1분, 60분은 1시간이다. 하루는 24시간으로 이루어진다. (그리고 놀랍게도 시계가 표시하는 시간은 지구상에서의 위치에 따라 또 다르다.) 사실 여기까지 생각했을 때는 별로 어렵지 않다. 하지만 날짜가… 더 보기 »날짜와 시간을 다루기 – Swift Date/Time

(Swift) Process를 이용한 외부 프로세스 이용

파이썬의 Subprocess 모듈을 사용하는 것과 비슷하게, Objective-C에서는 NSTask를 사용하여 프로세스 내에서 다른 외부 프로세스를 실행할 수 있다. Swift로 넘어오면서 NSTask는 브릿징을 통해서 그대로 사용 가능했지만, API를 좀 더 모던하게 개선한 Process라는 별도의 클래스가 새롭게 정의되었다. Process를 사용하여 외부 프로세스의 출력 결과를 가져오는 방식은 .standardOutput 프로퍼티를 이용하여 Pipe를 통해 데이터를 받을 수 있다.

외부 프로세스가 실행되는 동안 .waitUntilExit()를 통해서 프로세스 흐름을 블럭하고 기다리는 방법도 있지만, GUI를 사용하는 경우에는 UI가 멈춰버리기 때문에 .terminationHandler를 사용하여 서브 프로세스 실행이 완료되었을 때, 런루프가 지정한 적절한 시점에 콜백을 실행할 수도 있다.

파이프를 통한 결과 획득

Process 객체를 생성하고 실행할 때 standardOutput, standardInput 등의 속성에 Pipe 객체를 지정해주면, 해당 프로세스의 표준 입출력을 프로그램에서 사용할 수 있다. 프로세스는 생성한 후에 launchPatharguments 를 지정하여 실행할 명령의 경로와 인자를 전달한다. 그런다음 실행(launch)한 후에 .waitUntilExit()를 통해서 해당 프로세스가 종료될때까지 기다렸다가 파이프에 들어온 데이터를 읽으면 된다.

import Foundation

let task = Process()
let pipe = Pipe()
task.launchPath = "/bin/ls"
task.standardOutput = pipe
try? task.run()
task.waitUntilExit()
// FileHandle.availableData: Data (Data? 타입이 아님)
if case let data = pipe.fileHandleForReading.availableData, data.count > 0 {
    String(data:data, encoding:.utf8)?.split(separator:"\n").forEach{ print($0) }
}

파이프를 한 번 읽고나면 파이프는 닫히기 때문에, waitUntilExit()를 호출해서 프로세스가 완전히 끝날 때까지 대기해야한다. GUI에서는 이 메소드가 블럭하면서 UI가 프리징될 수 있기 때문에, 핸들러를 통한 처리 방식을 사용할 것이 권장된다.

더 보기 »(Swift) Process를 이용한 외부 프로세스 이용

오퍼레이션 큐 (Operation Queue)

코코아에서 비동기 작업이나 백그라운드 작업을 실행하는 OOP 스타일의 전통적인 방식은 NSOperation 클래스를 사용하는 것이었다. 이 클래스는 실행할 작업을 객체로 감싸면서 백그라운드 실행이나 의존성, 실행 상황에 대한 KVO 등 많은 기능들을 제공해주기는 했지만, 그 자체로는 추상 클래스였기 때문에 이 클래스를 상속하여 커스텀 클래스를 작성해서 사용해야 하는 불편함이 있었다. 이후 Objective-C 2.0에서 코드 블럭이 본격적으로 활용되기 시작하면서 NSBlockOperation 과 같은 코드 블럭을 사용한 간편한 작업 객체 생성이 가능했는데, 우선순위나 의존성 등의 오퍼레이션 객체의 기능이 요구되지 않는 상황에서는 작업 큐 만으로 동기/비동기 작업을 간단히 관리할 수 있게 되었다.

비동기 작업을 위한 큐는 크게 오퍼레이션 큐와 디스패치 큐의 두 종류가 있다. 사실 내부적으로 이 둘은 모두 GCD를 사용하기 때문에(iOS 4.0부터 NSOperationQueue는 GCD를 사용하기 시작했다.) 본질적으로는 같다고 볼 수 있다. 대신에 오퍼레이션 큐는 추가된 코드블럭을 내부적으로 NSBlockOperation으로 만들어서 관리하며, 기존의 오퍼레이션 객체를 추가할 수 있다. 따라서 의존성에 따른 실행 순서를 지정해야 하거나, 특정 타임 아웃 내에 작업을 중단해야 하는 등의 추가적인 관리 기능을 사용할 수 있다.

용도 측면에서 본다면 디스패치 큐는 성능이나 메모리의 오버헤드를 최소화하여 오래 걸리지 않는 작은 규모의 작업을 한꺼번에 실행하면서 CPU 성능을 최적으로 활용하고 싶을 때 사용할 수 있으며, 오퍼레이션 큐는 개별 작업을 관리해야 하고, 시간이 오래 걸릴 수 있는 (그래서 중간에 중지해야 할 수도 있는) 작업을 수행할 때 더 적합하다 하겠다.

더 보기 »오퍼레이션 큐 (Operation Queue)

Contacts 프레임워크

Contacts 프레임워크를 이용한 주소록 액세스

iOS8 까지는 AddressBook 프레임워크를 이용해서 시스템의 주소록 데이터베이스에 액세스할 수 있었는데, iOS9에서는 이 프레임워크 자체가 deprecated 되었다. (헐…) 대신에 연락처를 액세스하는 별도의 프레임워크인 Contacts가 신설되었다. 더 보기 »Contacts 프레임워크