콘텐츠로 건너뛰기
Home » Swift » 페이지 11

Swift

Swift / Cocoa / Foundation / Programming Language / UIKit / AppKit / Swift Standard Library / Swift 문법과 기능 / 공부하면서 알게된 내용들을 정리 / 어느 프로그래밍 언어 덕후의 연습장

오일러 프로젝트 34

숫자 145에는 신기한 성질이 있습니다. 각 자릿수의 팩토리얼(계승)을 더하면 1! + 4! + 5! = 1 + 24 + 120 = 145 처럼 자기 자신이 됩니다. 이렇게 각 자릿수의 팩토리얼을 더하면 자기 자신이 되는 모든 수의 합을 구하세요. 단, 1! = 1 과 2! = 2 의 경우는 덧셈이 아니므로 제외합니다.

http://euler.synap.co.kr/prob_detail.php?id=34
더 보기 »오일러 프로젝트 34

오일러 프로젝트 32

1부터 n까지의 각 숫자를 한번씩만 써서 만들 수 있는 숫자를 팬디지털(pandigital)이라고 합니다. 예를 들면 15234는 1부터 5의 숫자가 한번씩만 쓰였으므로 1 ~ 5 팬디지털입니다. 7254라는 숫자는 그런 면에서 특이한데, 39 × 186 = 7254 라는 곱셈식을 만들 때 이것이 1 ~ 9 팬디지털이 되기 때문입니다. 이런 식으로 a × b = c 가 1 ~ 9 팬디지털이 되는 모든 c의 합은 얼마입니까? (참고: 어떤 c는 두 개 이상의 (a, b)쌍에 대응될 수도 있는데, 이런 경우는 하나로 칩니다)

http://euler.synap.co.kr/prob_detail.php?id=32
더 보기 »오일러 프로젝트 32

Swift 면접질문들

Swift 면접 질문이라는데… 난이도는 그리 높지 않은 편이다. http://www.toptal.com/swift/interview-questions 1 다음 코드를 보고 질문에 답하시오 var array1 = [1, 2, 3, 4, 5] var array2 = array1 array2.append(6) var len = array1.count 문: len 값은 얼마이며, 왜 그런가요? 답: 5. Swift의 Array는 값 시멘틱이며, 다른 변수에 대입하게 되면 복사가 일어난다. 따라서 array2는 array1과는 다른 독립된 사본이며, array2.append(6)가 실행되더라도 array1은 변하지 않는다. 2 다음 코드를 보고 질문에 답하시오 let op1: Int = 1 let op2: UInt = 2 let op3: Double… 더 보기 »Swift 면접질문들

커링함수 코드 만들기

Swift의 차기 버전에서는 자동 커링 함수를 만드는 기능이 제거된다고 한다.  예를 들어 func add(x: Int)(_ y:Int) -> Int { return x + y } let plusOne = add(1) let y = plusOne(4) // y = 5 이런 형태로 함수를 만들 때부터 커링을 지원하도록 하던 기능이 없어진다. 커링함수는 이 기능을 쓰지 않고도 클로저를 리턴하는 함수를 이용해서 만들 수는 있다. func curry <A, B, C>(body: (A, B) -> C) -> A -> B -> C { return { x in { y… 더 보기 »커링함수 코드 만들기

(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를 이용한 외부 프로세스 이용

(Swift) 키보드로부터 문자열을 입력받기

Swift의 표준 함수 중에서 input() 과 같은 함수가 없었는데, readLine() 함수가 생겼다. 원형은 다음과 같다. 이 함수는 키보드로부터 입력받은 문자열을 (UTF-8로 가정한다) 리턴해준다. 물론 디코딩상의 문제가 있을 수 있어서 출력되는 값은 옵셔널이다. Swift에서는 C함수를 그대로 사용할 수 있고, C의 표준 라이브러리들은 기본적으로 Foundation 프레임워크에 포함되어 있는데, 요상하게 입출력에 관련된 함수 (scanf, printf 등)은 호출할 수가 없었다. 이 함수가 추가하기 전에는 표준입력을 NSFileHandle로 구현해서 다음과 같이 구현해야 했다. 프롬프트를 포함하는 키보드 입력 받기 대신 readLine() 함수는 파이썬의 input() 처럼 프롬프트를 지정할… 더 보기 »(Swift) 키보드로부터 문자열을 입력받기

Functor의 개념과 Swift내의 functor

배열은 Swift에서 동일 타입의 원소를 하나 이상 가질 수 있는 순서있는 집합을 나타내는 자료 구조이다. 배열은 Swift 뿐만 아니라 거의 모든 프로그래밍 언어에서 가장 기본적이며 중요한 자료 구조 중 하나인데, 특히 함수형 프로그래밍 언어에서는 배열을 리스트라고 하는 재귀적인 데이터 구조를 사용하여 일련의 연속적인 값들을 집합으로 다루게 된다. 배열 혹은 리스트에 대한 연산 중에서 가장 대표적인 것은 맵핑 연산이다.  하스켈의 fmap 은 임의의 타입의 원소를 갖는 리스트의 각 원소에 대해 주어진 함수를 적용하여 새로운 리스트를 생성한다. 그리고 대부분의 배열을 지원하는 현대 언어들도 비슷한 기능을 가지고 있다. 자바 스크립트의 Array와 Swift의 Array도 공통적으로 map이라는 메소드를 통해서 변형(transform)함수를 받아 자신의 원소들에게 적용하여 유사한 동작을 수행한다.

더 보기 »Functor의 개념과 Swift내의 functor

오퍼레이션 큐 (Operation Queue)

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

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

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

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

(Swift) iOS, OSX에서 이미지 저장하기

이미지를 저장하기

이미지를 JPEG, PNG 데이터로 만드는 것은 UIKit의 표준함수를 이용할 수 있다.

func UIImageJPEGRepresentation(_ image: UIImage!, _ compressionQuality: CGFloat) -> NSData!
func UIImagePNGRepresentation(_ image:UIImage!) -> NSData!

이를 이용해서 데이터를 저장할 수 있다. NSData로 만들어서 그냥 저장하면 되니까.

func saveImage(image: UIImage, toURL url: NSURL, withFormat format:ImageSavingFormat = .PNG) {
    let data: NSData
    switch format {
    case .PNG:
        data = UIImagePNGRepresentation(image)
    case .JPEG:
        data = UIImageJPEGRepresentation(image, 1.0)
    }
    var error: NSError?
    data.writeToURL(url, atomically: false, error: &error)
    if error != nil {
        println("Fail to save image")
    } else {
        println("successfully saved.")
    }
}

더 보기 »(Swift) iOS, OSX에서 이미지 저장하기