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

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

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



답변

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

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


답변

클래스가을 확장 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 {
}


답변

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

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가 개체 내용을 검사 할 수 있도록 속성 빌드에 대한 간단한 읽기 전용 리플렉션이 있습니다.


답변

스위프트 리플렉션 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는 같은 주제를 다루는 훌륭한 블로그 항목을 가지고 있습니다.


답변

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

class MyClass {}

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


답변

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)
}


답변