수색…


통사론

  • Mirror (reflection : instance) // 반영 할 주제가있는 미러를 초기화합니다.
  • mirror.displayStyle // Xcode 놀이터에 사용 된 스타일 표시
  • mirror.description //이 인스턴스의 텍스트 표현은 CustomStringConvertible을 참조하십시오.
  • mirror.subjectType // 반사되는 대상의 유형을 반환합니다.
  • mirror.superclassMirror // 반영되는 대상의 수퍼 클래스 미러를 반환합니다.

비고

  1. 총론:

Mirror 는 Swift에서 객체의 내포에 사용되는 struct 입니다. 가장 눈에 띄는 속성은 하위 배열입니다. 한 가지 가능한 사용 사례는 Core Data 대한 구조체를 직렬화하는 것입니다. 이 structNSManagedObject 로 변환하여 수행됩니다.

  1. 미러 비고의 기본 사용법 :

Mirrorchildren 속성은 Mirror 인스턴스가 반영하는 객체의 자식 객체 배열입니다. child 객체는 labelvalue 두 가지 속성 label value . 예를 들어 아이는 title 이름을 가진 속성이고 Game of Thrones: A Song of Ice and Fire 의 가치 일 수 있습니다.

거울의 기본 사용법

거울의 대상이 될 클래스 만들기

class Project {
    var title: String = ""
    var id: Int = 0
    var platform: String = ""
    var version: Int = 0
    var info: String?
}

실제로 미러의 대상이 될 인스턴스를 만듭니다. 또한 여기에서 Project 클래스의 속성에 값을 추가 할 수 있습니다.

let sampleProject = Project()
sampleProject.title = "MirrorMirror"
sampleProject.id = 199
sampleProject.platform = "iOS"
sampleProject.version = 2
sampleProject.info = "test app for Reflection"

아래 코드는 Mirror 인스턴스의 생성을 보여줍니다. 미러의 하위 등록 정보는 AnyForwardCollection<Child> 여기서 Child 는 주제의 등록 정보 및 값에 대한 typealias 튜플입니다. Child 에는 label: Stringvalue: Any .

let projectMirror = Mirror(reflecting: sampleProject)
let properties = projectMirror.children

print(properties.count)        //5
print(properties.first?.label) //Optional("title")
print(properties.first!.value) //MirrorMirror
print()

for property in properties {
    print("\(property.label!):\(property.value)")
}

위의 for 루프에 대해 Xcode의 놀이터 또는 콘솔에 출력하십시오.

title:MirrorMirror
id:199
platform:iOS
version:2
info:Optional("test app for Reflection")

Xcode 8 베타 2의 놀이터에서 테스트 됨

클래스를 인스턴스화 할 필요없이 클래스의 속성 유형 및 이름 가져 오기

Swift 클래스 사용 Mirror 는 특정 클래스의 인스턴스 에 대해 속성의 이름 , 유형 (Swift 3 : type(of: value) , Swift 2 : value.dynamicType )을 추출하려는 경우 작동합니다.

당신이 클래스에서 상속하는 경우 NSObject , 당신은 방법을 사용할 수 있습니다 class_copyPropertyList 함께 property_getAttributes 의 인스턴스를하지 않고 - 이름과 클래스의 속성 유형을 찾을 수 있습니다. Github 에서 프로젝트를 만들었지 만 코드는 다음과 같습니다.

func getTypesOfProperties(in clazz: NSObject.Type) -> Dictionary<String, Any>? {
    var count = UInt32()
    guard let properties = class_copyPropertyList(clazz, &count) else { return nil }
    var types: Dictionary<String, Any> = [:]
    for i in 0..<Int(count) {
        guard let property: objc_property_t = properties[i], let name = getNameOf(property: property) else { continue }
        let type = getTypeOf(property: property)
        types[name] = type
    }
    free(properties)
    return types
}

func getTypeOf(property: objc_property_t) -> Any {
    guard let attributesAsNSString: NSString = NSString(utf8String: property_getAttributes(property)) else { return Any.self }
    let attributes = attributesAsNSString as String
    let slices = attributes.components(separatedBy: "\"")
    guard slices.count > 1 else { return getPrimitiveDataType(withAttributes: attributes) }
    let objectClassName = slices[1]
    let objectClass = NSClassFromString(objectClassName) as! NSObject.Type
    return objectClass
}
    
   func getPrimitiveDataType(withAttributes attributes: String) -> Any {
        guard let letter = attributes.substring(from: 1, to: 2), let type = primitiveDataTypes[letter] else { return Any.self }
        return type
    }

primitiveDataTypes 는 속성 문자열의 문자를 값 유형에 매핑하는 사전입니다.

let primitiveDataTypes: Dictionary<String, Any> = [
    "c" : Int8.self,
    "s" : Int16.self,
    "i" : Int32.self,
    "q" : Int.self, //also: Int64, NSInteger, only true on 64 bit platforms
    "S" : UInt16.self,
    "I" : UInt32.self,
    "Q" : UInt.self, //also UInt64, only true on 64 bit platforms
    "B" : Bool.self,
    "d" : Double.self,
    "f" : Float.self,
    "{" : Decimal.self
]
    
   func getNameOf(property: objc_property_t) -> String? {
        guard let name: NSString = NSString(utf8String: property_getName(property)) else { return nil }
        return name as String
    }

그것은 추출 할 수 있습니다 NSObject.Type 클래스 타입에서 상속 모든 속성의 NSObject 같은 NSDate : (Swift3 Date ,) NSString (Swift3 : String ?)과 NSNumber 그러나이 유형에 가게 Any 당신이로 볼 수있다 ( 메서드에 의해 반환 된 Dictionary 값의 유형). 이는 Int, Int32, Bool과 같은 value types 의 한계 때문입니다. 이러한 유형의 호출, NSObject를 상속하지 않기 때문에 .self 예에서 int로 - Int.self NSObject.Type를 돌려주는 것이 아니라 유형하지 않습니다 Any . 따라서이 메서드는 Dictionary<String, Any>? 반환합니다 Dictionary<String, Any>? Dictionary<String, NSObject.Type>? 아닌 .

이 방법은 다음과 같이 사용할 수 있습니다.

class Book: NSObject {
    let title: String
    let author: String?
    let numberOfPages: Int
    let released: Date
    let isPocket: Bool

    init(title: String, author: String?, numberOfPages: Int, released: Date, isPocket: Bool) {
        self.title = title
        self.author = author
        self.numberOfPages = numberOfPages
        self.released = released
        self.isPocket = isPocket
    }
}

guard let types = getTypesOfProperties(in: Book.self) else { return }
for (name, type) in types {
    print("'\(name)' has type '\(type)'")
}
// Prints:
// 'title' has type 'NSString'
// 'numberOfPages' has type 'Int'
// 'author' has type 'NSString'
// 'released' has type 'NSDate'
// 'isPocket' has type 'Bool'

또한 AnyNSObject.Type 으로 캐스팅하려고 시도 할 수 있습니다. NSObject.TypeNSObject 에서 상속 한 모든 속성에 성공합니다. 그런 다음 표준 == 연산자를 사용하여 유형을 확인할 수 있습니다.

func checkPropertiesOfBook() {
    guard let types = getTypesOfProperties(in: Book.self) else { return }
    for (name, type) in types {
        if let objectType = type as? NSObject.Type {
            if objectType == NSDate.self {
                print("Property named '\(name)' has type 'NSDate'")
            } else if objectType == NSString.self {
                print("Property named '\(name)' has type 'NSString'")
            }
        }
    }
}

이 커스텀 == 연산자를 선언하면 :

func ==(rhs: Any, lhs: Any) -> Bool {
    let rhsType: String = "\(rhs)"
    let lhsType: String = "\(lhs)"
    let same = rhsType == lhsType
    return same
}

다음과 같이 value types 의 유형을 확인할 수도 있습니다.

func checkPropertiesOfBook() {
    guard let types = getTypesOfProperties(in: Book.self) else { return }
    for (name, type) in types {
        if type == Int.self {
            print("Property named '\(name)' has type 'Int'")
        } else if type == Bool.self {
            print("Property named '\(name)' has type 'Bool'")
        }
    }
}

제한 사항 이 솔루션은 value types 이 옵션 일 때 작동하지 않습니다. NSObject 서브 클래스에서 다음과 같이 속성을 선언했다면 : var myOptionalInt: Int? class_copyPropertyList 메소드 인 class_copyPropertyList 선택적 값 유형이 없기 때문에 위의 코드는 해당 특성을 찾지 않습니다.



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow