Comments (4)
Thank you for reporting that @ingun37 !
The root of the issue goes deeply in Swfit-ObjC interoperability, which has special handling for hashable containers (Set
and Dictionary
). Feel free to play with the attached example: SwiftObjCCasting.zip
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 Hashable
(non-builtin and non-NSObject
) types in it:
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 Dictionary
:
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 nullable id
and then back to its original Swift type. That's what you see in your original crash stack trace: some promise got resolved with Swift value of hashable container type and tries to notify subscribers about that. The control leaves ObjC core logic and enters Swift wrapper, where the original Swift value is initially passed as Any?
, which we try to cast back to the original type in asValue
helper func.
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 NSObject
s are fine, though), which is obviously less than ideal.
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 Type
is the original type of input
. But that approach is quite suboptimal due to the copy overhead.
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.
from promises.
I tested inheriting NSObject and it worked fine. I hope theres other solution because I wouldn't like the idea of inheriting unnecessary class.
Thank you
from promises.
Hi @ingun37, could you provide more context, please?
A small code snippet which reproduces the issue for you would be much appreciated!
Also, Xcode and Swift version may be useful.
Thanks!
from promises.
I found a solution
I changed Promise<Set<MyClass>>
to Promise<[MyClass]>
and it works fine now
Im satisfied with the solution but I hv made this reproducing unit test code anyway because I would like to contribute as much as I love this library.
Xcode version: 9.4.1
Swift version: 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
from promises.
Related Issues (20)
- Contextual type for closure argument list expects 1 argument, which cannot be implicitly ignored
- Objective-C Promises crashes in SwiftUI previews HOT 3
- ios 16 strings convertible to NSError HOT 1
- FBLPromises fails to load building macos flutter app HOT 2
- 'NSInvalidArgumentException', reason: '-[FBLPromise HTTPBody]: unrecognized selector sent to instance HOT 1
- Confused when retry a Promise variable
- type(of: value) is NSError.Type HOT 1
- Bitcode Issue on Xcode 13 when disable it. HOT 1
- Question regarding implementation HOT 3
- Ignore a certain Error and terminate Promise HOT 5
- Please release a new version of promises that includes latest changes for Firebase HOT 4
- Builds including PromisesSwift failing on CI
- Build fails for macOS with Xcode 14.3
- Create releases for new versions HOT 1
- The iOS deployment target 'IPHONEOS_DEPLOYMENT_TARGET' is set to 8.0, but the range of supported deployment target versions is 12.0 to 17.0.99.
- Privacy manifest for sensitive APIs HOT 6
- Version 2.4.0 not compiling HOT 15
- iOS build issue with 2.4.0 HOT 5
- PrivacyInfo.xcprivacy is not included in the framework output built by Carthage HOT 1
- FBLPromises.xcframework missing mac_catalyst support HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from promises.