如何检查是否已使用Swift反射设置属性?

时间:2016-01-04 23:34:44

标签: swift reflection

我的一些模型具有可选属性。我试图编写一种可以评估它们是否已经设置的方法。

以下是尝试,但我无法弄清楚如何从Any对象中确定零值[编辑:( child变量的类型为Any} )]。它没有编译。

func allPropertiesHaveValues(obj: AnyObject) -> Bool {
    let mirror = Mirror(reflecting: obj)
    for child in mirror.children {
       let value = child.value
       if let optionalValue = value as? AnyObject? { //Does not compile
          if optionalValue == nil {
             return false 
          }
       }
    }
    return true
}

修改

我忘了澄清上例中的child值始终为Any类型。 Any类型很难,因为它无法与nil进行比较,而AnyObject的强制转换始终会失败。我试图在下面的操场上说明它。

var anyArray = [Any]();

var optionalStringWithValue: String? = "foo";
anyArray.append(optionalStringWithValue);

var nilOptional: String?
anyArray.append(nilOptional)

print(anyArray[0]);   // "Optional("foo")\n"
print(anyArray[1]);   // "nil\n"

if let optionalString = anyArray[0] as? AnyObject {
    //will always fail
    print("success")
}

//if anyArray[1] == nil {  //  will not compile

//}

4 个答案:

答案 0 :(得分:4)

<强>过时:

您只需检查可选值是否为零:

func allPropertiesHaveValues(obj: AnyObject) -> Bool {
   let mirror = Mirror(reflecting: obj)
   for child in mirror.children {
     //child.value being an optional
     if child.value == nil {
       return false
     }
    }
   return true
}

修改

使用反射来检查Any对象是否是可选的并包含值:

let optionalString : String? = "optional string"
let any : Any = optionalString

//First you will need to create a mirror of the any object
let mirror = Mirror(reflecting : any)

//Then you can check the display style to see if it's an optional
if mirror.displayStyle == .Optional {
    //If it is, check the count of its children to see if there is a value or not
    if mirror.children.count == 0 {
        print("I don't have a value")
    }
    else {
        print("I have a value")
    }
}

这是一个游乐场示例(基于你的):

var anyArray = [Any]()

var optionalStringWithValue: String? = "foo"
anyArray.append(optionalStringWithValue)

var nilOptional: String?
anyArray.append(nilOptional)

let string = "string not optional"
anyArray.append(string)

print(anyArray[0])   // "Optional("foo")\n"
print(anyArray[1])   // "nil\n"
print(anyArray[2])   // "string not optional\n"

let mirrorOptionalWithValue = Mirror(reflecting: anyArray[0])

if mirrorOptionalWithValue.displayStyle == .Optional
    && mirrorOptionalWithValue.children.count == 1 {
    print("Is an optional and contains a value")
}

let mirrorOptionalWithoutValue = Mirror(reflecting: anyArray[1])

if mirrorOptionalWithoutValue.displayStyle == .Optional &&
    mirrorOptionalWithoutValue.children.count == 0 {
    print("Is an optional but is nil")
}

let mirrorNotAnOptional = Mirror(reflecting: anyArray[2])

if mirrorNotAnOptional.displayStyle != .Optional {
    print("Is not an optional")
}

答案 1 :(得分:3)

我使用了反映Any值的@ebluehands技术来修改原始函数。它使用初始镜像循环遍历属性,然后使用displayStyle单独反映每个属性以确定属性是否是可选的。

func allPropertiesHaveValues(obj: AnyObject) -> Bool {
    let mirror = Mirror(reflecting: obj)
    for child in mirror.children {
        let value: Any = child.value
        let subMirror = Mirror(reflecting: value)
        if subMirror.displayStyle == .Optional {
            if subMirror.children.count == 0 {
                return false
            }
        }
    }
    return true
}

答案 2 :(得分:0)

另一个选择是创建扩展名。

extension NSManagedObject {

    func checkIfAllRequiredMembersAreSet() -> Bool {
        let attributes = self.entity.attributesByName

        for (attribute, value) in attributes {

            if value.attributeValueClassName != nil {
                let v: AnyObject? = self.valueForKey(attribute)
                if !value.optional && v != nil {
                    return false
                }
            }
        }

        return true
    }
}

答案 3 :(得分:0)

根据this answer,我建议使用var main = myApp.controller("main", ['$scope', function ($scope) { /* Include the following two lines in index.html head <script src='build/pdfmake.min.js'></script> <script src='build/vfs_fonts.js'></script> After that in your angularjs controller you can write the following lines to implement a function. getPdf in the controller scope. This can be attached to a button click using ng-click and it will download the pdf with the image. eg. <div ng-controller="main"> <button ng-click="getPdf()">Get PDF</button> </div> */ $scope.image = "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"; $scope.getPdf = function(){ var imageContentDefinition = { content: [ { image: 'data:image/jpeg;base64,' + $scope.image } ]}; pdfMake.createPdf(imageContentDefinition).download("yourpdf.pdf"); }; }]);

我最近做了一些事情,以确保我至少有一个可选集。这是一个确保所有设置都已确定的示例。你可以粘贴到游乐场:

if case Optional<Any>.some(_)