斯威夫特为什么这样?要求AnyObject vs Any

时间:2021-07-20 16:10:09

I'm getting a compiler error at the as?. Type 'Type' does not conform to protocol 'AnyObject'. Why would as? be requiring AnyObject?

我在as?收到编译错误。类型“类型”不符合协议“AnyObject”。为什么会这样?需要AnyObject吗?

func listForKey<Type>(key: String) -> [Type] {

    guard let fullList = (itemList as NSArray).valueForKey( key ) as? NSArray else {
        return [Type]()
    }

    // Filter out any values not matching the expected type such as if nil was used (value wasn't supplied)!
    let typeOnlyList = fullList.filter( {$0 as? Type != nil} )
    guard let foundList = typeOnlyList as? [Type] else {     // <== at as?, Compiler Error 'Type' does not conform to protocol AnyObject
        return [Type]()
    }

    return foundList
}

If I change the declaration to the following, it will compile:

如果我将声明更改为以下内容,它将编译:

func listForKey<Type:AnyObject>(key: String) -> [Type] {

However, it then won't work with String objects as Strings are of type any. Any thoughts on what's going on?

但是,它不适用于String对象,因为字符串是any类型。对于发生了什么的任何想法?

斯威夫特为什么这样?要求AnyObject vs Any

I thought I had a potential solution after reading Anton's comment by casting to Any. That resolved the compile time error, but now I get a runtime error (fatal error: array cannot be bridged from Objective-C):

我认为在阅读Anton的评论之后我有一个潜在的解决方案。这解决了编译时错误,但现在我得到一个运行时错误(致命错误:数组无法从Objective-C桥接):

extension NSArray {
    public func toSwiftArray<Type>() -> [Type] {
        // Filter out any values not matching the expected type such as nil
        let typeOnlyList : [AnyObject] = self.filter( {$0 is Type} )
        let typeOnlyAnyList : [Any] = typeOnlyList as [Any]                // <== Runtime error EXC_BAD_INSTRUCTION
        guard let foundList : [Type] = typeOnlyAnyList as? [Type] else {
            return [Type]()
        }

        return foundList
    }
}

Why would casting from [AnyObject] to [Any] cause a runtime error? I figured [Any] was the super set of [AnyObject].

为什么从[AnyObject]转换为[Any]会导致运行时错误?我认为[Any]是[AnyObject]的超级集合。

3 个解决方案

#1


1  

Here:

guard let fullList = ... as? NSArray

... you declare your fullList variable to be NSArray.

...您将fullList变量声明为NSArray。

Therefore typeOnlyList is also NSArray (it's a result of filtering of fullList).

因此typeOnlyList也是NSArray(它是对fullList进行过滤的结果)。

NSArray's elements are AnyObject's (bridged from Objective-C).

NSArray的元素是AnyObject(从Objective-C桥接)。

Therefore, when you try to cast typeOnlyList as? [Type] Swift expects Type to conform to AnyObject protocol.

因此,当您尝试将typeOnlyList强制转换为? [Type] Swift希望Type符合AnyObject协议。

#2


0  

I guess this doesn't really answer the original question. However, it is a workaround that gets the job done. I still don't understand why the solution above doesn't work (especially the fatal error when casting from [AnyObject] to [Any]), but I took a different approach which works great:

我想这并没有真正回答原来的问题。但是,这是一种可以完成工作的解决方法。我仍然不明白为什么上面的解决方案不起作用(尤其是从[AnyObject]转换为[Any]时的致命错误),但我采用了一种非常有效的方法:

extension NSArray {
    public func toSwiftArray<Type>() -> [Type] {
        var swiftArray = [Type]()

        for value in self {
            if let valueOfType = value as? Type {
                swiftArray.append( valueOfType )
            }
        }

        return swiftArray
    }

    public func toSwiftArray<Type>() -> ([Type], [Any]) {
        var swiftTypeArray = [Type]()
        var unknownTypeArray = [Any]()

        for value in self {
            if let valueOfType = value as? Type {
                swiftTypeArray.append( valueOfType )
            } else {
                unknownTypeArray.append( value )
            }
        }

        return (swiftTypeArray, unknownTypeArray)
    }
}

Not sure why I couldn't use .filter to do this, but this is a very straightforward solution to the problem, and it also allows for a version that returns a list of the values that couldn't be converted. This is very handy routine for converting to NSArray with full type safety.

不知道为什么我不能使用.filter来做这个,但这是一个非常简单的问题解决方案,它还允许一个版本返回一个无法转换的值列表。这是转换为具有完全类型安全性的NSArray的非常方便的例程。

#3


0  

If you want to work with NSArray in Swift, you will have to work with classes only because NSArray cannot hold anything else.

如果你想在Swift中使用NSArray,你必须只使用类,因为NSArray不能保存任何其他内容。

extension NSArray {
    public func toSwiftArray<Type: AnyObject>() -> [Type] {

        let typeOnlyList : NSArray = self.filter( {$0 is Type} )
        return typeOnlyList as! Array<Type>
    }
}

let nsArray: NSArray = [10, 20, "my-text"]
print("NSArray: \(nsArray)")

let swiftArray: [NSString] = nsArray.toSwiftArray()
print("Swift array: \(swiftArray)")

In short: use NSString instead of String. You can also convert [NSString] to [String] as the second step.

简而言之:使用NSString而不是String。您还可以将[NSString]转换为[String]作为第二步。

#1


1  

Here:

guard let fullList = ... as? NSArray

... you declare your fullList variable to be NSArray.

...您将fullList变量声明为NSArray。

Therefore typeOnlyList is also NSArray (it's a result of filtering of fullList).

因此typeOnlyList也是NSArray(它是对fullList进行过滤的结果)。

NSArray's elements are AnyObject's (bridged from Objective-C).

NSArray的元素是AnyObject(从Objective-C桥接)。

Therefore, when you try to cast typeOnlyList as? [Type] Swift expects Type to conform to AnyObject protocol.

因此,当您尝试将typeOnlyList强制转换为? [Type] Swift希望Type符合AnyObject协议。

#2


0  

I guess this doesn't really answer the original question. However, it is a workaround that gets the job done. I still don't understand why the solution above doesn't work (especially the fatal error when casting from [AnyObject] to [Any]), but I took a different approach which works great:

我想这并没有真正回答原来的问题。但是,这是一种可以完成工作的解决方法。我仍然不明白为什么上面的解决方案不起作用(尤其是从[AnyObject]转换为[Any]时的致命错误),但我采用了一种非常有效的方法:

extension NSArray {
    public func toSwiftArray<Type>() -> [Type] {
        var swiftArray = [Type]()

        for value in self {
            if let valueOfType = value as? Type {
                swiftArray.append( valueOfType )
            }
        }

        return swiftArray
    }

    public func toSwiftArray<Type>() -> ([Type], [Any]) {
        var swiftTypeArray = [Type]()
        var unknownTypeArray = [Any]()

        for value in self {
            if let valueOfType = value as? Type {
                swiftTypeArray.append( valueOfType )
            } else {
                unknownTypeArray.append( value )
            }
        }

        return (swiftTypeArray, unknownTypeArray)
    }
}

Not sure why I couldn't use .filter to do this, but this is a very straightforward solution to the problem, and it also allows for a version that returns a list of the values that couldn't be converted. This is very handy routine for converting to NSArray with full type safety.

不知道为什么我不能使用.filter来做这个,但这是一个非常简单的问题解决方案,它还允许一个版本返回一个无法转换的值列表。这是转换为具有完全类型安全性的NSArray的非常方便的例程。

#3


0  

If you want to work with NSArray in Swift, you will have to work with classes only because NSArray cannot hold anything else.

如果你想在Swift中使用NSArray,你必须只使用类,因为NSArray不能保存任何其他内容。

extension NSArray {
    public func toSwiftArray<Type: AnyObject>() -> [Type] {

        let typeOnlyList : NSArray = self.filter( {$0 is Type} )
        return typeOnlyList as! Array<Type>
    }
}

let nsArray: NSArray = [10, 20, "my-text"]
print("NSArray: \(nsArray)")

let swiftArray: [NSString] = nsArray.toSwiftArray()
print("Swift array: \(swiftArray)")

In short: use NSString instead of String. You can also convert [NSString] to [String] as the second step.

简而言之:使用NSString而不是String。您还可以将[NSString]转换为[String]作为第二步。