[ios] Swift는 리플렉션을 지원합니까?
Swift는 리플렉션을 지원합니까? 예를 들어 Swift 객체 valueForKeyPath:
와 같은 것이 setValue:forKeyPath:
있습니까?
실제로 obj.class
Objective-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 {
}
답변
문서는 주로 동적 유형 시스템에 대해 설명합니다.
Type
과 dynamicType
예:
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의 블로그 항목 은 다음 문자열을 해독하는 데 도움이됩니다.
예를 들어 _TtSi
Swift의 내부 Int
유형을 나타냅니다 .
답변
대신 toString () 사용을 고려할 수 있습니다 . 공용이며 _stdlib_getTypeName () 과 동일하게 작동 하지만 AnyClass 에서도 작동한다는 차이점이 있습니다 ( 예 : Playground enter).
class MyClass {}
toString(MyClass.self) // evaluates to "__lldb_expr_49.MyClass"
답변
reflect
Swift 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)
}