overview
scope
와 linfetime
을 제공한다.<Variable의 종류>
//Variable_scope_lifetime.file
fileprivate let secret = "sercret"
let secondSecret = "SecondSecret"
//main.file
print(secret) // error
class Example {
static let name = "iOS"
}
Example.name // ok
name // error
타입명시 하거나 초기화를 통해 타입을 추론할 수 있다.
class Example2 {
let name = "example"
}
// Type Implement
let example: Example2
//declaration
let example2 = Example2()
//declaration + initialization
numeric Type의 Double, CGFloat 같이 같은 value이지만 여러개의 타입으로 사용가능한 경우
let number = 2.0
let number = 2.0
if number is Double {
print("yes")
}
// yes 가 프린트됨
컴파일러의 타입추론을 통해 선언 및 초기화 할 때
예시 : 아래 autoreverse, repeat는 UIView.AnimationOpions의 값들인데 컴파일러 입장에선 모르기 때문에 명시해야한다.
var ops = [.acutoreverse, .repeat]
//compiler error
var ops: UIView.AnimationOptions = [.acutoreverse, .repeat]
프로그래머가 타입을 추론하기 힘들 때
예시 : 아래의 track은 AVAssetTrack이고 컴파일러는 아래의 코드를 타입명시하지 않아도 잘 알고있지만 프로그래머입장에서 (나중에 봐도?) 알고싶을때
let duration: CMTime = track.timeRange.duration
instance property를 선언할 땐 타입만선언하지말고 초기화 까지 해줘라. 단 conditional initialization
은 제외.
struct Test {
let a: Int
//초기화 조건이 필요한 경우
init(_ num: Int) {
if num > 0 {
a = num
} else {
a = 0
}
}
만약 variable이 함수의 인자
로 사용되는 경우 반드시 초기화 되어야한다(타입만 명시하면 안된다). 가짜 값이더라도 할당해주어야함.
초기화 되기도 전에 self를 사용하려고 하는경우 (당연한 얘기)
//Cocoa가 가진 UIApplication instance method
func beginBackgroundTask(
expirationHandler handler: (() -> Void)? = nil)
-> UIBackgroundTaskIdentifier
let bti = UIApplication.shared.beginBackgroundTask {
UIApplication.shared.endBackgroundTask(bti)
}
//compiler error
var bti: UIBackgroundTaskIdentifier = .invalid
bti = UIApplication.shared.beginBackgroundTask {
UIApplication.shared.endBackgroundTask(bti)
}
// fake initial value를 할당해준 후 호출
자주쓰는 객체의 타입이 너무 길어서 하나로 묶어둘 때
//예시
var myTableView : MyMusicPlayerTableView {
SomeViewController.playerTableView
}
var playerItem : PlayerItem? {
self.myTableView.item
}
정교한 계산을 수행할 나타낼 때
Q. 함수(메소드)로도 구현할 수 있지 않은가?
A. 함수는 과정을 나타내고, computed Property는 과정이 아닌 결과(thing)로서 직관적인 측면이 있기 때문
class tableView: UITableView {
var imgageSize: CGRect {
/* massive calculation
.
.
.
.
*/
return CGRext value
}
}
Facade for storage
// 이전에 내가 사용했던 방법
class Example {
private var _example: Int = 10
var showedExample : Int {
get {
return self._example
} set {
self._example = newValue
}
}
// refactoring
class Example2 {
private(set) var _example: Int = 10
func changeExmapleValue(to x: Int) {
self._example = x
}
}
// storage로서 computedProperty
class Example3 {
private var _example: Int = 10
var showedExample : Int {
get {
return self._example
} set {
//새로 할당되는 값을 0과 5사이로 제한
self._example = max(min(newValue,5), 0)
}
}
//newValue가 0과 5사이인 값을 가지는 propertyWrapper를 만듬
//PropertyWrapper_Chpater3.swift 파일내부
@propertyWrapper struct Example {
private var _number = 0
var wrappedValue: Int {
get {
return self._number
} set {
self._number = max(min(newValue, 5), 0)
}
}
}
//선언만하면됨. - 초기화, getter와 setter없어도 됨
//이미 propertyWrapper에 작성해 두었기 때문
//장사잘되는 음식점에서 미리 수저, 소스, 휴지 가방에 넣어논것과 같은 개념
//main.swift 파일내부
struct Example2 {
@Example var propertyWrapperExample
}
lazy
같다는 생각이 든다)연산프로퍼티 패턴
을 encapsulate
하는 것var number = 10 {
willSet {
print("\(newValue)")
}
didSet {
print("\(oldValue)")
}
}
lazy
하다<lazily하게 초기화되는 것들>
Global variables
“Under the hood, this behavior is implemented in such a way as to make initialization both singular (it can happen only once) and thread-safe.”
이런식의 구현은 단인할 초기화와( 단 한번 초기화가 일어나도록 하는 것) 스레드 안정성을 만드는 방법이다.
Static Properties
Instance Properties
Singleton
단일한 class타입의 인스턴스에 접근하도록 할 때 구현하는 패턴
static
은 Data
영역에 할당
단점 : immutable
하게 선언할 수 없다.
사용하는 이유
내부에서 초기화 되기 이전에 인스턴스를 refer
할 수 있다.
class MyClass {
//lazy 하게 초기화
static let shared = MyClass()
private init() { }
}
let myClass = MyClass.shared
let myClass2 = Myclass.shared