클래스가 아닌 구조를 선택하는 이유
Java 배경의 Swift를 가지고 놀다 보면 클래스가 아닌 Structure를 선택하려는 이유가 무엇입니까?동일한 것으로 보이며, 기능이 떨어지는 구조입니다.그럼 왜 그걸 선택하죠?
매우 인기 있는 WWDC 2015 Talk Protocol Oriented Programming in Swift(비디오, 스크립트)에 따르면, Swift는 많은 상황에서 클래스보다 더 나은 구조를 만드는 많은 기능을 제공합니다.
클래스에서 발생하는 동일한 인스턴스에 대한 여러 참조를 갖는 것보다 복사가 훨씬 안전하기 때문에 구조가 비교적 작고 복사 가능한 경우 선호됩니다.이는 변수를 여러 클래스에 전달하거나 멀티스레드 환경에서 전달할 때 특히 중요합니다.변수의 복사본을 항상 다른 곳으로 보낼 수 있는 경우, 아래에 있는 변수의 값이 변경되는 다른 위치에 대해 걱정할 필요가 없습니다.
Structures를 사용하면 메모리 누수나 변수의 단일 인스턴스에 액세스/수정하기 위해 여러 스레드가 경합하는 것에 대해 걱정할 필요가 훨씬 적습니다.(기술에 관심이 있는 경우,단, 클로저 내부의 구조를 캡처하는 경우는 예외입니다.이는 명시적으로 복사하도록 표시하지 않는 한 인스턴스에 대한 참조를 실제로 캡처하기 때문입니다).
클래스는 하나의 슈퍼 클래스에서만 상속할 수 있기 때문에 클래스가 비대해질 수도 있습니다.그것은 우리가 느슨하게만 관련되어 있는 많은 다른 능력들을 포함하는 거대한 슈퍼클래스를 만들도록 장려한다.프로토콜, 특히 프로토콜에 구현을 제공할 수 있는 프로토콜 확장과 함께 프로토콜을 사용하면 클래스가 이러한 동작을 수행할 필요가 없습니다.
이 토크에서는 클래스가 바람직한 시나리오에 대해 설명합니다.
- 인스턴스를 복사하거나 비교하는 것은 의미가 없다(예: Window)
- 인스턴스의 라이프 타임은 외부 효과(Temporary File 등)와 관련지어져 있습니다.
- 인스턴스는 외부 상태에 대한 쓰기 전용 도관인 "싱크"에 불과합니다(예:CG Context)
즉, 구조가 기본이고 클래스가 폴백이어야 합니다.
한편, Swift Programming Language 문서는 다소 모순적입니다.
구조 인스턴스는 항상 값으로 전달되고 클래스 인스턴스는 항상 참조로 전달됩니다.이것은 그들이 다른 종류의 작업에 적합하다는 것을 의미합니다.프로젝트에 필요한 데이터 구조 및 기능을 고려할 때 각 데이터 구조를 클래스로 정의할지 아니면 구조로 정의할지 결정합니다.
일반적인 가이드라인으로 다음 조건 중 하나 이상이 적용되는 경우 구조를 작성하는 것을 고려하십시오.
- 이 구조의 주요 목적은 비교적 단순한 데이터 값을 캡슐화하는 것입니다.
- 캡슐화된 값은 해당 구조의 인스턴스를 할당하거나 전달할 때 참조되지 않고 복사될 것으로 예상하는 것이 합리적입니다.
- 구조체에 의해 저장된 속성은 그 자체로 값 유형이며, 이 값도 참조가 아닌 복사될 것으로 예상됩니다.
- 구조체는 다른 기존 유형에서 속성 또는 동작을 상속할 필요가 없습니다.
구조물에 적합한 후보로는 다음이 있습니다.
- Double 유형의 너비 특성과 높이 특성을 캡슐화한 기하학적 모양의 크기입니다.
- Int 타입의 시작 속성과 길이 속성을 캡슐화한 시리즈 내의 범위를 참조하는 방법.
- 3D 좌표계의 점으로, 각각 이중 유형의 x, y 및 z 속성을 캡슐화합니다.
다른 모든 경우 클래스를 정의하고 해당 클래스의 인스턴스를 생성하여 관리 및 참조로 전달합니다.실제로 이는 대부분의 사용자 지정 데이터 구조가 구조가 아닌 클래스여야 함을 의미합니다.
여기서는 특정 상황에서만 클래스를 사용하고 구조를 사용해야 한다고 주장하고 있습니다.궁극적으로 가치 유형 대 참조 유형의 실제 영향을 이해한 다음 구조 또는 클래스를 사용할 시기를 정보에 따라 결정할 수 있습니다.또한 이러한 개념은 항상 진화하고 있으며 Swift Programming Language 문서는 Protocol Oriented Programming Talk가 발표되기 전에 작성되었습니다.
이 답변은 원래 구조와 클래스의 성능 차이에 관한 것이었다.안타깝게도 제가 사용한 측정 방법에 대해 많은 논란이 있습니다.아래에 두었는데 너무 많이 읽지는 마세요.오랜 세월이 흐르면서 스위프트 커뮤니티에서는 구조(엔럼과 함께)가 항상 그 단순성과 안전성 때문에 선호된다는 것이 분명해졌다고 생각합니다.
성능이 앱에 중요한 경우 직접 측정하십시오.나는 여전히 대부분의 시간 구조 성능이 우수하다고 생각하지만, 가장 좋은 대답은 누군가가 댓글에서 말한 대로이다: 그것은 상황에 따라 다르다.
=== 오래된 대답 ===
구조체 인스턴스는 스택에 할당되고 클래스 인스턴스는 힙에 할당되므로 구조체의 속도가 대폭 빨라질 수 있습니다.
그러나 항상 직접 측정하여 고유한 사용 사례에 따라 결정해야 합니다.
예시를 해 보세요. 이 의 두 을 보여 줍니다. 이 예에서는 포장 방법의 두 가지 전략을 보여 줍니다.Int 을 사용한struct ★★★★★★★★★★★★★★★★★」class여러 필드가 있는 실제 세계를 더 잘 반영하기 위해 10개의 반복 값을 사용하고 있습니다.
class Int10Class {
let value1, value2, value3, value4, value5, value6, value7, value8, value9, value10: Int
init(_ val: Int) {
self.value1 = val
self.value2 = val
self.value3 = val
self.value4 = val
self.value5 = val
self.value6 = val
self.value7 = val
self.value8 = val
self.value9 = val
self.value10 = val
}
}
struct Int10Struct {
let value1, value2, value3, value4, value5, value6, value7, value8, value9, value10: Int
init(_ val: Int) {
self.value1 = val
self.value2 = val
self.value3 = val
self.value4 = val
self.value5 = val
self.value6 = val
self.value7 = val
self.value8 = val
self.value9 = val
self.value10 = val
}
}
func + (x: Int10Class, y: Int10Class) -> Int10Class {
return IntClass(x.value + y.value)
}
func + (x: Int10Struct, y: Int10Struct) -> Int10Struct {
return IntStruct(x.value + y.value)
}
퍼포먼스는 다음 방법으로 측정됩니다.
// Measure Int10Class
measure("class (10 fields)") {
var x = Int10Class(0)
for _ in 1...10000000 {
x = x + Int10Class(1)
}
}
// Measure Int10Struct
measure("struct (10 fields)") {
var y = Int10Struct(0)
for _ in 1...10000000 {
y = y + Int10Struct(1)
}
}
func measure(name: String, @noescape block: () -> ()) {
let t0 = CACurrentMediaTime()
block()
let dt = CACurrentMediaTime() - t0
print("\(name) -> \(dt)")
}
코드는 https://github.com/knguyen2708/StructVsClassPerformance 에서 확인할 수 있습니다.
업데이트 (2018년 3월 27일)
4.0, on 은 Swift 4.0, Xcode 9.2, iPhone 6S, iOS 11.2.6입니다.-O -whole-module-optimization:
class2됨 2.06초 걸렸어요.struct4. 고속가 소요되었습니다(50,000배 고속)
분산이 5% 미만으로 매우 작기 때문에 더 이상 다중 런의 평균을 산출하지 않습니다.
주의: 모듈 전체를 최적화하지 않으면 차이가 크게 나지 않습니다.깃발이 실제로 어떤 역할을 하는지 누군가 지적해 주셨으면 좋겠습니다.
업데이트 (2016년 5월 7일):
.2 on 3은 은 Swift 2.2.1' Xcode 7.3, iPhone 6S' 릴리즈 빌드 5.3입니다.-O -whole-module-optimization:
class22 22.159942142s 요 2struct5.83E-08s(3700,000)입니다.
주의: 실제 시나리오에서는 구조물에 여러 필드가 있을 가능성이 높다고 언급하고 있기 때문에 1이 아닌 10개의 필드가 있는 구조/클래스에 대한 테스트를 추가했습니다.놀랍게도, 결과는 크게 다르지 않다.
오리지널 결과 (2014년 6월 1일) :
(10개의 필드가 아닌 1개의 구조/클래스로 실행)
Swift 1.2 현재 Xcode 6.3.2는 iPhone 5S에서 Release Build를 실행하고 있으며 iOS 8.3은 평균 5회 이상 실행되었습니다.
class9되었습니다.struct은 0. 고속로 설정되었습니다.★ 0.010532942s(900배 고속)
오래된 결과(알 수 없는 시간)
(10개의 필드가 아닌 1개의 구조/클래스로 실행)
MacBook Pro를 기반으로 한 릴리스 빌드:
class1struct0.sec (빠름)0.0224 sec (50배 빠름)
구조와 클래스 간의 유사성.
나는 간단한 예시로 이것의 요지를 만들었다.https://github.com/objc-swift/swift-classes-vs-structures
그리고 차이점
1. 상속
구조는 빠르게 상속될 수 없습니다.네가 원한다면
class Vehicle{
}
class Car : Vehicle{
}
수업을 들으러 가다.
2. 지나가다
스위프트 구조는 값으로 전달되고 클래스 인스턴스는 참조로 전달됩니다.
콘텍스트의 차이
구조 상수 및 변수
예(WWDC 2014에서 사용)
struct Point{
var x = 0.0;
var y = 0.0;
}
점이라는 구조물을 정의합니다.
var point = Point(x:0.0,y:2.0)
x를 바꾸려고 하면유효한 표현입니다.
point.x = 5
하지만 점을 상수로 정의하면
let point = Point(x:0.0,y:2.0)
point.x = 5 //This will give compile time error.
이 경우 전체 점이 불변 상수입니다.
클래스 포인트를 대신 사용한 경우 이것은 유효한 표현입니다.클래스에서는 불변의 상수가 클래스 자체에 대한 참조가 되지 않기 때문입니다(이러한 변수가 상수로 정의되지 않은 경우).
Structure가 값 유형이고 Class가 참조 유형임을 알고 있다고 가정합니다.
값 유형과 참조 유형이 무엇인지 모르는 경우 참조별 전달과 값별 전달의 차이점은 무엇입니까?를 참조하십시오.
mikeash의 투고에 근거합니다.
...먼저 극단적이고 명백한 예를 몇 가지 살펴보겠습니다.정수는 분명히 복사할 수 있습니다.값 유형이어야 합니다.네트워크 소켓은 올바르게 복사할 수 없습니다.참조 유형이어야 합니다.x, y 쌍과 같이 점을 복사할 수 있습니다.값 유형이어야 합니다.디스크를 나타내는 컨트롤러는 적절하게 복사할 수 없습니다.참조 유형이어야 합니다.
카피할 수 있는 타입도 있습니다만, 항상 필요한 것은 아닙니다.즉, 참조 유형이어야 합니다.예를 들어, 화면의 버튼을 개념적으로 복사할 수 있습니다.사본은 원본과 완전히 동일하지는 않을 것이다.사본을 클릭해도 원본이 활성화되지 않습니다.카피는, 화면의 같은 장소에 배치되지 않습니다.버튼을 돌리거나 새 변수에 넣으면 원래 버튼을 참조할 수 있으며, 명시적으로 요청되었을 때만 복사할 수 있습니다.즉, 버튼 타입은 참조 타입이어야 합니다.
보기 및 창 컨트롤러도 이와 유사한 예입니다.베낄 수 있을지는 모르지만, 당신이 하고 싶은 일은 거의 없어요.참조 유형이어야 합니다.
모델 타입은 어떻습니까?시스템의 사용자를 나타내는 사용자 유형 또는 사용자가 수행한 작업을 나타내는 범죄 유형이 있을 수 있습니다.이것들은 카피할 수 있기 때문에, 값 타입이 될 가능성이 있습니다.그러나 프로그램의 한 곳에서 발생한 사용자 범죄에 대한 업데이트를 프로그램의 다른 부분에 표시하고자 할 수도 있습니다.이는 사용자를 참조 유형인 일종의 사용자 컨트롤러로 관리해야 함을 나타냅니다.예
struct User {} class UserController { var users: [User] func add(user: User) { ... } func remove(userNamed: String) { ... } func ... }컬렉션은 흥미로운 경우입니다.여기에는 배열이나 사전, 문자열 등이 포함됩니다.복사할 수 있습니까?물론. 뻔하지.베끼는 것이 쉽고 자주 일어나고 싶은 일인가요?덜 명확하네요.
대부분의 언어는 이에 대해 "아니오"라고 말하며 컬렉션을 참조 유형으로 만듭니다.이것은 Objective-C, Java, Python, JavaScript 등 제가 생각할 수 있는 거의 모든 언어에서 해당됩니다.(주요 예외 중 하나는 STL 컬렉션 타입을 가진 C++이지만 C+는 모든 것을 이상하게 하는 언어 세계의 열광적인 미치광이입니다.)
Swift는 "예"라고 대답했습니다. 이는 Array, Dictionary, String과 같은 유형이 클래스가 아닌 구조임을 의미합니다.할당 시 및 매개 변수로 전달 시 복사됩니다.Swift가 매우 노력한 복사본이 저렴한 한, 이것은 전적으로 합리적인 선택입니다.
저는 개인적으로 수업 이름을 그렇게 짓지 않아요.저는 보통 UserController 대신 UserManager라는 이름을 붙이는데 생각은 똑같습니다.
또한 함수의 모든 인스턴스를 덮어쓸 필요가 있는 경우(공유 기능이 없는 경우)에는 클래스를 사용하지 마십시오.
여러 개의 서브클래스가 있는 대신프로토콜에 적합한 여러 구조를 사용합니다.
구조물에 대한 또 다른 합리적인 사례는 이전 모델과 새 모델의 델타/디프를 수행하려는 경우입니다.레퍼런스 타입의 경우는, 곧바로 사용할 수 없습니다.값 유형의 경우 돌연변이는 공유되지 않습니다.
고려해야 할 다른 이유는 다음과 같습니다.
구조체에는 코드 내에서 유지 관리할 필요가 없는 자동 이니셜라이저가 있습니다.
struct MorphProperty { var type : MorphPropertyValueType var key : String var value : AnyObject enum MorphPropertyValueType { case String, Int, Double } } var m = MorphProperty(type: .Int, key: "what", value: "blah")
이것을 클래스로 가져오려면 이니셜라이저를 추가하고 이니셜라이저를 유지해야 합니다.
다음과 같은 기본 수집 유형
Array자기 참고가예요.자신의 코드로 사용할수록 참조가 아닌 값으로 전달하는 데 익숙해집니다.§:func removeLast(var array:[String]) { array.removeLast() println(array) // [one, two] } var someArray = ["one", "two", "three"] removeLast(someArray) println(someArray) // [one, two, three]불변성 대 불변성 대 불변성 대 불변성 대 불변성 대 불변성 대 불변성 대 불변성 대 불변성 대 불변성 대 불변성 대 불변성 대 불변성 대 불변성 대 불변성 대 불변성 대 불변성,가변 객체와 불변 객체
장점:
- 공유할 수 없기 때문에 자동으로 스레드 세이프가 되는
- isa 및 refcount가 없기 때문에 메모리 사용량이 적습니다(실제로 스택은 일반적으로 할당됩니다).
- 메서드는 항상 정적으로 디스패치되기 때문에 인라인을 사용할 수 있습니다(@final은 클래스에 대해 이 작업을 수행할 수 있지만).
- 스레드 안전과 같은 이유로 쉽게 추론할 수 있다(NSArray, NSString 등의 일반적인 '방어적 복사' 불필요).
Structsvalue type ★★★★★★★★★★★★★★★★★」Classesreference type
- 값 유형이 참조 유형보다 빠릅니다.
- 여러 스레드가 경쟁 조건이나 교착 상태를 걱정할 필요 없이 인스턴스를 변환할 수 있으므로 값 유형 인스턴스는 멀티 스레드 환경에서 안전합니다.
- 값 유형은 참조 유형과 달리 참조가 없으므로 메모리 누수가 없습니다.
사용하다value뭇매를 맞다
- 복사본을 독립 상태로 만들려면 데이터가 여러 스레드에 걸쳐 코드로 사용됩니다.
사용하다reference뭇매를 맞다
- 공유, 변경 가능한 상태를 생성하려고 합니다.
상세한 것에 대하여는, Apple 의 메뉴얼을 참조해 주세요.
https://docs.swift.org/swift-book/LanguageGuide/ClassesAndStructures.html
추가 정보
스위프트 값 유형은 스택에 저장됩니다.프로세스에서 각 스레드는 자체 스택 공간을 가지므로 다른 스레드는 값 유형에 직접 액세스할 수 없습니다.따라서 레이스 조건, 잠금, 교착 상태 또는 관련된 스레드 동기 복잡성이 없습니다.
값 유형에는 동적 메모리 할당이나 참조 카운트가 필요하지 않습니다. 둘 다 비용이 많이 드는 작업입니다.동시에 값 유형의 메서드는 정적으로 디스패치됩니다.이는 성능 측면에서 가치 유형을 선호하는 데 큰 이점을 제공합니다.
여기 Swift의 목록이 있습니다.
값 유형:
- 구조
- 열거형
- 튜플
- 원형(Int, Double, Bool 등)
- 컬렉션(어레이, 문자열, 사전, 세트)
참조 유형:
- 학급
- NSObject에서 나오는 모든 것
- 기능.
- 클로즈
구조가 클래스보다 훨씬 빠릅니다.또한 상속이 필요한 경우 클래스를 사용해야 합니다.가장 중요한 점은 클래스가 참조 유형인 반면 구조는 값 유형이라는 것입니다.예를들면,
class Flight {
var id:Int?
var description:String?
var destination:String?
var airlines:String?
init(){
id = 100
description = "first ever flight of Virgin Airlines"
destination = "london"
airlines = "Virgin Airlines"
}
}
struct Flight2 {
var id:Int
var description:String
var destination:String
var airlines:String
}
이제 둘 다 인스턴스를 만듭니다.
var flightA = Flight()
var flightB = Flight2.init(id: 100, description:"first ever flight of Virgin Airlines", destination:"london" , airlines:"Virgin Airlines" )
이제 이러한 인스턴스를 ID, 설명, 대상 등을 수정하는 두 가지 함수에 전달합니다.
func modifyFlight(flight:Flight) -> Void {
flight.id = 200
flight.description = "second flight of Virgin Airlines"
flight.destination = "new york"
flight.airlines = "Virgin Airlines"
}
또한.
func modifyFlight2(flight2: Flight2) -> Void {
var passedFlight = flight2
passedFlight.id = 200
passedFlight.description = "second flight from virgin airlines"
}
그렇게,
modifyFlight(flight: flightA)
modifyFlight2(flight2: flightB)
이제 우리가 항공편을 인쇄한다면A의 ID와 인상착의는
id = 200
description = "second flight of Virgin Airlines"
여기서 변경 방법에 전달된 파라미터가 실제로 flightA 오브젝트(참조 타입)의 메모리 주소를 가리키기 때문에 FlightA의 ID와 설명이 변경되었음을 알 수 있다.
이제 FLightB 인스턴스의 ID와 설명을 출력하면
id = 100
description = "first ever flight of Virgin Airlines"
여기에서는 FlightB 인스턴스가 변경 중이기 때문에 변경되지 않았음을 알 수 있습니다.Flight2 방법, Flight2의 실제 인스턴스는 참조(값 유형)가 아닌 통과입니다.
가치 유형과 참조 유형의 관점에서 질문에 답하면, 이 Apple 블로그 투고에서는 매우 심플하게 나타납니다.
다음과 같은 경우 값 유형 [예: structure, enum]을 사용합니다.
- 인스턴스 데이터를 ==와 비교하는 것이 타당합니다.
- 복사본이 독립 상태를 갖기를 원합니다.
- 데이터는 여러 스레드에 걸쳐 코드로 사용됩니다.
다음과 같은 경우 참조 유형 [예: 클래스]를 사용합니다.
- 인스턴스 ID를 ===와 비교하는 것이 타당합니다.
- 공유, 변경 가능한 상태를 작성한다.
이 기사에서 언급했듯이 쓰기 가능한 속성이 없는 클래스는 구조물과 동일하게 동작합니다. 단, (추가하겠습니다) 구조물은 스레드 세이프 모델에 최적입니다.이것은 현대 애플리케이션 아키텍처에서 점점 더 시급한 요건입니다.
구조와 클래스
Struct더 선호됩니다.그렇지만Struct디폴트로는 모든 문제가 해결되는 것은 아닙니다.으로는 '아예'라는 소리를 수 .value type는 스택에 할당되어 있습니다만, 항상 참인 것은 아닙니다.로컬 변수만 스택에 할당됩니다.
//simple blocks
struct ValueType {}
class ReferenceType {}
struct StructWithRef {
let ref1 = ReferenceType()
}
class ClassWithRef {
let ref1 = ReferenceType()
}
func foo() {
//simple blocks
let valueType1 = ValueType()
let refType1 = ReferenceType()
//RetainCount
//StructWithRef
let structWithRef1 = StructWithRef()
let structWithRef1Copy = structWithRef1
print("original:", CFGetRetainCount(structWithRef1 as CFTypeRef)) //1
print("ref1:", CFGetRetainCount(structWithRef1.ref1)) //2 (originally 3)
//ClassWithRef
let classWithRef1 = ClassWithRef()
let classWithRef1Copy = classWithRef1
print("original:", CFGetRetainCount(classWithRef1)) //2 (originally 3)
print("ref1:", CFGetRetainCount(classWithRef1.ref1)) //1 (originally 2)
}
* 사용/재활용하지 마십시오.retainCount 있지
스택 또는 힙을 검사하려면
SIL(Swift Intermediate Language)을 컴파일하면 코드를 최적화할 수 있습니다.
swiftc -emit-silgen -<optimization> <file_name>.swift
//e.g.
swiftc -emit-silgen -Onone file.swift
//emit-silgen -> emit-sil(is used in any case)
//-emit-silgen Emit raw SIL file(s)
//-emit-sil Emit canonical SIL file(s)
//optimization: O, Osize, Onone. It is the same as Swift Compiler - Code Generation -> Optimization Level
여기서 (스택에 할당)및 (히프에 할당)을 찾을 수 있습니다.
[최적화 수준(SWIFT_OPTIMIZATION_LEVEL)]
상속을 받고 참조로 전달되는 클래스의 경우, 구조체에는 상속이 없으며 값으로 전달됩니다.
Swift에는 훌륭한 WWDC 세션이 있습니다.이 질문에 대한 자세한 답변은 그 중 하나입니다.언어 가이드나 iBook보다 훨씬 더 빠르게 속도를 낼 수 있으므로 이러한 내용을 확인하십시오.
구조가 기능성을 저하시킨다고는 말할 수 없습니다.
물론, 자아는 변이 기능을 제외하고는 불변의 존재지만, 그게 다야.
모든 수업은 추상적이거나 최종적이어야 한다는 오래된 생각을 고수하는 한 상속은 잘 작동합니다.
추상 클래스를 프로토콜로 구현하고 최종 클래스를 구조체로 구현합니다.
구조체의 장점은 공유 가변 상태를 만들지 않고 필드를 가변 상태로 만들 수 있다는 것입니다. 쓰기 시 복사가 해당 작업을 처리하기 때문입니다.
그렇기 때문에 다음 예의 속성/필드는 모두 변경 가능하지만 Java, C# 또는 swift 클래스에서는 이 작업을 수행하지 않습니다.
"example"이라는 함수의 맨 아래에 더럽고 간단한 사용법이 있는 상속 구조의 예:
protocol EventVisitor
{
func visit(event: TimeEvent)
func visit(event: StatusEvent)
}
protocol Event
{
var ts: Int64 { get set }
func accept(visitor: EventVisitor)
}
struct TimeEvent : Event
{
var ts: Int64
var time: Int64
func accept(visitor: EventVisitor)
{
visitor.visit(self)
}
}
protocol StatusEventVisitor
{
func visit(event: StatusLostStatusEvent)
func visit(event: StatusChangedStatusEvent)
}
protocol StatusEvent : Event
{
var deviceId: Int64 { get set }
func accept(visitor: StatusEventVisitor)
}
struct StatusLostStatusEvent : StatusEvent
{
var ts: Int64
var deviceId: Int64
var reason: String
func accept(visitor: EventVisitor)
{
visitor.visit(self)
}
func accept(visitor: StatusEventVisitor)
{
visitor.visit(self)
}
}
struct StatusChangedStatusEvent : StatusEvent
{
var ts: Int64
var deviceId: Int64
var newStatus: UInt32
var oldStatus: UInt32
func accept(visitor: EventVisitor)
{
visitor.visit(self)
}
func accept(visitor: StatusEventVisitor)
{
visitor.visit(self)
}
}
func readEvent(fd: Int) -> Event
{
return TimeEvent(ts: 123, time: 56789)
}
func example()
{
class Visitor : EventVisitor
{
var status: UInt32 = 3;
func visit(event: TimeEvent)
{
print("A time event: \(event)")
}
func visit(event: StatusEvent)
{
print("A status event: \(event)")
if let change = event as? StatusChangedStatusEvent
{
status = change.newStatus
}
}
}
let visitor = Visitor()
readEvent(1).accept(visitor)
print("status: \(visitor.status)")
}
Swift에서는 Protocol Oriented Programming으로 알려진 새로운 프로그래밍 패턴이 도입되었습니다.
크레이셔널 패턴:
swift에서 Structure는 자동으로 복제되는 값 유형입니다.따라서 프로토타입 패턴을 구현하기 위해 필요한 동작을 무료로 제공합니다.
반면 클래스는 할당 중에 자동으로 복제되지 않는 참조 유형입니다.프로토타입 패턴을 구현하기 위해 클래스는 다음을 채택해야 합니다.NSCopying프로토콜입니다.
얕은 복사본은 해당 개체를 가리키는 참조만 복제하는 반면 깊은 복사본은 개체의 참조를 복제합니다.
각 참조 유형에 대해 심층 복사를 구현하는 것은 지루한 작업이 되었습니다.클래스에 추가 참조 유형이 포함된 경우 각 참조 특성에 대한 프로토타입 패턴을 구현해야 합니다.그리고 실제로 객체 그래프 전체를 복사해야 합니다.NSCopying프로토콜입니다.
class Contact{
var firstName:String
var lastName:String
var workAddress:Address // Reference type
}
class Address{
var street:String
...
}
구조 및 Enum을 사용하여 복사 로직을 구현할 필요가 없기 때문에 코드를 심플하게 만들었습니다.
많은 Cocoa API에서는 NSObject 서브클래스가 필요하기 때문에 강제로 클래스를 사용할 수 있습니다.그러나 그 외에 Apple의 Swift 블로그에서 다음과 같은 사례를 사용하여 structure/enum 값 유형을 사용할지 클래스 참조 유형을 사용할지 결정할 수 있습니다.
https://developer.apple.com/swift/blog/ ?id = 10
이러한 답변에서 주목받지 못하는 한 가지 포인트는 클래스를 유지하는 변수 vs 구조체일 수 있다는 것입니다.let오브젝트 속성을 변경할 수 있지만 구조에서는 변경할 수 없습니다.
이 기능은 변수가 다른 개체를 가리키지 않고 개체를 수정해야 하는 경우(예: 업데이트하려는 인스턴스 변수가 여러 개 있는 경우)에 유용합니다.구조체일 경우 변수를 다른 개체로 모두 재설정할 수 있도록 허용해야 합니다.var이를 위해 Swift의 상수 값 유형은 변환이 0인 반면 참조 유형(클래스)은 이러한 방식으로 동작하지 않기 때문입니다.
구조는 값 유형이기 때문에 스택에 저장할 메모리를 매우 쉽게 만들 수 있습니다.Structure에 쉽게 접근할 수 있으며 작업 범위 후에는 스택의 상단에서 팝을 통해 스택 메모리에서 쉽게 할당 해제됩니다.한편, 참조 클래스는 힙에 저장되는 참조 유형이며, 한 클래스 개체에서 변경된 내용은 밀접하게 결합되어 참조 유형에 따라 다른 개체에 영향을 미칩니다.구조의 모든 구성원은 공용인 반면 클래스의 모든 구성원은 비공개입니다.
구조의 단점은 유전될 수 없다는 것이다.
구조 및 클래스는 사용자 정의 데이터 유형입니다.
디폴트로는 구조는 퍼블릭이지만 클래스는 프라이빗입니다.
클래스는 캡슐화 원칙을 구현합니다.
클래스의 개체가 힙 메모리에 생성됩니다.
클래스는 재사용성을 위해 사용되는 반면 구조는 동일한 구조에서 데이터를 그룹화하는 데 사용됩니다.
구조 데이터 멤버는 직접 초기화할 수 없지만 구조 외부에서 할당할 수 있습니다.
클래스 데이터 멤버는 매개 변수 감소 생성자에 의해 직접 초기화되고 매개 변수화된 생성자에 의해 할당될 수 있습니다.
언급URL : https://stackoverflow.com/questions/24232799/why-choose-struct-over-class
'programing' 카테고리의 다른 글
| 한 디렉터리에 있지만 다른 디렉터리에 없는 파일 찾기 (0) | 2023.04.22 |
|---|---|
| MVVM에는 어떤 프레임워크를 사용해야 합니까? (0) | 2023.04.22 |
| Visual Studio 2010을 완전히 제거하려면 어떻게 해야 합니까? (0) | 2023.04.22 |
| git 오류: RPC 실패, 56 OpenSSL SSL_read: SSL_ERROR_SYSCALL, errno 10054 (0) | 2023.04.22 |
| 디렉토리에서 일부 파일을 제외한 모든 파일 제거 (0) | 2023.04.22 |