diff --git a/compiler/objc/src/main/java/org/robovm/objc/ObjCClass.java b/compiler/objc/src/main/java/org/robovm/objc/ObjCClass.java index fd3009c02..4d3b066f9 100755 --- a/compiler/objc/src/main/java/org/robovm/objc/ObjCClass.java +++ b/compiler/objc/src/main/java/org/robovm/objc/ObjCClass.java @@ -248,8 +248,12 @@ public static ObjCClass getFromObject(ObjCObject id) { } return getByType(id.getClass()); } - + public static ObjCClass getFromObject(long handle) { + return getFromObject(handle, false); + } + + public static ObjCClass getFromObject(long handle, boolean optional) { long classPtr = ObjCRuntime.object_getClass(handle); // dkimitsa. There is a bug observed in iOS12 that causes not all Objective-C class fields properly initialized // in Class instance of Swift classes. This causes a crash in APIs like class_copyProtocolList to crash @@ -260,7 +264,7 @@ public static ObjCClass getFromObject(long handle) { if (classPtr != 0 && ObjCRuntime.class_respondsToSelector(classPtr, SELECTOR_NSOBJECT_CLASS.getHandle())) { classPtr = ObjCRuntime.ptr_objc_msgSend(handle, SELECTOR_NSOBJECT_CLASS.getHandle()); } - return toObjCClass(classPtr); + return toObjCClass(classPtr, optional); } public static ObjCClass getByType(Class type) { @@ -328,6 +332,10 @@ private static List getProtocols(long handle, boolean isProtocol) { } public static ObjCClass toObjCClass(final long handle) { + return toObjCClass(handle, false); + } + + public static ObjCClass toObjCClass(final long handle, final boolean optional) { long classPtr = handle; ObjCClass c = ObjCObject.getPeerObject(classPtr); if (c == null) { @@ -358,7 +366,7 @@ public static ObjCClass toObjCClass(final long handle) { } } } - if (c == null) { + if (c == null && !optional) { String name = VM.newStringUTF(ObjCRuntime.class_getName(handle)); throw new ObjCClassNotFoundException("Could not find Java class corresponding to Objective-C class: " + name); } diff --git a/compiler/objc/src/main/java/org/robovm/objc/ObjCObject.java b/compiler/objc/src/main/java/org/robovm/objc/ObjCObject.java index 082e33cb8..215263129 100755 --- a/compiler/objc/src/main/java/org/robovm/objc/ObjCObject.java +++ b/compiler/objc/src/main/java/org/robovm/objc/ObjCObject.java @@ -328,8 +328,16 @@ public static T toObjCObject(Class cls, long handle, i } } - ObjCClass objCClass = ObjCClass.getFromObject(handle); - if (!expectedType.isAssignableFrom(objCClass.getType())) { + // dkimitsa: when ObjCProxy is a target at java level it expected to return Interface/Protocol implementation + // But not always is possible to recognizable ObjC object implementing the protocol behind the handle. + // For example in case protocol is implemented by pure Swift object. + // In this cause case ObjCClass might not be resolved (cause ObjCClassNotFoundException) + // or not resolve to one that implement the protocol (not isAssignableFrom). + // To workaround -- allow getFromObject to be optional and return Null. + // in this case objCClass will be resolved using getByType() from provided $ObjCProxy + // it's the case when proper ObjC object that implement the protocol can't be identified + ObjCClass objCClass = ObjCClass.getFromObject(handle, expectedType != cls); + if (objCClass == null || !expectedType.isAssignableFrom(objCClass.getType())) { /* * If the expected return type is incompatible with the type of * the native instance we have to make sure we return an