-
Notifications
You must be signed in to change notification settings - Fork 295
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Could not cast value of type #MyClass to NSObject #67
Comments
I tested inheriting NSObject and it worked fine. I hope theres other solution because I wouldn't like the idea of inheriting unnecessary class. |
Hi @ingun37, could you provide more context, please? |
I found a solution Xcode version: 9.4.1 class MyClass: Hashable, Decodable {
let s:String
init(_ s:String) {
self.s = s
}
var hashValue: Int {return s.hashValue}
static func == (lhs: apiTests.MyClass, rhs: apiTests.MyClass) -> Bool {
return lhs.s == rhs.s
}
}
func testFail() {
let ex = XCTestExpectation(description: "test")
Promise { Set([MyClass("a"), MyClass("b")]) }.then { (a)-> Promise<Set<MyClass>> in
Promise {a}
}.then {
print($0)
ex.fulfill()
}
wait(for: [ex], timeout: 10.0)
}
func testSuccess() {
let ex = XCTestExpectation(description: "test")
Promise { Set([MyClass("a"), MyClass("b")]) }.then {
print($0)
ex.fulfill()
}
wait(for: [ex], timeout: 10.0)
} It doesnt break at the exactly same point but I think its the same bug |
Thank you for reporting that @ingun37 ! The root of the issue goes deeply in Swfit-ObjC interoperability, which has special handling for hashable containers ( Briefly, if we have the following code in ObjC: @implementation ObjC
- (nullable id)cast:(nullable id)object {
return object;
}
@end When we pass a Swift object in such a method and try to restore the type for the returned value, the Swift dynamic cast will crash in case the object is a hashable container with object of custom class TestClass: Hashable {
init(_ string: String) {
self.string = string
}
var hashValue: Int { return string.hashValue }
static func == (lhs: TestClass, rhs: TestClass) -> Bool {
return lhs.string == rhs.string
}
private let string: String
}
let input = Set([TestClass("a")])
let output = ObjC().cast(input)
let value = output as? Set<TestClass> // Run-time crash! Or the same in case of a let input = [TestClass("a"): "a"]
let output = ObjC().cast(input)
let value = output as? Dictionary<TestClass, String> // Run-time crash! Since Promises for Swift rely on ObjC implementation for compatibility reasons, any value a promise gets resolved with goes through conversion to Generally, the issue may be perceived as a flaw in Swift-ObjC interoperability and unfortunately, we don't currently have a proper fix or a good workaround for it, other than not using Promises with hashable containers holding custom types (any A direction to explore would be something like: let output = ObjC().cast(input) as AnyObject
if let keys = output.allKeys as? [AnyHashable], let values = output.allObjects {
let value = Dictionary(uniqueKeysWithValues: zip(keys, values)) as? Type
} else if let values = output.allObjects as? [AnyHashable] {
let value = Set(values) as? Type
} else {
let value = output as? Type
} Where Anyhow, I hope the above sheds some light on the root of the problem. We're open for any suggestions and continue searching for a real fix w/o modifying the compiler, of course. |
I ran to this runtime error.
Does it mean my class has to be inherited from NSObject to be used as Promise type?
It stops at this library code
callstack :
...
#4 0x000000010f00ccfb in swift::swift_dynamicCastFailure(void const*, char const*, void const*, char const*, char const*) ()
#5 0x000000010f00cd60 in swift::swift_dynamicCastFailure(swift::TargetMetadataswift::InProcess const*, swift::TargetMetadataswift::InProcess const*, char const*) ()
#6 0x000000010f049d8e in swift_dynamicCastObjCClassUnconditional ()
#7 0x000000010f00f03d in swift_dynamicCast ()
#8 0x000000010f4eaf1a in swift_rt_swift_dynamicCast ()
#9 0x000000010f546f64 in specialized setDownCastConditional<A, B>(:) ()
#10 0x000000010f5478c2 in specialized static Set.conditionallyBridgeFromObjectiveC(:result:) ()
#11 0x000000010f4a792f in static Set.conditionallyBridgeFromObjectiveC(:result:) ()
#12 0x000000010f4a79a4 in protocol witness for static ObjectiveCBridgeable.conditionallyBridgeFromObjectiveC(:result:) in conformance Set ()
#13 0x000000010f0100cd in dynamicCastClassToValueViaObjCBridgeable(swift::OpaqueValue*, swift::OpaqueValue*, swift::TargetMetadataswift::InProcess const*, swift::TargetMetadataswift::InProcess const*, (anonymous namespace)::ObjectiveCBridgeableWitnessTable const*, swift::DynamicCastFlags) ()
#14 0x000000010946f02a in swift_rt_swift_dynamicCast ()
#15 0x000000010947eddd in static Promise.asValue(:) at $projectpath/Pods/PromisesSwift/Sources/Promises/Promise.swift:104
#16 0x00000001094794d3 in closure #1 in Promise.then(on::) at $projectpath/Pods/PromisesSwift/Sources/Promises/Promise+Then.swift:90
#17 0x0000000109479a6d in partial apply for closure #1 in Promise.then(on::) ()
#18 0x000000010947823c in thunk for @escaping @callee_guaranteed (@owned Swift.AnyObject?) -> (@out Any?) ()
#19 0x000000010880567e in __56-[FBLPromise chainOnQueue:chainedFulfill:chainedReject:]_block_invoke.88 at $projectpath/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise.m:271
#20 0x00000001088048f5 in __44-[FBLPromise observeOnQueue:fulfill:reject:]_block_invoke_2 at $projectpath/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise.m:224
Thank you.
The text was updated successfully, but these errors were encountered: