저는 Swift를 처음 접했고 클래스가 참조로 전달되고 배열 / 문자열 등이 복사된다는 것을 읽었습니다.
참조에 의한 전달은 Objective-C 또는 Java에서 실제로 "a"참조를 전달하는 것과 동일한 방식입니까? 아니면 참조에 의한 적절한 전달입니까?
저는 Swift를 처음 접했고 클래스가 참조로 전달되고 배열 / 문자열 등이 복사된다는 것을 읽었습니다.
참조에 의한 전달은 Objective-C 또는 Java에서 실제로 "a"참조를 전달하는 것과 동일한 방식입니까? 아니면 참조에 의한 적절한 전달입니까?
답변:
규칙은 다음과 같습니다.
클래스 인스턴스는 참조 유형 (즉, 당신의 클래스 인스턴스를 참조하여 효과적으로이다 포인터 )
함수는 참조 유형입니다.
그 밖의 모든 것은 값 유형입니다 . "기타 모든 것"은 단순히 구조체의 인스턴스와 열거 형의 인스턴스를 의미합니다. 그게 스위프트에있는 전부이기 때문입니다. 예를 들어 배열과 문자열은 구조체 인스턴스입니다. newacct가 지적한 것처럼 주소 를 사용 하고 가져옴 으로써 (함수 인수로) 이러한 것 중 하나에 대한 참조를 전달할 수 있습니다inout
. 그러나 유형 자체는 가치 유형입니다.
참조 유형 객체는 실제로 다음과 같은 이유로 특별합니다.
단순한 할당 또는 함수에 전달하면 동일한 객체에 대한 여러 참조가 생성 될 수 있습니다.
객체에 대한 참조가 상수 ( let
, 명시 적 또는 암시 적) 인 경우에도 객체 자체는 변경 가능합니다 .
개체에 대한 변형은 개체에 대한 모든 참조에서 볼 수있는 것처럼 개체에 영향을줍니다.
위험 할 수 있으므로주의를 기울이십시오. 반면에 참조 유형을 전달하는 것은 포인터 만 복사 및 전달되기 때문에 명확하게 효율적입니다.
분명히 값 유형을 전달하는 것은 "안전하다"는 let
의미이며 let
참조 를 통해 구조체 인스턴스 또는 열거 형 인스턴스를 변경할 수 없습니다 . 다른 한편으로, 그 안전성은 가치의 별도 사본을 만들어 달성되는 것입니까? 값 유형을 전달하는 데 잠재적으로 비용이 많이 들지 않습니까?
글쎄, 예 그리고 아니오. 생각만큼 나쁘지 않습니다. Nate Cook이 말했듯이, 값 유형을 전달하는 것이 반드시 복사를 의미하는 것은 아닙니다 . 왜냐하면 let
(명시 적 또는 묵시적) 불변성을 보장하므로 아무것도 복사 할 필요가 없기 때문입니다. 그리고 심지어로 통과 var
참조하는 일이 의미하지는 않습니다 것입니다 그들은 단지 것을, 복사 할 수 있습니다 (돌연변이가 있기 때문에) 필요합니다. 이 문서는 특히 팬티를 뒤틀 지 말라고 조언합니다.
inout
유형에 관계없이 없을 때 값에 의한 전달 입니다. 참조에 의한 전달 여부는 유형과 직교합니다.
그것은되어 항상 패스에 의해 값 매개 변수가없는 경우 inout
.
그것은되어 항상 패스에 의해 참조 매개 변수 인 경우 inout
. 그러나 &
이는 inout
매개 변수에 전달할 때 인수에 연산자 를 명시 적으로 사용해야한다는 사실로 인해 다소 복잡 하므로 변수를 직접 전달하는 참조에 의한 전달의 기존 정의에 맞지 않을 수 있습니다.
inout
inout
실제로 참조로 전달되지는 않지만 copy-in copy-out 함수 호출 후 수정 된 값이 원래 인수에 할당되도록 보장합니다. 인 - 아웃 매개 변수
Swift의 모든 것은 기본적으로 "복사"에 의해 전달되므로 값 유형을 전달하면 값의 사본을 얻게되고 참조 유형을 전달하면 의미하는 모든 내용과 함께 참조의 사본을 얻게됩니다. (즉, 참조 사본은 여전히 원래 참조와 동일한 인스턴스를 가리 킵니다.)
Swift는 많은 최적화를 수행하기 때문에 위의 "복사"주위에 겁을주는 인용문을 사용합니다. 가능하면 돌연변이 나 돌연변이 가능성이있을 때까지 복사하지 않습니다. 매개 변수는 기본적으로 변경 불가능하므로 대부분의 경우 실제로 복사가 발생하지 않습니다.
다음은 참조로 전달하기위한 작은 코드 샘플입니다. 강력한 이유가없는 한 이렇게하지 마십시오.
func ComputeSomeValues(_ value1: inout String, _ value2: inout Int){
value1 = "my great computation 1";
value2 = 123456;
}
이렇게 불러
var val1: String = "";
var val2: Int = -1;
ComputeSomeValues(&val1, &val2);
inout
복사 입력, 복사 출력 연산자입니다. 먼저 객체에 복사 한 다음 함수가 반환 된 후 원래 객체를 덮어 씁니다. 동일하게 보일 수 있지만 미묘한 차이가 있습니다.
애플 스위프트 개발자 블로그라는 게시물이 값 및 참조 유형 이 매우 주제에 대한 명확하고 자세한 설명을 제공합니다.
인용하려면 :
Swift의 유형은 첫 번째, "값 유형"중 하나에 속합니다. 여기서 각 인스턴스는 일반적으로 struct, enum 또는 tuple로 정의되는 고유 한 데이터 사본을 유지합니다. 두 번째는 인스턴스가 데이터의 단일 사본을 공유하는 "참조 유형"이며 유형은 일반적으로 클래스로 정의됩니다.
Swift 블로그 게시물은 예제를 통해 차이점을 계속 설명하고 다른 하나를 사용할 때를 제안합니다.
클래스는 참조로 전달되고 다른 클래스는 기본적으로 값으로 전달됩니다. inout
키워드 를 사용하여 참조로 전달할 수 있습니다 .
inout
복사 입력, 복사 출력 연산자입니다. 먼저 객체에 복사 한 다음 함수가 반환 된 후 원래 객체를 덮어 씁니다. 동일하게 보일 수 있지만 미묘한 차이가 있습니다.
inout을 + =와 같은 중위 연산자와 함께 사용하면 & address 기호를 무시할 수 있습니다. 컴파일러가 참조로 통과한다고 가정합니까?
extension Dictionary {
static func += (left: inout Dictionary, right: Dictionary) {
for (key, value) in right {
left[key] = value
}
}
}
origDictionary + = newDictionaryToAdd
그리고 멋지게이 사전 'add'는 원래 참조에도 하나의 쓰기 만 수행하므로 잠금에 적합합니다!
클래스와 구조
구조와 클래스의 가장 중요한 차이점 중 하나는 구조가 코드에서 전달 될 때 항상 복사되지만 클래스는 참조로 전달된다는 것입니다.
폐쇄
클래스 인스턴스의 속성에 클로저를 할당하고 클로저가 인스턴스 또는 해당 멤버를 참조하여 해당 인스턴스를 캡처하면 클로저와 인스턴스 사이에 강력한 참조주기가 생성됩니다. Swift는 캡처 목록을 사용하여 이러한 강력한 참조주기를 끊습니다.
ARC (Automatic Reference Counting)
참조 계산은 클래스 인스턴스에만 적용됩니다. 구조와 열거는 참조 유형이 아니라 값 유형이며 참조로 저장 및 전달되지 않습니다.