Swift는 리플렉션을 지원합니까?


113

Swift는 리플렉션을 지원합니까? 예를 들어 Swift 객체 valueForKeyPath:와 같은 것이 setValue:forKeyPath:있습니까?

실제로 obj.classObjective-C 와 같은 동적 유형 시스템도 있습니까?


1
Swift에서 리플렉션을위한 도우미 클래스를 만들었습니다. 다음에서 찾을 수 있습니다. github.com/evermeer/EVReflection
Edwin Vermeer

2
그들은 Swift 2.0 내에서 반영을 제거했습니다. 이것이 내가 속성과 값을 열거하는 방법입니다 Link
mohacs

답변:


85

반사 지원이 시작된 것 같습니다.

class Fruit {
    var name="Apple"
}

reflect(Fruit()).count         // 1
reflect(Fruit())[0].0          // "name"
reflect(Fruit())[0].1.summary  // "Apple"

mchambers 요점에서, 여기 : https://gist.github.com/mchambers/fb9da554898dae3e54f2


5
글쎄, 나는 이것을 진짜 반영이라고 생각하지 않을 것입니다. 한 가지는 읽기 전용입니다. Xcode에서 디버깅을 활성화하는 것은 해킹 일뿐입니다. 프로토콜은 Mirror실제로 단어를 IDE여러 번 인용합니다 .
Sulthan

7
그리고 그것은 속성에 대해서만 작동합니다. 방법 반영이 없습니다.
Sulthan

11
체크인 요점의 작성자. WWDC의 Swift 랩에서이 글을 썼고 나머지는 공유 할 것이라고 생각했습니다. 모두가 이해했듯이, 나와 이야기 한 엔지니어들은 플레이 그라운드를 지원하기 위해 reflect () 함수가 존재한다는 것을 확인했습니다. 그러나 당신은 여전히 ​​그것을 가지고 약간의 재미를 가질 수 있습니다 :) 여기 나는 그것을 사용하여 작은 모델 직렬 변환기를 해킹했습니다. 놀이터에 붙여 재미를 : gist.github.com/mchambers/67640d9c3e2bcffbb1e2
마크 챔버

1
어떻게 도움이 될 수 있는지 알아 보려면 답변 stackoverflow.com/a/25345461/292145 를 살펴보십시오 _stdlib_getTypeName.
Klaas

1
다음은 기본 클래스와 선택 사항 (유형이 아님)을 반영하고 NSCoding 및 사전에 대한 구문 분석을 지원하는 클래스입니다. github.com/evermeer/EVCloudKitDao/blob/master/AppMessage/…
Edwin Vermeer

44

클래스가을 확장 NSObject하면 Objective-C의 모든 내성과 역 동성이 작동합니다. 여기에는 다음이 포함됩니다.

  • 클래스에 메서드 및 속성에 대해 질문하고 메서드를 호출하거나 속성을 설정하는 기능.
  • 메소드 구현을 교환하는 기능. (모든 인스턴스에 기능 추가).
  • 즉석에서 새 하위 클래스를 생성하고 할당하는 기능. (주어진 인스턴스에 기능 추가)

이 기능의 한 가지 단점은 Swift 선택적 값 유형에 대한 지원입니다. 예를 들어 Int 속성은 열거 및 수정할 수 있지만 Int? 속성은 할 수 없습니다. 선택적 유형은 reflect / MirrorType을 사용하여 부분적으로 열거 할 수 있지만 여전히 수정되지는 않습니다.

클래스가 확장되지 않으면 NSObject새롭고 매우 제한적인 (그리고 진행중인?) 리플렉션 만 작동합니다 (reflect / MirrorType 참조). 이는 인스턴스에 클래스 및 속성에 대해 질문 할 수있는 제한된 기능을 추가하지만 위의 추가 기능은 없습니다. .

NSObject를 확장하지 않거나 '@objc'지시문을 사용하는 경우 Swift는 기본적으로 정적 및 vtable 기반 디스패치를 ​​사용합니다. 더 빠르지 만 가상 머신이없는 경우 런타임 메서드 차단이 허용되지 않습니다. 이 차단은 Cocoa의 기본 부분이며 다음 유형의 기능에 필요합니다.

  • Cocoa의 우아한 재산 관찰자. (속성 관찰자는 Swift 언어에 바로 적용됩니다).
  • 로깅, 트랜잭션 관리 (예 : Aspect Oriented Programming)와 같은 비 침습적 적용 교차 절단 문제.
  • 프록시, 메시지 전달 등

따라서 Swift로 구현 된 Cocoa / CocoaTouch 애플리케이션의 clases를 권장합니다.

  • NSObject에서 확장합니다. Xcode의 새로운 클래스 대화 상자는이 방향으로 조정됩니다.
  • 동적 디스패치의 오버 헤드로 인해 성능 문제가 발생하는 경우 정적 디스패치를 ​​사용할 수 있습니다.

요약:

  • Swift는 빠른 static / vtable 디스패치 및 제한된 리플렉션으로 C ++처럼 동작 할 수 있습니다. 따라서 C ++와 관련된 복잡성, 학습 곡선 또는 오류 위험없이 낮은 수준 또는 성능 집약적 인 애플리케이션에 적합합니다.
  • Swift는 컴파일 된 언어이지만, 메시징 스타일의 메서드 호출은 Objective-C와 비슷하지만 Objective-C의 레거시 구문이없는 Ruby 및 Python과 같은 현대 언어에서 발견되는 내성과 역 동성을 추가합니다.

참조 데이터 : 메서드 호출에 대한 실행 오버 헤드 :

  • 정적 : <1.1ns
  • vtable : ~ 1.1ns
  • 동적 : ~ 4.9ns

(실제 성능은 하드웨어에 따라 다르지만 비율은 비슷합니다.)

또한 dynamic 속성을 사용하면 메소드가 동적 디스패치를 ​​사용해야하며 따라서 가로 채기를 지원할 것임을 Swift에 명시 적으로 지시 할 수 있습니다.

public dynamic func foobar() -> AnyObject {
}

2
Objective-C 기술을 사용하더라도 선택적 Swift 유형에는 작동하지 않는 것 같습니다. 내가 속임수를 놓치고 있지 않는 한 대답 에이 제한을 언급하는 것이 좋습니다.
whitneyland

8

문서는 주로 동적 유형 시스템에 대해 설명합니다.

TypedynamicType

참조 (언어 참조) 메타 타입 유형

예:

var clazz = TestObject.self
var instance: TestObject = clazz()

var type = instance.dynamicType

println("Type: \(type)") //Unfortunately this prints only "Type: Metatype"

이제 TestObject확장 가정NSObject

var clazz: NSObject.Type = TestObject.self
var instance : NSObject = clazz()

if let testObject = instance as? TestObject {
    println("yes!") //prints "yes!"
}

현재는 리플렉션이 구현되지 않았습니다.

편집 : 나는 분명히 틀렸다. stevex의 대답을 참조하십시오. IDE가 개체 내용을 검사 할 수 있도록 속성 빌드에 대한 간단한 읽기 전용 리플렉션이 있습니다.


6

스위프트 리플렉션 API는 현재 Apple의 최우선 순위가 아닌 것 같습니다. 그러나 @stevex 답변 외에도 표준 라이브러리에 도움이되는 또 다른 기능이 있습니다.

베타 6 _stdlib_getTypeName부터는 변수의 유형 이름이 변경됩니다. 이것을 빈 플레이 그라운드에 붙여 넣으십시오.

import Foundation

class PureSwiftClass {
}

var myvar0 = NSString() // Objective-C class
var myvar1 = PureSwiftClass()
var myvar2 = 42
var myvar3 = "Hans"

println( "TypeName0 = \(_stdlib_getTypeName(myvar0))")
println( "TypeName1 = \(_stdlib_getTypeName(myvar1))")
println( "TypeName2 = \(_stdlib_getTypeName(myvar2))")
println( "TypeName3 = \(_stdlib_getTypeName(myvar3))")

출력은 다음과 같습니다.

TypeName0 = NSString
TypeName1 = _TtC13__lldb_expr_014PureSwiftClass
TypeName2 = _TtSi
TypeName3 = _TtSS

Ewan Swick의 블로그 항목 은 다음 문자열을 해독하는 데 도움이됩니다.

예를 들어 _TtSiSwift의 내부 Int유형을 나타냅니다 .

Mike Ash는 같은 주제를 다루는 훌륭한 블로그 항목을 가지고 있습니다.


@aleclarson 예, 그것도 매우 유용합니다.
Klaas 2014 년

1
그 개인 API가 아닌가요? 앱이 사용되는 경우 Apple에서 승인합니까?
Eduardo Costa

@EduardoCosta 예, 확실히. 그들은 사적입니다. 디버그 빌드에만 사용합니다.
Klaas

다음은 Ewan Swick
RenniePet

5

대신 toString () 사용을 고려할 수 있습니다 . 공용이며 _stdlib_getTypeName () 과 동일하게 작동 하지만 AnyClass 에서도 작동한다는 차이점이 있습니다 ( 예 : Playground enter).

class MyClass {}

toString(MyClass.self) // evaluates to "__lldb_expr_49.MyClass"

1

reflectSwift 5에는 키워드가 없습니다 . 이제 사용할 수 있습니다.

struct Person {
    var name="name"
    var age = 15
}

var me = Person()
var mirror = Mirror(reflecting: me)

for case let (label?, value) in mirror.children {
    print (label, value)
}

왜 이것이 찬성되지 않습니까? 이것은 v 유용합니다. json역 직렬화 에 적용하겠습니다
javadba
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.