Open Seokki-Kwon opened 9 months ago
1.final 선언 상속이 필요없는 경우 final로 선언하면 Static Dispatch로 호출되기 때문에 성능이 향상됨.
2.lazy 프로퍼티 사용하기 lazy 프로퍼티를 사용한다면 인스턴스를 직접 호출하는 시점에 초기화 되며 클래스의 성능을 향상시킬 수 있다.
3. 계산 프로퍼티 사용 최소화 계산 프로퍼티를 사용하면 해당 속성에 접근할때마다 계산을 수행하기 때문에 계산 비용이 많이드는 속성에 자주 엑세스 하게된다면 성능저하의 요인이 될 수 있다.
4. map, filter같은 고차함수 사용 map, filter같은 고차함수는 고도화된 내부 알고리즘으로 인하여 추가적인 데이터 구조를 만들지 않고도 컬렉션에 대한 작업을 수행할 수 있다.
5. private 선언 파일 내에서만 접근하는 경우 private로 선언하면 컴파일러가 오버라이딩 되는곳이 없다고 추론하여 Static Dispatch로 동작되게끔 해준다.
인스턴스 메서드란 일반적으로 클래스에 선언된 메서드(static, class 키워드를 안붙힌) 메서드를 의미하며 타입 메서드란 static 또는 class를 붙힌다. 타입 메서드에 접근하는 경우 클래스타입.메서드명 으로 접근해야 한다 반면 인스턴스 메서드는 해당 인스턴스를 생성하고 접근해서 사용해야 한다.
코드적으로 설명을 해보자면 class func로 메서드를 선언하면 상속받은 서브클래스에서 재정의(override)가 가능하다. 반면 static func 로 메서드를 선언하면 서브클래스에서 재정의가 불가능하다.
class func -> 재정의 가능, Dynamic Dispatch static func -> 재정의 불가능, Static Dispatch final class func -> 재정의 불가능, Static Dispatch static func, final class func 는 결과가 똑같음(취향 차이)
메모리의 주소값을 저장하는 변수
Retain Cycle의 우려가 있습니다 Retain Cycle 이란 메모리 누수가 발생하는 현상을 말합니다.
class TestClass {
private let text = "some text"
// 클로저 내부에서 self 키워드를 붙혀야함
// TestClas의 RC가 늘어남
// 해당 클로저또한 self에 관해 RC를 유지되어 사라지지 않음
private lazy var myLabel: () -> UILabel = {
let label = UILabel()
label.text = self.text
return label
}
}
해당 클로저 내부에서 self를 참조하여 해당 클로저는 해제되지 않음 TestClass 또한 해당 클로저를 참조하여 RC가 늘어남 이러한 원인으로 메모리가 해제되지 않는 현상발생
해결책으로는 non-escaping 클로저를 사용
class TestClass {
private let text = "some text"
// 클로저 내부에서 self 키워드를 붙혀야함
// TestClas의 RC가 늘어남
// 해당 클로저또한 self에 관해 RC를 유지되어 사라지지 않음
private lazy var myLabel: UILabel = {
let label = UILabel()
label.text = text
return label
}()
}
해당 클래스를 사용할떄 ()를 붙혀 즉시 실행되도록하여 non-escaping 클로저로 적용되어 self를 사용하지 않으므로 retain-cycle을 예방할 수 있다.
값을 저장하거나 메서드를 캡슐화할 수 있는 타이비다. 사용하는 방법은 클래스와 유사하게 사용하지만 상속이 불가능하며 값타입이다.
구조체의 저장속성을 변경하는 메서드의 경우 mutating 키워드를 붙혀야한다.
Swift의 구조체는 값타입이다. 값타입의 프로퍼티를 변경할때 원본값을 변경하는게 아닌 인스턴스 자체를 복사하여 변경하기 때문이다. mutating 키워드는 해당 메서드를 종료할때 변경된 프로퍼티가 있는 변경된 구조체로 인스턴스를 대체하도록 해준다.
복사본에 대한 실질적인 사용이 이루어질때 실제로 복사를 수행하는 기술을 말한다. 값을 복사시 값에 실질적인 쓰기작업이 이루어지기 이전에는 얕은 복사(Shallow Copy)를 수행하며 실제 값에 쓰기작업이 이루어지는 시기가 되서야 깊은복사(Deep Copy)를 수행한다.
var array1 = [1, 2, 3, 4]
var array2 = array1
print(address: array1) // 0x60000170ae20
print(address: array2) // 0x60000170ae20
// 값을 변경 -> Deep Copy 수행
array2[3] = 11
print(address: array1) // 0x60000170ae20
print(address: array2) // 0x60000171c1a0(바뀐 메모리 주소)
실제로 값을 복사하는 것은 추가적인 메모리 공간을 차지함을 의미 만약 데이터를 무조건적으로 복사를 한다면 메모리를 무의미하게 많이 차지할 수 있으므로 여러 프로그래밍 언어에서 COW를 사용하고 있다.
final 키워드 붙이기
원래 클래스는 Dynamic Dispatch 방법을 사용하여, 런타임 시점에 호출된다. 상속 / 다형성의 장점을 누릴 수 있다. 하지만 클래스에 final 키워드를 붙이면, 메서드 호출 방식이 변경된다. Direct Dispatch 방식으로 변경되는데, 이 방식은 컴파일 시점에 코드에 메서드의 메모리 주소를 삽입하여, 속도가 빨라진다는 장점이 있다.
lazy 프로퍼티 사용하기
이 속성은 사용되기 전까지는 초기값이 계산되지 않는다. 복잡한 계산이나 부하가 많이 걸리는 작업은 인스턴스 초기화 시점에 계산하지 않아서 성능을 개선할 수 있다.
인스턴스 메서드는 인스턴스가 사용하는 메서드이다.
타입 메서드는 인스턴스를 생성하지 않고, 타입에서 바로 접근 가능한 메서드이다. static 키워드나 class 키워드를 붙여서 선언할 수 있다. static 키워드로 선언된 메서드는 상속이 불가하며, class 키워드로 선언된 메서드는 상속이 가능하다
인스턴스 메서드는 저장프로퍼티나, 타입 프로퍼티에 접근이 가능한 반면.
타입메서는 저장프로퍼티에 접근이 불가하고, 타입프로퍼티는 같은 타입이라면 타입이름 없이 접근이 가능하다
static 키워드로 선언된 메서드는 상속이 불가하며, class 키워드로 선언된 메서드는 상속이 가능하다
포인터는 메모리 주소를 가리키는 정수타입의 값이다. class 의 메서드(함수)의 포인터를 배열형태로 보관하고 있다가 필요할 때 호출한다.
lazy 속성은 사용되기 전까지는 초기값이 계산되지 않는다. 복잡한 계산이나 부하가 많이 걸리는 작업은 인스턴스 초기화 시점에 계산하지 않아서 성능을 개선할 수 있다.
다중 쓰레드에서 속성에 접근할시에 취약하다는 주의점이 있다.
스위프트의 타입의 하나로, 인스턴스의 값을 저장하거나, 기능을 제공하게 해준다. 상속을 불가하며, 인스턴스를 생성하면 스택에 저장되고 사용이후 사라진다
Struct 의 메서드는 기본적으로 프로퍼티의 값을 수정할 수 없다. 메서드 앞에 mutating 키워드를 붙여주면, 프로퍼티를 수정할 수 있게 된다
값타입의 경우에는 값을 복사하면, 할 때마다 새로운 메모리 저장 공간을 만들고 복사한 값을 저장한다. 이는 메모리의 비효율을 발생시키므로 COW 방식을 사용한다. 이 방식은 값을 복사하면 참조타입 처럼 메모리 주소만 공유한다. 이렇게 메모리 공간을 절약하고, 이후 복사한 값의 변경이 일어나면, 그 때 새로운 메모리 공간에 변경된 값을 저장하는 방식이다.
이번주는 예상보다 분량이 많아서 class 와 struct의 비교는 며칠안에 추가 업로드 하겠습니다!
2024.02.20
class
struct
Class / Struct차이