【问题标题】:Cannot downcast from an object conforming to Equatable to AnyObject不能从符合 Equatable 的对象向下转换为 AnyObject
【发布时间】:2014-09-24 13:26:58
【问题描述】:

这一直困扰着我。我希望使用Moya + ReactiveCocoajson-swift

如果不重写其中一些框架似乎并不容易,因为有时我似乎需要返回一个 AnyObject 并创建了一些符合 Equatable 的数据,因此不允许这样做。

这是一个玩具 Playground 就绪示例,用于演示错误消息

struct JSValue: Equatable {
    let value:String
}

func ==(lhs: JSValue, rhs: JSValue) -> Bool {
    return (lhs.value == rhs.value)
}

var jsv = JSValue(value: "abc")
var anyValue = jsv as AnyObject

Cannot downcast from JSValue to non-@objc protocol type 'AnyObject'”的最后一行错误。

我通常会避免转换为 AnyObject,但我一直在尝试使用 an implementation of JSValue from json-swift 并重复 the pattern described inside Moya's implementation of ReactiveCocoa seen with the usage of tryMap here。 Moya + RACSignal 扩展中 tryMap 所需的回调签名期望返回一个 AnyObject。

对于那些更愿意看例子而不是理解上下文的人,我的意思是:

import Foundation

import Moya
import ReactiveCocoa

import JSONLib

/*
let MoyaErrorDomain = "Moya"

public enum MoyaErrorCode: Int {
    case ImageMapping = 0
    case JSONMapping
    case StringMapping
    case StatusCode
    case Data
}
*/

public typealias JSParsingResult = (value: JSValue?, error: Error?)

/// Extension for processing raw NSData generated by network access.
public extension RACSignal {

    /// Maps data received from the signal into a literal JSON type. If the conversion fails, the signal errors.
    public func mapLiteralJSON() -> RACSignal {
        return tryMap({ (object, error) -> AnyObject! in
            var json:AnyObject?
            if let response = object as? MoyaResponse {
                let parsingResult = JSON.parse(response.data)
                json = parsingResult.value! as AnyObject // The same error message as described previously.
            }

            // Note: ignore that I am not handling errors yet...
            /*
            if json == nil && error != nil && error.memory == nil {
                var userInfo: [NSObject : AnyObject]?
                if object != nil {
                    userInfo = ["data": object]
                }

                error.memory = NSError(domain: MoyaErrorDomain, code: MoyaErrorCode.JSONMapping.toRaw(), userInfo: userInfo)
            }
            */

            return json
        })
    }
}

是否有任何快速解决此错误消息的方法,或者我唯一的选择是使用(1)不符合 Equatable 的解析 JSON 的不同方法,或者(2)重写 Moya 以使用the other version of ReactiveCocoa in which tryMap does not return AnyObject,或者( 3) 不使用 ReactiveCocoa。

通过避免 AnyObject 来正确解决这个问题真的很好,但在这一点上,我可能缺乏 Swift 和 ReactiveCocoa 技能来做到这一点......

在非技术层面,有什么方法可以解决这个问题?减少接触未完成的技术是否明智?

【问题讨论】:

  • 如果你把它变成一个类而不是一个结构呢?
  • 问题是我无法控制那段代码。符合 Equatable 的 struct 来自 json-swift 一个抽象,用于在 Swift 中更好地处理 JSON。
  • 当然你不能将结构向下转换为'AnyObject',但是可以将你的结构转换为'Any'类型。
  • 它适用于类,因为 AnyObject 可以表示任何类类型的实例。 (参见 Swift 编程语言)。在这一行:let parsingResult = JSON.parse(response.data);,那个JSON.parse.value是什么类型!回报?以及为什么要将其强制转换为 AnyObject?
  • 相关,因为答案提供了对沮丧机制的良好解释:Double question mark, How does it work?

标签: json swift protocols reactive-cocoa


【解决方案1】:

您遇到了这个问题,因为您正在混合为 Objective-C 编写的库和为 Swift 编写的库。

Objective-C id 映射到 AnyObject,它可以是对任何类的引用。

在 Swift 中,如果你想要一个可以引用任何东西的变量,你需要使用Any

此外,出于性能原因,我们鼓励您使用 Swift 结构,其中值类型语义是有意义的。这无疑会导致结构在 Swift 库中被频繁使用。因此,您可能会遇到与 Swift 库和 Objective-C 库的重大兼容性问题。

【讨论】:

  • “此外,出于性能原因,我们鼓励您使用 Swift 结构体。”你有来自苹果的引用吗?结构有好处,但我不明白性能是选择它们的原因。
  • 有没有办法解决这个兼容性问题,或者这完全不可能?
  • @RobNapier 抱歉,该声明相当模糊且有点笼统。更正确地说,出于性能原因,您应该使用结构(值类型语义有意义的地方)。你可以在这里看到一个影响的例子:blog.human-friendly.com/…我没有引用,但从 Apple 工程师那里得到了反馈。提高性能的潜力应该非常明显,常量结构是完全不可变的,而常量类则不是。
  • @olive 解决这个问题的唯一方法是创建自己的适配器层,将这些结构转换为类,然后可以传递给需要AnyObject的Objective-C框架@
【解决方案2】:

在 ReactiveCocoa 的 Swift 版本发布之前,我的临时解决方案是这样的:

public class WrappedStruct<T> {

    let data:T?

    init(data: T?) {
        self.data = data
    }

}

我能够将该类作为 AnyObject 传递。这是一件很老套的事情,但至少很容易理解。

【讨论】:

    【解决方案3】:

    是的,我知道在 Swift 中使用 structs 而不是适当的类是可取的,但我发现以下内容可以消除 Playground 错误。

    class JSValue: Equatable {
        let value:String
    
        init(value: String) {
            self.value = value
        }
    }
    
    func ==(lhs: JSValue, rhs: JSValue) -> Bool {
        return (lhs.value == rhs.value)
    }
    
    var jsv = JSValue(value: "abc")
    var anyValue = jsv as AnyObject
    

    同样,这并不理想,但在 ReactiveCocoa 完全 Swift 化之前,它可能是您唯一的选择。我不得不对MoyaResponse 类做类似的事情。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-06
      相关资源
      最近更新 更多