값이 저장되는 일반적인 속성(변수)
여태까지 배운 대부분의 속성
각 인스턴스가 가지는 고유의 데이터 저장 공간
struct Bird {
var name: String // 저장 속성
var weight: Double
// let weight: Double // 값 변경 불가능
init(name: String, weight: Double) {
self.name = name
self.weigth = weight
}
}
var aBird = Bird(name: "참새1", weight: 0.2)
aBird.name
aBird.weight = 0.3
struct Bird1 {
var name: String
lazy var weight: Double = 0.2 // 지연 저장 속성 -> 메모리 공간이 생기지 않는다
init(name: String) {
self.name = name
// self.weight = ~~ // 불가능
}
}
var aBird1 = Bird(name: "새1") // weight에 대한 메모리 공간은 생기지 않는다
aBird1.weight // 접근하는 순간 이제서야 메모리 공간을 만든다 (0.2 저장)
class AView {
var a: Int
// 1. 메모리 공간을 많이 차지할 때
lazy var view = UIImageView()
// 2. 다른 속성을 이용해야 할 때
lazy var b: Int = {
return a * 10
}()
init(num: Int) {
self.a = num
}
}
var view1 = Aview(num: 10) // a에 대한 메모리만 저장
메모리 공간을 많이 차지하는 속성을 저장할 때 (이미지, ...)
메모리 낭비를 막기 위함
다른 저장 속성에 의존해야만 할 때
지연 저장 속성은 먼저 초기화된 속성에 접근할 수 있다.
class Person {
var birth: Int = 0 // 저장 속성
var age: Int { // 계산 속성
get { // get : 반드시 구현해야 함
return 2023 - birth
}
set(age) { // set : 선택적으로 구현해도 되고 안해도 된다. (생략 가능)
self.birth = 2023 - age
}
/* set에서 parameter 생략이 가능하다. (newValue 사용)
set {
self.birth = 2023 - newValue
}
*/
}
/* set 생략하고 get만 구현할 때는 get 글씨 생략 가능 (get only property) (read-only)
var age: Int {
return 2023 - birth
}
*/
/*
// 두 개의 메서드 (birth라는 저장 속성을 통해 계산)
func getAge() -> Int { // 리턴값이 있다
return 2023 - birth
}
func setAge(_ age: Int) { // 리턴값이 없다
self.birth = 2023 - age
}
*/
}
var p1 = Person()
p1.birth = 2000
// p1.getAge()
// p1.setAge(20)
// age(계산속성)에 접근하면, get인지 set인지 판단
p1.age // 21 // get
p1.age = 20 // 나이를 새로 세팅 // set
p1.birth // 2003
class Person {
var name: String = "사람"
var height: Double = 160.0
var weight: Double = 60.0
func calculateBMI() -> Double {
let bmi = weight / (height * height) * 10000
return bmi
}
}
let p = Person()
p.height = 165
p.weight = 65
p.calculateBMI() // 23.875
// 위 예시를 computed properties로 바꾸어서 구현
class Person1 {
var name: String = "사람"
var height: Double = 160.0
var weight: Double = 60.0
var bmi: Double {
get {
let result = weight / (height * height) * 10000
return result
}
set {
// 키는 안변한다고 가정하고 몸무게 변화
weight = bmi * height * height / 10000
}
}
}
let p1 = Person1()
p1.height = 165
p1.weight = 65
p1.bmi // get
p1.bmi = 24 // set
class Dog {
static var species: String = "Dog"
var name: String
var weight: Double
init(name: String, weight: Double) {
self.name = name
self.weight = weight
}
}
let dog = Dog(name: "초코", weight: 15.0)
dog.name // 초코
dog.weight // 15.0
* dog. // 인스턴스로 접근할 수 없다
Dob.species // 타입 자체로 접근해야 한다.
class Circle {
// 저장 타입 속성
static let pi: Double = 3.14 // 고정
static var count: Int = 0 // 인스턴스를 몇 개 찍어내는지 확인
// 저장 속성
var radius: Double
// 계산 속성
var diameter: Double {
get {
return radius * 2
}
set {
radius = newValue / 2
}
}
// 생성자
init(radius: Double) {
self.radius = radius
Circle.count += 1 // 생성자가 일할 때마다 +1
}
}
var circle1 = Circle(radius: 2) // 인스턴스 +1
circle1.radius
circle1.diameter = 6
circle1.diameter * Circle.pi // 원의 둘레
var circle2 = Circle(radius: 3) // 인스턴스 + 1
Circle.count // 2
// 실제 사용
Int.max // 9223... (2^63)
Int.min // -9223... (-2^63)
Double.pi // 3.141592...
class Circle1 {
// 저장 타입 속성
static let pi: Double = 3.14
static var count: Int = 0
// 계산 타입 속성
static var multiPi: Double { // read only 인 경우
return pi * 2 // 원칙적으로는 Circle1.pi라고 써야 하지만, 타입끼리는 서로 생략이 가능하다.
}
// 저장 속성
var radius: Double
// 생성자
init(radius: Double) {
self.radius = radius
}
}
let b = Circle1.multiPi
class Profile {
var name: String = "이름"
// 저장속성 + 저장 속성이 변하는 시점을 '관찰'하는 메서드
var statusMessage: String = "기본 상태메세지" { // 뒤에 값까지 써준다. -> 기본 저장 공간을 갖는다.
willSet(message) { // 추가적인 걸 더 써주었다
print("메세지가 \(statusMessage)에서 \(message)로 변경될 예정입니다.")
//print("상태메세지 업데이트 준비")
}
}
}
let p = Profile()
p.statusMessage // "기본 상태메세지"
p.statusMessage = "행복해" // 출력 : 메세지가 기본 상태메세지에서 행복해로 변경될 예정입니다.
p.statusMessage = "우울해" // 출력 : 메세지가 기본 상태메세지에서 행복해로 변경될 예정입니다.
class Profile1 {
var name: String = "이름"
var statusMessage: String = "기본 상태메세지" {
willSet(message) { // 값이 저장되기 직전에 호출
print("메세지가 \(statusMessage)에서 \(message)로 변경될 예정입니다.")
//print("상태메세지 업데이트 준비")
}
diddSet(message) { // 값이 저장되고 난 직후에 호출 (파라미터는 바뀌기 전의 값)
print("메세지가 \(message)에서 \(statusMessage)로 이미 변경되었습니다.")
// print("상태메세지 업데이트 완료")
}
/* 파라미터 생략하고 newValue, oldValue로 사용 가능
willSet {
print("메세지가 \(statusMessage)에서 \(newValue)로 변경될 예정입니다.")
}
didSet {
print("메세지가 \(oldValue)에서 \(statusMessage)로 이미 변경되었습니다.")
}
*/
}
}
class Dog {
var name: String
var weight: Double
init(name: String, weight: Double) {
self.name = name
self.weight = weight
}
func sit() {
print("\(name)가 앉다")
}
func layDown() {
print("\(name)가 눕다")
}
func play() {
print("논다")
}
func changeName(newName name: String) { // mutating 키워드가 필요 없다
self.name = name
}
func trainning { // 메서드 안에서 다른 메서드 사용 가능
sit()
sit()
self.sit() // self 쓸 수도 있고 안써도 된다
}
}
let bori = Dog(name: "보리", weight: 20.0)
bori.sit()
bori.layDwon()
bori.changeName(newName: "말썽쟁이보리")
bori.name
struct Dog2 {
var name: String
var weight: Double
init(name: String, weight: Double) {
self.name = name
self.weight = weight
}
func sit() {
print("\(name)가 앉았습니다.")
}
mutating func changeName(newName name: String) { // 이름을 바꾸는 메서드
self.name = name
}
}
func sit() {
print("\(name)가 앉았습니다.")
}
func sit(a: String) {
print("\(a)")
}
// 둘 다 사용 가능
bori.sit()
bori.sit(a: "hi")
class Dog {
static var species = "Dog"
var name: String
var weight: Double
init(name: String, weight: Double) {
self.name = name
self.weight = weight
}
static func letmeKnow() { // 종을 알려주는 메서드
print("종은 항상 \(species)입니다.") // Dog.species라고 써도 되지만, 생략 가능
}
}
Dog.letmeKnow // 타입 이름으로 호출 가능
// 사용 예시
Int.random(in: 1...100)
Double.random(in: 1.2...3.7)
class SomeClass {
class func someTypeMethod() {
print("타입과 관련된 공통된 기능의 구현")
}
}
SomeClass.somTypeMethod()
// 상속
class SomeThingClass: SomeClass {
override class func someTypeMethod() {
print("타입과 관련된 공통된 기능의 구현 (업그레이드)")
}
}
SomeThingClass.someTypeMethod()
array[0]
dictionary["A"]
class SomeDate {
var data = ["apple", "swift", "ios", "hello"]
subscript(index: Int) -> String { // func 키워드도 생략. 아예 이름을 subscript
get {
return datas[index]
}
set (parameterName) {
datas[index] = parameterName // 여기서는 paramter 생략하고 newValue 사용 가능. 계산 속성의 set과 동일
}
}
}
var data = SomeDate()
data[0]
data[0] = "AAA"
struct TimesTable {
let multiplier: Int = 3
subscript(index: Int) -> Int {
return multiplier * index // get만 구현
}
}
let threeTimesTable = TimesTable()
threeTimesTable[6] // 18
threeTimesTable[24] // 72
struct Matrix {
var data = [ ["1", "2", "3"], ["4", "5", "6"], ["7", "8", "9"] ]
subscript(row: Int, column: Int) -> String? {
if row >= 3 || column >= 3 {
return nil
}
return data[row][column]
}
}
var mat = Matrix()
mat[0, 1]! // 파라미터 두 개 필요
enum Planet: Int { // 열거형의 원시값
case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune
static subscript(n: Int) -> Planet {
return Planet(rawValue: n)! // Planet을 생성
}
}
let mars = Planet[4]
print(mars) // "mars"
class SomeClass {
private var name = "이름" // 외부에서 name에 접근 불가
func nameChange(name: String) {
self.name = name
}
}
// 기존
var s = SomeClass()
s.name = "홍길동"
s.nameChange(name: "홍홍홍")
// private 후
s. // name이 안 뜬다
s.nameChange(name: "하하하") // nameChange 함수로만 이름 변경 가능
메모리상에 유일하게 1개만 존재하는 객체를 설계한다
앱 구현 시, 유일하게 1개만 존재하는 객체가 필요한 경우
한번 생성된 이후에는 앱이 종료될 때까지 유일한 객체로 메모리에 상주
메모리 구조 강의자료 보기
변수로 접근하는 순간 lazy하게 동작해서 메모리에 올라감
class Singleton {
static let shared = Singleton() // 자신의 객체 생성해서 변수에 할당
var userInfoId = 12345
private init() {} // 생성자 앞에 private -> 접근 불가
}
Singleton.shared // 접근하는 순간 메모리에 올라감
let object = Singleton.shared
object.userInfoId =1234567
Single.shared.userInfoId // 1234567. 이렇게 접근해도 값은 동일 (유일한 객체)
let object2 = Singleton.shared // 유일한 객체 가리키는 것
object2.userInfoId // 1234567 (유일한 객체)
// 원래. -> init이 private이 되었기 때문에 새로운 객체 생성이 불가능하다.
* let object3 = Singleton() // 그냥 새로운 객체 생성
* object3.userInfoId // 12345
let screen = UIScreen.main // 화면 관라히는 유일한 객체
let userDefaults = UserDefaults.standard // 유저 관리
let application = UIApplication.shared // 앱 관리
let fileManager = FileManager.default // 파일 관리
let notification = NotificationCenter.default // 노티피케이션(특정 상황, 시점을 알려줌)