검색결과 리스트
2015/07에 해당되는 글 5건
- 2015.07.30 [swift2] Xcode7 beta4 Swift 언어 변경사항
- 2015.07.16 [swift] 성능향상 시키기 - 다이나믹 디스패치를 최소화
- 2015.07.11 [swift2] Xcode7 beta3 Swift 언어 변경사항
- 2015.07.10 [swift2] Swift에서 에러 처리 (Error Handling)
- 2015.07.01 [swift2] 타입의 텍스트적인 표현 커스터마이징하기
글
[swift2] Xcode7 beta4 Swift 언어 변경사항
드디어 Xcode7 beta4가 공개되었네요! beta4 에서 Swift 언어 변경사항에 대해 알아볼까요?
Objective-C Language Changes
1. 더블 언더스코어 nullability 한정자들 이름이 변경되었습니다.
- as is: __nullable, __nonnull, __null_unspecified
- to be: _Nullable, _Nonnull, _Null_unspecified
- 소스 호환성을 위해 컴파일러가더블 언더스코어 이름을 새로운 이름으로 맵핑하는 매크로를 정의해줍니다.(predefine)
Swift Language Changes
1. Enum과 Case에 indirect 키워드를 사용할 수 있습니다.
- indirect 키워드를 사용해서 재귀적인 데이터 구조를 정의할 수 있음.
- 재귀적인 데이터 구조 정의시 enum의 연관값은 간접적으로 저장됨
enum List<T> {
case Nil
indirect case Cons(head: T, tail: List<T>)
}
indirect enum Tree<T> {
case Leaf<T>
case Branch(left: Tree<T>, right: Tree<T>)
}
2. class 객체를 참조하는 AnyObject, NSObject 변수를 class Object 타입으로 복원이 가능합니다.
let x:AnyObject = NSObject.self // NSObject 클래스 객체를 AnyObject로 캐스팅
let y = x as! NSObject.Type // AnyObject를 NSObject 클래스 객체로 복원
3. class 객체를 포함하는 Array,Dictionary,Set 을 NSArray,NSDictionary,NSSet로 브리징할 수 있습니다.
- [NSURLSessionConfiguration protocolClasses]과 같이 NSArray * 객체를 반환하는 Objective-C API도 이제 Swift에서 정상동작합니다.
4. 클래스에 적용한 @objc 속성은 Objective-C 헤더에 생성된 클래스의 컴파일타임 이름 뿐만 아니라 런타임 이름도 변경합니다.
- 프로토콜에도 적용됨
// Swift
@objc(MyAppDelegate)
class AppDelegate : NSObject, UIApplicationDelegate {
//...
}
// Objective-C
@interface MyAppDelegate : NSObject <UIApplcationDelegate>
// ...
@end
5. 스칼라값의 0 엘리먼트를 참조하는 기능은 제거되었습니다.
6. 타입검사 제약시스템이 생성한 에러 진단메시지가 beta4에서 개선되었습니다. 이후 베타버전에서 더 많은 부분들이 개선될 예정입니다.
7. SinkType 프로토콜과 SinkOf 구조체가 표준 라이브러리에서 제거되고 대신 (T) -> () 클로져를 사용합니다.
8. ExtensibleCollectionType 부모프로토콜이 서브 프로토콜 RangeReplaceableCollectionType로 통함되었습니다.
- RangeReplaceableCollectionType 은 subRange를 다른 컬렉션의 엘리먼트들로 교체를 지원하는 컬렉션 타입.
- 기본구현을 위한 메소드들이 추가됨.
- 이 프로토콜들과 연관된 (free) Swift 모듈 함수들 대신 이 메서드들을 사용할 수 있습니다.
9. Unmanaged를 사용한 속성과 메서드들도 Objective-C에 노출가능합니다.
- Unmanaged는 unmananged 객체 레퍼런스를 전달하기 위한 타입.
- 이 타입을 사용하면 객체가 살아있도록 유지할 책임이 있음.
10. performSelector 류의 API 들 Swift 코드에서 사용가능합니다.
11. __unsafe_unretained로 마크된 C 구조체 필드는 Swift에 Unmanaged 로 표시됩니다.
- Swift 컴파일러는 이 참조들이 실제로 strong(+1) 또는 unretained(+0)로 의도되었는지는 알수 없음.
12. Swift 문서 주석들은 최상위 목록아이템을 인식합니다.
- Throws: ... 구문은 어떤 에러가 왜 던져질수 있는지 문서화하기 위해 사용합니다.
- Xcode QuickHelp의 파라미터 및 반환값 설명 옆에 표시됩니다.
13. 타입은 그 타입보다 더 낮은 버전에서 가용한 프로토콜을 구현할 수 있습니다.
@available (iOS 9.0, *)
protocol P { ... }
@available (iOS 7.0, *)
class MyController : UIViewController, P {
...
}
'Swift' 카테고리의 다른 글
| [swift1.2] Swift 프로토콜 지향 프로그래밍 (0) | 2015.08.06 |
|---|---|
| [swift] 문자열과 문자 -1 (Strings and Characters) (0) | 2015.08.01 |
| [swift2] Xcode7 beta4 Swift 언어 변경사항 (0) | 2015.07.30 |
| [swift] 성능향상 시키기 - 다이나믹 디스패치를 최소화 (0) | 2015.07.16 |
| [swift2] Xcode7 beta3 Swift 언어 변경사항 (0) | 2015.07.11 |
| [swift2] Swift에서 에러 처리 (Error Handling) (0) | 2015.07.10 |
설정
트랙백
댓글
글
[swift] 성능향상 시키기 - 다이나믹 디스패치를 최소화
애플 Swift 블로그의 [Increasing Performance by Reducing Dynamic Dispatch] 를 번역한 글입니다.
다른 언어들처럼 Swift도 수퍼클래스에 선언된 메서드와 속성을 오버라이드 할수 있습니다.
이말은 곧 프로그램이 런타임에 어떤 메서드와 프로퍼티를 참조할 것인지 결정해야하고, 간접호출 또는 간접접근을
수행해야 한다는 것을 의미합니다. 다이나믹 디스패치(dynamic dispatch)라고 불리는 이 기술은,
간접 호출/접근 횟수마다 일정량의 런타임 오버헤드 비용을 증가시킵니다. 성능에 민감한 코드에서는 그와같은 오버헤드
종종 바람직하지 않습니다. 이 포스트는 다이나믹함을 제거함으로써 성능을 향상시키는 3가지 방법에 대해 알려드립니다.
: final, private, 모듈 최적화.
다음 예를 살펴보겠습니다.
class ParticleModel {
var point = ( 0.0, 0.0 )
var velocity = 100.0
func updatePoint(newPoint: (Double, Double), newVelocity: Double) {
point = newPoint
velocity = newVelocity
}
func update(newP: (Double, Double), newV: Double) {
updatePoint(newP, newVelocity: newV)
}
}
var p = ParticleModel()
for i in stride(from: 0.0, through: 360, by: 1.0) {
p.update( (i * sin(i), i), newV: i*1000 )
}
작성된데로, 컴파일러는 동적으로 호출을 dispatch 할 것입니다.
1. p의 upodate 호출
2. p의 uodatePoint 호출
3. p의 point 튜플 속성에 접근한다
4. p의 velocity 속성에 접근한다
이것은 코드를 보면서 기대했던 것이 아닐수 있습니다. 동적 호출은 ParticleModel의 서브클래스들이 point 또는 velocity 를
계산속성이나 새롭게 구현된 updatePoint() 또는 update()로 오버라이딩 할수 있기 때문에 필수적입니다.
Swift에서 동적 디스패치콜은 메서드 테이블에서 함수를 찾고 간적호출을 수행하는 방식으로 구현되어집니다. 이것은 직접호출로
수행하는 것보다 더 느립니다. 게다가 간접호출은 많은 컴파일러 최적화를 막아 간접호출이 훨씬 더 많은 비용이 들도록 합니다.
성능 크리티컬한 코드에서 성능을 향샹시킬 필요가 있을때 다이나믹 행동을 제한하기 위해 사용할 수 있는 기술들이 있습니다.
1. 오버라이딩 할 필요가 없는 속성 선언에는 final을 사용하세요.
final은 클래스, 메서드, 속성이 오버라이드 할 수 없도록 제약하는 키워드입니다. 이렇게 하면 컴파일러가 다이나믹 디스패치의
간접호출/접근을 생략할 수 있게 합니다. 아래 예제의 point, velocity는 객체의 저장속성으로부터 직접적으로 액세스되고, updatePoint()는 direct 함수콜을 통해 호출됩니다. 반면 udpate()는 여전히 동적 디스패치를 통해 호출되며 서브클래스가 update()를 오버라이 할 수 있습니다.
class ParticleModel {
final var point = ( x:0.0, y:0.0 )
final var velocity = 100.0
final func updatePoint(newPoint: (Double, Double), newVelocity: Double) {
point = newPoint
velocity = newVelocity
}
func update(newP: (Double, Double), newV: Double) {
updatePoint(newP, newVelocity: newV)
}
}
var p = ParticleModel()
for i in stride(from: 0.0, through: 360, by: 1.0) {
p.update( (i * sin(i), i), newV: i*1000 )
}
final를 사용하여 전체 클래스 자체를 final로 만들수 있습니다. 이렇게 하면 서브클래싱이 불가능해지며 클래스의 모든 함수와 속성들이 final이 됩니다.
final class ParticleModel {
var point = ( x: 0.0, y: 0.0 )
var velocity = 100.0
// ...
}
2. private 키워드를 사용하면 한 파일에서만 참조되는 final 선언임을 추론할수 있습니다.
private 키워드를 선언부에 적용하면 현재파일에만 선언이 노출되도록 가시성을 제한합니다. 이것은 컴파일러가 모든 잠재적인 오버라이딩 선언을
찾을 수 있도록 합니다. 오버라이딩 선언이 없으면 컴파일러는 자동으로 final 키워드를 추론하고 메서드와 속성 접근에 대해 간접호출
(indirect calls)들을 제거합니다.
현재 파일에 ParticleModel 클래스에 대한 오버라이딩이 없다고 판단되면, 컴파일러는 private으로 선언된 모든 dynamic dispatch call을
직접호출로 대체합니다.
class ParticleModel {
private var point = ( x:0.0, y:0.0 )
private var velocity = 100.0
private func updatePoint(newPoint: (Double, Double), newVelocity: Double) {
point = newPoint
velocity = newVelocity
}
func update(newP: (Double, Double), newV: Double) {
updatePoint(newP, newVelocity: newV)
}
}
var p = ParticleModel()
for i in stride(from: 0.0, through: 360, by: 1.0) {
p.update( (i * sin(i), i), newV: i*1000 )
}
이전 예제에서처럼, point, velocity는 직접접근되며 updatePoint()는 직접호출 됩니다. 하지만 update()는 private이 아니기
때문에 간접적으로 호출됩니다.
final과 마찬가지로 클래스 선언부에 private을 사용하여 클래스 자체를 private로 만들고 그에 따라 모든 속성과 메서드를 private하게 만들
있습니다.
private class ParticleModel {
var point = ( x: 0.0, y: 0.0 )
var velocity = 100.0
}
3. internal 선언을 final로 추론할수 있는 전체 모듈 최적화를 사용하세요.
internal 접근자를 갖는 선언(디플트값)은 그들이 선언된 모듈 내에서만 볼수 접급될 수 있습니다. swift는 일반적으로 모듈을 구성하는
파일들을 개별적으로 컴파일하기 때문에 컴파일러는 internal 선언이 다른 파일에서 오버라이딩 됐는지 알수 없습니다. 그러나 전체 모듈최적
옵션을 활성화하면 모든 모듈이 동시에 한번에 컴파일 됩니다. 이렇게 하면 전체 모듈에 대해 컴파일러가 추론할수 있게되어 오버라이딩 되지
않은 internal 선언을 final로 추론할 수 있게됩니다.
원래 코드로 되돌아가서 이번에는 ParticleModel에 몇몇 public 키워드를 추가해보겠습니다.
public class ParticleModel {
var point = ( x:0.0, y:0.0 )
var velocity = 100.0
func updatePoint(newPoint: (Double, Double), newVelocity: Double) {
point = newPoint
velocity = newVelocity
}
public func update(newP: (Double, Double), newV: Double) {
updatePoint(newP, newVelocity: newV)
}
}
var p = ParticleModel()
for i in stride(from: 0.0, through: 360, by: 1.0) {
p.update( (i * sin(i), i), newV: i*1000 )
}
모듈 최적화(Module Optimization) 옵션을 활성화하고 이 코드를 컴파일하면, 컴파일러는 point, velocity,
updatePoint() 함수를 final로 추론할수 있습니다. 반면 udpate()는 public 접근자를 갖기 때문에 final로 추론
될 수 없습니다.
'Swift' 카테고리의 다른 글
| [swift] 문자열과 문자 -1 (Strings and Characters) (0) | 2015.08.01 |
|---|---|
| [swift2] Xcode7 beta4 Swift 언어 변경사항 (0) | 2015.07.30 |
| [swift] 성능향상 시키기 - 다이나믹 디스패치를 최소화 (0) | 2015.07.16 |
| [swift2] Xcode7 beta3 Swift 언어 변경사항 (0) | 2015.07.11 |
| [swift2] Swift에서 에러 처리 (Error Handling) (0) | 2015.07.10 |
| [swift2] 타입의 텍스트적인 표현 커스터마이징하기 (0) | 2015.07.01 |
설정
트랙백
댓글
글
[swift2] Xcode7 beta3 Swift 언어 변경사항
Swift Language Changes
1. 표현식 결과 포맷팅 방식 변경
po 또는 expr -O를 사용할 때 Swift 표현식 결과를 포맷팅하는 방식이 beta3에서 상당히 변화되었습니다.
첫 번째 beta 버전에서 소개되었던 Customization이 다음과 같은 방식으로 개선되었습니다.
CustomDebugStringConvertible 또는 CustomStringConvertible 프로토콜을 구현하는 타입들은
상대적으로 debugDescription, description 메소드를 사용하여 포맷팅 결과를 제공합니다. 둘다 구현하지 않은경우
타입이름이 출력되고, 레퍼런스 타입들은 Objective-C 클래스처럼 참조되는 주소를 보여줄 것입니다.레퍼런스 타입들과는 다르게 enums, tuples, struct 같은 value 타입들은 디폴트로 summary 아래에 모든 멤버들이
들여쓰기 되어 보여질것입니다. CustomReflectable 구현함으로써 이러한 동작들을 커스터마이징 할수 있습니다.
출력 커스터마이징은 모든 필드와 값들의 리스트를 제공하기 위해 p 또는 expr을 -O옵션없이 사용해서 건너뛸 수 있습니다.
2. String 타입 Enum의 기본값
string raw타입으로 선언된 enum 엘리먼트가 명시적으로 raw value를 갖지 않으면, enum의 이름을 디폴트 텍스트로
갖습니다.
예를 들어 다음 선언은
enum WorldLayer : String {
case Ground, BelowCharacter, Character
}
아래와 동일합니다.
enum WorldLayer : String {
case Ground = "Ground"
case BelowCharacter = "BelowCharacter"
case Character = "Character"
}
3. 이름 없는 파라미터
이름없는 파라미터는 명시적으로 이름이 없음을 의미하는 _:를 사용합니다**. 예를 들어 다음은 이제 에러입니다.
func f(Int) {} // 에러
다음과 같이 작성되야합니다.
func f(_:Int) {}
이것이 인자의 레이블 모델을 단순화시킵니다.
그리고 func f((a: Int, b:Int)) 같은 경우에 a 그리고 b라는 이름의 파라미터를 가지지 않는지 명료하게 해줍니다.
4. array에 tuple 추가가 가능합니다.
5. Objective-C 클래스의 제네릭 서브클래싱이 지원됩니다.
6. 문법이 조정되어 .으로 시작하는 라인들은 항상 메서드 또는 프로퍼티 룩업으로 파싱되어 다음과 같은 코드 포맷팅이 가능합니다.
foo
.bar
.bas = 68000
문맥에 따른 static member looup 으로 시작하는 라인은 더이상 사용 불가능합니다.
.staticVar = MyType()
7. try!
try! 표현식에서 발생한 에러, 최상위 또는 playground에서 처리되지 않은 에러들은 trap 메시지에 에러 값들이 표시됩니다.
8. NS_REFINDED_FOR_SWIFT 매크로
오리지널 구현을 사용가능하면서도, Swift의 동일 API에서는 더 좋은 버전을 제공하기 위해 NS_REFINED_FOR_SWIFT
매크로는를 Objective-C 선언부에 사용할수 있습니다. 예를 들어 클래스를 인자로 받는 Objective-C API는 Swift에서는
파라미터 타입을 더 정밀하게 제공할수 있습니다.
NS_REFINDED_FOR_SWIFT 매크로는 경우에 따라 다르게 동작합니다.
- init 메소드는 첫 번째 외부 파라미터 이름에 __이 붙는 initializer가 임포트 됩니다.
- (instancetype)initWithClassName:(NSString*)name NS_REFINED_FOR_SWIFT
=> init(__className:String)
- 다른 메소드들은 기본이름에 __이 붙어 임포트 됩니다.
- (NSString*)displayNameForMode:(DisplayMode)mode NS_REFINED_FOR_SWIFT;
=> func __displayNameForMode(mode:DisplayMode) -> String
subscript 메소드는 다른 메서드들처럼 취급되며 subcript로 임포트 되지 않습니다.
다른 선언들은 이름 앞에 __이 붙습니다.
@property DisplayMode mode NS_REFINED_FOR_SWIFT;
var __mode:DisplayMode { get set }
9. 타입 제네릭 파라미터
Swift 표준 라이브러리에서 제공하는 타입 제네릭 파라미터들은 API에서 타입의 역할을 반영하도록 이름이 변경되었습니다.
예를 들어 Array
'Swift' 카테고리의 다른 글
| [swift2] Xcode7 beta4 Swift 언어 변경사항 (0) | 2015.07.30 |
|---|---|
| [swift] 성능향상 시키기 - 다이나믹 디스패치를 최소화 (0) | 2015.07.16 |
| [swift2] Xcode7 beta3 Swift 언어 변경사항 (0) | 2015.07.11 |
| [swift2] Swift에서 에러 처리 (Error Handling) (0) | 2015.07.10 |
| [swift2] 타입의 텍스트적인 표현 커스터마이징하기 (0) | 2015.07.01 |
| [swift2] Xcode7 beta2 Swift 언어 변경사항 (0) | 2015.06.24 |
설정
트랙백
댓글
글
[swift2] Swift에서 에러 처리 (Error Handling)
(본 포스트는 The Swift Programming Language - Swift 2 Prerelease. 의 Error Handling 장을 번역한 문서입니다.)
에러처리는 프로그램에서 에러조건에 대응하고 회복하는 과정입니다. Swift는 런타임에 회복 가능한 에러를 던지고, 잡고,
전파하고, 조작하는 first-class(1급) support를 제공합니다. 몇몇 함수와 메소드는 항상 완전한 실행과 유용한 정보를
출력한다고 보장할 수 없습니다. Optional은 값의 부재를 표현하기 위해 사용되지만 함수가 실패했을때 실패원인을 이해하고
거기에 맞춰 코드를 대응하는게 더 유용할때가 있습니다.
디스크의 파일로부터 데이터를 읽고 처리하는 작업을 예로 들어보겠습니다.
경로에 파일이 없거나 읽기 권한이 없거나, 파일이 호환되지 않는 포맷으로 인코딩 되어있는 것 등 여러가지 이유로 작업이
실패할 수 있습니다. 이러한 상황의 차이를 구별하고 필요하다면 사용자와 커뮤니케이션해야 에러를 해결하고 회복할수 있습니다.
1. 에러의 표현 (Representing Errors)
스위프트에서 에러는 ErrorType 프로토콜을 구현하는 타입값으로 표현됩니다.
Swift enumerations는 특히 관련있는 에러조건(에러의 원인에 대한 정보를 연관값으로 가진채) 그룹을 모델링하는데
적합합니다. 이러한 이유로, Swift enumerations는 ErrorType을 자동으로 구현하고, 컴파일러에 의해 생성된 구현체를 갖습니다.
자판기의 에러조건을 표현하기 위한 예입니다.
enum VendingMachineError: ErrorType {
case InvalidSelection
case InsufficientFunds(required: Double)
case OutOfStock
}
이 예제에서 자판기는 다음과 같은 이유로 실패할수 있습니다.
- 1. 요청한 아이템이 유효한 선택이 아닌 경우. InvalidSelection 으로 표현.
- 2. 요청한 아이템 비용이 입금한 비용보다 더 큰 경우. InsufficentFunds로 표현.
연관된 Double 값은 트랜잭션을 완료하기 위해 필요한 추가요금. - 3. 요청한 아이템의 재고가 없는 경우. OutOfStock으로 표현.
2. 에러 던지기 (Throwing Errors)
함수 또는 메서드가 에러를 던질수 있다는것을 나타내기 위해, 선언부의 파라미터 다음에 throws 키워드를 사용합니다.
만일 return 타입이 있으면, throws 키워드는 리턴 화살표 앞에 표기합니다. 함수, 메소드, 클로져는 명시적으로 표시하지
않으면 에러를 던질 수 없습니다.
func canThrowErrors() throws -> String
func canThrowErrors() -> String
throws를 선언한 함수의 몸체 어느 시점에서도 throw 문을 사용하여 에러를 던질수 있습니다.
아래 예제에서 vend(itemNamed:) 함수는 요청한 아이템의 재고가 없거나, 금액이 부족할 때 에러를 던집니다.
stuct Item {
var price:Double
var count:Int
}
var inventory = [
"Candy Bar": Item(price:1.25, count:7),
"Chips": Item(price: 1.00, count:4),
"Pretzels": Item(price: 0.75, count:11)
]
var amountDeposited = 1.00
func vend(itemNamed name:String) throws {
guard var item = inventory[name] else {
throw VendingMachineError.InvalidSelection
}
guard item.count > 0 else {
throw VendingMachineError.OutOfStock
}
if amountDeposited >= item.price {
amountDeposited -= item.price
--item.count
inventory[name] = item
} else {
let amountRequired = item.price - amountDeposited
throw VendingMachineError.InsufficentFunds(required: amountRequired)
}
}
먼저 quard 문은 item 상수와 count 변수를 inventory의 대응하는 값과 바인드하기 위해 사용되었습니다.
item 이 inventory에 없으면 InvalidSelection 에러를 던집니다. 그 다음으로 요청한 item의 count를 체크해
가용성을 결정합니다. count가 0보다 같거나 작으면 OutOfStock 에러를 던집니다. 마지막으로 요청한 아이템의 가격과
현재 입금된 금액을 비교합니다. 입금된 금액이 아이템의 가격보다 크면, 입금액에서 가격만큼 차감되고, inventory에 있는
재고량이 감소합니다. 그리고 함수는 요청한 아이템을 반환합니다. 그렇지 않으면 초과된 금액이 연관값으로 전달되어 InsufficentFunds 에러를 던져집니다. throw 문은 즉시 프로그램의 제어를 이동시키기 때문에 아이템은 구매를 위한
모든 요구조건이 만족 될때만 판매됩니다.
throwing 함수를 호출할 때, 호출부 앞에 try를 붙힐 수 있습니다. 이 키워드는 함수가 에러를 던질수 있고,
try 이후 코드라인들이 실행되지 않을 수 있음을 암시합니다.
let favoriteSnacks = [
"Alice": "Chips",
"Bob": "Licorice",
"Eve": "Pretzels"
]
func buyFavoriteSnack(person:String) throws {
// a ?? b 구문은 a가 nil이 아니면 a를, nil이면 b를 반환.
let snackName = favoriteSnacks[person] ?? "Candy Bar"
try vend(itemNamed: snackName)
}
buyFavoriteSnack() 함수는 person이 가장 좋아하는 snack을 찾고, 그것을 구매하려고 시도합니다.
좋아하는 snack이 리스트에 없다면 candy bar를 사려고 시도합니다. 에러를 던질수도 있는 vend 함수가 호출되기
때문에 try 를 함수 앞에 사용했습니다. buyFavoriteSnack(_:) 함수는 throwing 함수이기 때문에, vend 함수
던지는 어떤 에러도 buyFavoriteSnack 함수가 호출되는 상위로 전파될수 있습니다..
3. 에러를 잡고 처리하기 (Catching and Handling Errors)
에러를 잡아 처리하기 위해 do-catch 문을 사용할 수 있습니다.
do {
try function that throws
...
} catch pattern {
statements
}
에러가 던져지면 catch 절에 의해 처리 될때까지 에러는 외부 스코프로 전파됩니다. catch 절은 catch 키워드 다음에
매칭할 에러패턴 그리고 실행할 구문집합으로 구성됩니다. switch 문처럼 컴파일러는 catch절이 모두 포괄되어 있는지
검사합니다. 그러한 결정이 이루어지면 에러는 처리됩니다. 해당 스코프에서는 에러를 처리하거나 또는 함수가 throws로
선언되어야 합니다. 에러가 처리됐다는 것을 보장하기 위해 모든 에러들과 매칭되는 패턴을 가진 catch절을 사용합니다.
catch절이 패턴을 명시하지 않으면 그 절은 로컬상수 error에 모든 에러를 매칭하여 바인딩합니다. 패턴 매칭에 관한 더
자세한 정보는 Patterns 장을 참고하세요.
do {
try vend(itemNamed: "Candy Bar")
} catch VendingMachineError.InvalidSelection {
print("Invalid Selection.")
} catch VendingMachineError.OutOfStock {
print("Out of Stock.")
} catch VendingMachineError.InsufficientFunds(let amountRequired) {
print("Insufficient funds. Please insert an additions $\(amountRequired).")
}
위 예제에서, vend(itemNamed:) 함수는 에러를 던질 가능성이 있기 때문에 try 표현식 안에 표현되었습니다.
에러가 던져지면, 실행흐름은 즉시, 전파를 계속할지 결정되는 catch 절로 이동합니다. 만일 에러가 던져지지 않았다면,
vend(itemNamed:)의 반환값은 snack에 할당되고 do문의 남아있는 구문들이 실행됩니다.
4. 에러 전파 비활성화 (Disabling Error Propagation)
사실상 런타임에 에러를 던지지 않는 throwing 함수나 메서드를 알수 있는 경우가 있습니다. 이러한 경우에는
보통 사용하는 try 표현 대신에 try!(forced-try) 표현을 사용하여 throwing 함수나 메서드를 호출할 수 있습니다.
try!를 사용하여 throwing 함수나 메서드를 호출하면 error 전파가 비활성화 되고, 에러를 던지지 않는 런타임
assertion 안에서의 호출로 랩핑합니다. 만일 실제로 에러가 thrown 되면, 런타임 에러를 만나게 될것입니다.
5. 클린업 액션 지정하기 (Specifying Clearn-Up Actions)
defer 구문을 사용해서, 코드 실행흐름이 현재 코드블럭을 떠나기 직전에, 일련의 코드 집합을 실행할 수 있습니다.
에러의 발생유무와는 상관없이 반드시 실행되야할 클린업 작업을 처리할수 있습니다. 예를 들면 열려진 파일 식별자를
닫거나, 수동으로 할당된 메모리를 해제하는 작업이 될 수 있습니다.
defer 문은 현재 scope이 끝날 때까지 실행을 연기합니다. defer 키워드와 나중에 실행할 코드 구문들로 구성됩니다.
연기된 구문들은 제어흐름을 벗어나게 하는 break 또는 return, 에러를 던지는 것과 같은 코드를 포함해서는 안됩니다.
연기된 액션들은 기술된 순서의 역순으로 실행됩니다. 즉 처음 defer 문에 있는 코드는 두 번째 defer 문의 코드 다음에
실행됩니다.
func processFile(filename:String) throws {
if exists(filename) {
let file = open(filename)
defer {
close(file)
}
while let = try file.readline() {
// work with the file
}
// close(file) is called here, at the end of the scope.
}
}
위 예제에서는 open() 함수가 대응하는 close() 함수 호출을 보장하도록 defer문을 사용했습니다. 이 호출은
에러가 던져졌는지 유무와 상관없이 실행됩니다.
'Swift' 카테고리의 다른 글
| [swift] 성능향상 시키기 - 다이나믹 디스패치를 최소화 (0) | 2015.07.16 |
|---|---|
| [swift2] Xcode7 beta3 Swift 언어 변경사항 (0) | 2015.07.11 |
| [swift2] Swift에서 에러 처리 (Error Handling) (0) | 2015.07.10 |
| [swift2] 타입의 텍스트적인 표현 커스터마이징하기 (0) | 2015.07.01 |
| [swift2] Xcode7 beta2 Swift 언어 변경사항 (0) | 2015.06.24 |
| [swift] 문자열 Indexing과 Slicing (0) | 2015.06.23 |
설정
트랙백
댓글
글
[swift2] 타입의 텍스트적인 표현 커스터마이징하기
1. 값의 문자열 표현 얻기
모델 객체를 화면이나 디버깅 코드에 표시할 때, 텍스트적인 표현을 생성하면 유용할 때가 있습니다.
swift에서는 특정 타입을 string 형태로 표현하거나, 디버깅 목적으로 화면에 출력하기위해 CustomStringConvertible과
CustomDebugStringConvert 프로토콜을 따르도록 선언할수 있습니다. 이 프로토콜 중 하나를 따르는 타입을 정의하면 print,
debugPrint와 같은 출력함수와 string interpolation 이 기본객체의 description을 호출하지 않고 이 함수들을 호출할 것입니다.
다음과 같은 그룹채팅을 위한 Message 타입이 있습니다.
struct Message {
let from: String
let contents: String
let date: NSDate
}
messages = [
Message(from: "Sandy", contents: "Hey, what's going on tonight?", date: messageDates[0]),
Message(from: "Michelle", contents: "Studying for Friday's exam. You guys aren't?", date: messageDates[1]),
Message(from: "Christian", contents: "Nope. That's what tomorrow is for. Let's get food, I'm hungry!", date: messageDates[2]),
Message(from: "Michelle", contents: "Maybe. What do you want to eat?", date: messageDates[3])
] 메세지 객체중 하나를 출력하면, struct의 기본 description을 얻을 수 있습니다.
구조체의 모든 정보를 출력하는데, 채팅앱과 같이 특정한 경우의 로깅과 디버깅을 위해 보기좋게 포맷팅 되어 있지는 않습니다.
디버깅을 위해 특정타입이 출력되는방식을 커스터마이징 하기위해 CustomDebugStringConvertiable 프로토콜을 적용할 수 있습니다.
2. 디버깅 정보 출력 - CustomDebugStringConvertible 프로토콜
CustomDebugStringConvertiable 프로토콜은 한개의 필수 속성인 debugDescription를 가집니다.
이 속성에서 반환된 string은 객체의 description을 제공하기 위해 debugPrint 와 같은 함수에 의해 사용됩니다.
CustomDebugStringConvertible 프로토콜을 적용한 뒤 메시지 출력을 시도해보겠습니다.
extension Message: CustomDebugStringConvertible {
public var debugDescription: String {
return "[\(date) From: \(from)] \(contents)"
}
}
debugPrint(messages[0])
이 description은 디버깅에 적합하며, 사용자의 채팅 메시지를 보여주고자 할때, 로컬시간이 적용된 좀더 사용자 친화적인 시간을
보여주고 싶을 수 있습니다. 좀더 사용자 친화적인 버전의 description을 생성하는 CustomStringnConvertible 프로토콜을 구현할 수 있습니다.
3. 사용자 친화적인 형식으로 출력 - CustomStringConvertible 프로토콜
CustomStringCovertible description을 제공하면, string interpolation과 print 함수는 더이상 debugDescription 속성을 사용하지 않습니다.
import Foundation
let dateFormatter = NSDateFormatter()
dateFormatter.doesRelativeDateFormatting = true
dateFormatter.dateStyle = .ShortStyle
dateFormatter.timeStyle = .ShortStyle
extension Message: CustomStringConvertible {
public var description: String {
return "\(contents)\n \(from) \(dateFormatter.stringFromDate(date))"
}
}
print(messages[0])4. 요약
- 디버깅 정보를 출력하기 위해서 CustomDebugStringConvertible 프로토콜을 구현합니다.
- 사용자 친화적인 정보를 출력하기 위해서 CustomStringConvertible 프로토콜을 구현합니다.
'Swift' 카테고리의 다른 글
| [swift2] Xcode7 beta3 Swift 언어 변경사항 (0) | 2015.07.11 |
|---|---|
| [swift2] Swift에서 에러 처리 (Error Handling) (0) | 2015.07.10 |
| [swift2] 타입의 텍스트적인 표현 커스터마이징하기 (0) | 2015.07.01 |
| [swift2] Xcode7 beta2 Swift 언어 변경사항 (0) | 2015.06.24 |
| [swift] 문자열 Indexing과 Slicing (0) | 2015.06.23 |
| [swift] Map, Filter, Reduce (0) | 2015.06.22 |
