我目前正在为 Capcitor 应用程序开发一个本机插件。我对原生 iOS 开发、Swift 和 Obj-C 的经验很少。
我使用一个用C++编写的框架(FunSDK)。 我在 Objective-C++ 包装器中调用它。 如此处所述:https://medium.com/@cecilia.humlelu/set-up-c-library-dependency-in-swift-projects-5dc2ccd2ddaf
然后可以通过桥接头在 Swift 中使用包装器。 到目前为止,这是有效的,我可以从框架调用这些函数,并且它们可以正确执行。 然而,框架的功能是异步执行的。当获得结果时,始终会执行“OnFunSDKResult”方法。
在此步骤中,我在调试时收到 EXC_BAD_ACCESS 错误。然后我在诊断设置下勾选了“僵尸对象”。这会导致执行因 EXC_BREAKPOINT 停止。
据我了解,执行iniXMSDK方法后,FunSDKWrapper类会在执行“OnFunSDKResult”方法之前从内存中清除?
我还已经集成了一个completionHandler,它仅在“OnFunSDKResult”方法中调用,以便将数据传输到Swift类。然而,这也没有帮助。
我不知道如何继续。 我希望有人能帮助我。
如果您需要更多信息,我很乐意提供。
FunSDKWrapper.mm
//
// FunSDKWrapper.m
// App
//
// Created by Sysprobs on 12/8/23.
//
#import "FunSDKWrapper.h"
#import "FunSDK/FunSDK.h"
#import <XMNetInterface/Reachability.h>
@implementation FunSDKWrapper
-(NSString *)iniXMSDK:(int)test completion:(void (^)(int result))completionHandler{
self.initCompletionHandler = completionHandler;
self.msgHandle = FUN_RegWnd((__bridge void *)self);
FUN_Init();
Fun_LogInit(self.msgHandle, "", 0, "", LOG_UI_MSG);
FUN_XMCloundPlatformInit("xxx", "xxx", "xxx", 1);
FUN_InitNetSDK();
FUN_SetFunStrAttr(EFUN_ATTR_SAVE_LOGIN_USER_INFO,SZSTR([self GetDocumentPathWith:@"UserInfo.db"]));
FUN_SetFunStrAttr(EFUN_ATTR_USER_PWD_DB, SZSTR([self GetDocumentPathWith:@"password.txt"]));
FUN_SetFunStrAttr(EFUN_ATTR_UPDATE_FILE_PATH,SZSTR([self GetDocumentPathWith:@""]));
FUN_SetFunStrAttr(EFUN_ATTR_TEMP_FILES_PATH,SZSTR([self GetDocumentPathWith:@""]));
FUN_SetFunIntAttr(EFUN_ATTR_AUTO_DL_UPGRADE, 0);
FUN_SetFunStrAttr(EFUN_ATTR_CONFIG_PATH,SZSTR([self GetDocumentPathWith:@"APPConfigs"]));
FUN_SetFunIntAttr(EFUN_ATTR_SUP_RPS_VIDEO_DEFAULT, 1);
FUN_SetFunIntAttr(EFUN_ATTR_SET_NET_TYPE, [self getNetworkType]);
FUN_SysInit("arsp.xmeye.net;arsp1.xmeye.net;arsp2.xmeye.net", 15010);
FUN_InitNetSDK();
FUN_SysGetDevList(self.msgHandle, SZSTR(@"xxxx") , SZSTR(@"xxxx"),0);
return @"test";
}
- (void)searchLanDevices {
FUN_DevSearchDevice(self.msgHandle, 4000, 0);
}
// NSDocument/fileName
- (NSString *)GetDocumentPathWith:(NSString *) fileName {
NSString* path = [self documentsPath];
if (fileName != nil) {
path = [path stringByAppendingString:@"/"];
path = [path stringByAppendingString:fileName];
}
return path;
}
//NSDocument
- (NSString *)documentsPath {
NSArray *pathArray = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *path = [pathArray lastObject];
return path;
}
-(int)getNetworkType {
Reachability*reach=[Reachability reachabilityWithHostName:@"www.apple.com"];
//判断当前的网络状态
switch([reach currentReachabilityStatus]){
case ReachableViaWiFi:
return 1;
case ReachableViaWWAN:
return 2;
default:
return 0;
break;
}
}
- (void)OnFunSDKResult:(NSNumber *) pParam {
NSInteger nAddr = [pParam integerValue];
MsgContent *msg = (MsgContent *)nAddr;
switch (msg->id) {
case EMSG_SYS_GET_DEV_INFO_BY_USER:{
self.initCompletionHandler(1);
if (msg->param1 < 0){
//fehler
NSLog(@"Fehler beim XMCloud login");
}else{
char devJson[750*500];
FUN_GetFunStrAttr(EFUN_ATTR_GET_USER_ACCOUNT_DATA_INFO, devJson, 750*500);
NSLog(@"Geraeteliste: = %s",devJson);
}
}
break;
}
}
@end
Swift 类
import Foundation
import Capacitor
/**
* Please read the Capacitor iOS Plugin Development Guide
* here: https://capacitorjs.com/docs/plugins/ios
*/
@objc(xmsdkPlugin)
public class xmsdkPlugin: CAPPlugin {
private let implementation = xmsdk()
@objc func echo(_ call: CAPPluginCall) {
let value = call.getString("value") ?? ""
call.resolve([
"value": implementation.echo(value)
])
}
@objc func initXMSDK(_ call: CAPPluginCall) {
//let devId = call.getString("devId") ?? ""
let wrapper = FunSDKWrapper();
let resp = wrapper.iniXMSDK(1, completion: {(result) -> Void in
NSLog("Completion von iniXMSDK")
});
call.resolve([
"status": resp
])
}
}
带有 EXC_BREAKPOINT 的错误日志:
App`invocation function for block in UI_SendMsg(int, XMSG*):
0x102bed8f4 <+0>: sub sp, sp, #0x70
0x102bed8f8 <+4>: stp x22, x21, [sp, #0x40]
0x102bed8fc <+8>: stp x20, x19, [sp, #0x50]
0x102bed900 <+12>: stp x29, x30, [sp, #0x60]
0x102bed904 <+16>: add x29, sp, #0x60
0x102bed908 <+20>: mov x19, x0
0x102bed90c <+24>: ldr x8, [x0, #0x20]
0x102bed910 <+28>: ldr w9, [x8, #0x18]
0x102bed914 <+32>: str w9, [sp, #0x8]
0x102bed918 <+36>: ldr q0, [x8, #0x20]
0x102bed91c <+40>: stur q0, [sp, #0xc]
0x102bed920 <+44>: ldr x9, [x8, #0x38]
0x102bed924 <+48>: ldr x10, [x8, #0x50]
0x102bed928 <+52>: stp x10, x9, [sp, #0x20]
0x102bed92c <+56>: ldr w9, [x8, #0x30]
0x102bed930 <+60>: str w9, [sp, #0x34]
0x102bed934 <+64>: str x8, [sp, #0x38]
0x102bed938 <+68>: adrp x0, 6283
0x102bed93c <+72>: add x0, x0, #0x60 ; g_wndIndexLock
0x102bed940 <+76>: bl 0x102bdd34c ; XBASIC::CLock::Lock at Lock.cpp:58:29
0x102bed944 <+80>: adrp x8, 6283
0x102bed948 <+84>: ldr x10, [x8, #0x38]
0x102bed94c <+88>: cbz x10, 0x102bed98c ; <+152> at UIInterface.mm:130:24
0x102bed950 <+92>: ldr w9, [x19, #0x28]
0x102bed954 <+96>: adrp x11, 6283
0x102bed958 <+100>: add x11, x11, #0x38 ; g_id_wnd + 8
0x102bed95c <+104>: mov x8, x11
0x102bed960 <+108>: ldr w12, [x10, #0x20]
0x102bed964 <+112>: cmp w12, w9
0x102bed968 <+116>: cset w12, lt
0x102bed96c <+120>: csel x8, x8, x10, lt
0x102bed970 <+124>: ldr x10, [x10, w12, uxtw #3]
0x102bed974 <+128>: cbnz x10, 0x102bed960 ; <+108> [inlined] std::__1::less<int>::operator()(int const&, int const&) const at operations.h:487:17
0x102bed978 <+132>: cmp x8, x11
0x102bed97c <+136>: b.eq 0x102bed98c ; <+152> at UIInterface.mm:130:24
0x102bed980 <+140>: ldr w10, [x8, #0x20]
0x102bed984 <+144>: cmp w9, w10
0x102bed988 <+148>: b.ge 0x102bed9dc ; <+232> at UIInterface.mm:126:21
0x102bed98c <+152>: adrp x0, 6283
0x102bed990 <+156>: add x0, x0, #0x60 ; g_wndIndexLock
0x102bed994 <+160>: bl 0x102bdd354 ; XBASIC::CLock::Unlock at Lock.cpp:63:31
0x102bed998 <+164>: adrp x0, 4324
0x102bed99c <+168>: add x0, x0, #0xb00 ; @"NO MSG Object....."
0x102bed9a0 <+172>: bl 0x1038af9a0 ; symbol stub for: NSLog
0x102bed9a4 <+176>: ldr x0, [x19, #0x20]
0x102bed9a8 <+180>: ldr x9, [x0, #0x8]
0x102bed9ac <+184>: ldaxr x8, [x9]
0x102bed9b0 <+188>: sub x10, x8, #0x1
0x102bed9b4 <+192>: stlxr w11, x10, [x9]
0x102bed9b8 <+196>: cbnz w11, 0x102bed9ac ; <+184> [inlined] InterlockedDecrement(long*) at OS.h:120:9
0x102bed9bc <+200>: sub w8, w8, #0x1
0x102bed9c0 <+204>: cmp w8, #0x0
0x102bed9c4 <+208>: b.gt 0x102beda24 ; <+304> at UIInterface.mm:143:5
0x102bed9c8 <+212>: tbnz w8, #0x1f, 0x102beda18 ; <+292> [inlined] XBASIC::IReferable::Release() at Referable.h:95:17
0x102bed9cc <+216>: ldr x8, [x0]
0x102bed9d0 <+220>: ldr x8, [x8, #0x8]
0x102bed9d4 <+224>: blr x8
0x102bed9d8 <+228>: b 0x102beda24 ; <+304> at UIInterface.mm:143:5
0x102bed9dc <+232>: ldp x20, x21, [x8, #0x28]
0x102bed9e0 <+236>: adrp x0, 6283
0x102bed9e4 <+240>: add x0, x0, #0x60 ; g_wndIndexLock
0x102bed9e8 <+244>: bl 0x102bdd354 ; XBASIC::CLock::Unlock at Lock.cpp:63:31
0x102bed9ec <+248>: cbz x20, 0x102bed998 ; <+164> at UIInterface.mm:139:13
0x102bed9f0 <+252>: adrp x8, 4330
0x102bed9f4 <+256>: ldr x0, [x8, #0x5e8]
0x102bed9f8 <+260>: add x2, sp, #0x8
0x102bed9fc <+264>: bl 0x1038b5a00 ; objc_msgSend$numberWithUnsignedInteger:
0x102beda00 <+268>: mov x3, x0
0x102beda04 <+272>: mov x0, x20
0x102beda08 <+276>: mov x2, x21
0x102beda0c <+280>: mov w4, #0x1
0x102beda10 <+284>: bl 0x1038b5aa0 ; objc_msgSend$performSelectorOnMainThread:withObject:waitUntilDone:
-> 0x102beda14 <+288>: b 0x102bed9a4 ; <+176> at UIInterface.mm:142:9
0x102beda18 <+292>: adrp x0, 3297
0x102beda1c <+296>: add x0, x0, #0xd93 ; "Check Please Error(IReferable)!"
0x102beda20 <+300>: bl 0x1038b2364 ; symbol stub for: puts
0x102beda24 <+304>: ldp x29, x30, [sp, #0x60]
0x102beda28 <+308>: ldp x20, x19, [sp, #0x50]
0x102beda2c <+312>: ldp x22, x21, [sp, #0x40]
0x102beda30 <+316>: add sp, sp, #0x70
0x102beda34 <+320>: ret
评论后更新:
提前感谢您提供信息。
不幸的是,FunSDK 的文档并不是很好。 这是文档:https://developer.jftech.com/docs/?menusId=8af0e7f3d4af49eab71cfdd8d7e47cef&siderid=6caa41621abd4e689b21a3c0339e8cd6&lang=en
这是一个演示应用程序,其中使用了框架的所有功能:https://gitlab.xmcloud.io/demo/FunSDKDemo_iOS
文档没有具体描述如何调用“OnFunSDKResult”方法。 在 DemoApp 中的某个时刻,只有这样一条注释:“所有带有回调信息的 FUN 接口都会回调到这个方法中。”
EXC_BAD_ACCESS错误也仅在我实现“OnFunSDKResult”方法时发生。所以我假设框架以某种方式通过“UI_SendMsg”将数据返回到“OnFunSDKResult”方法。
我现在基本明白ARC发布了包装器。从内存管理教程中我仍然没有弄清楚如何在我的情况下改变它。
有人可以给我一个代码示例,说明如何确保 ARC 仅在特定时间释放包装器吗? 我还了解到我可以显式禁用各个类的 ARC 并自己接管内存管理。这是一个选项,以便我只能在“OnFunSDKResult”中再次手动释放内存吗?
我现在能够通过从 FunSDKWrapper 和 CompletionHandler 创建强引用来解决问题。
var funSDKWrapper: FunSDKWrapper?
@objc func initXMSDK(_ call: CAPPluginCall) {
let wrapper = FunSDKWrapper();
self.funSDKWrapper = wrapper;
let strongCompletionHandler: (([AnyHashable: Any]) -> Void) = { result in
NSLog("Completion von iniXMSDK");
}
let resp = wrapper.iniXMSDK(1, completion: strongCompletionHandler);
call.resolve([
"status": resp
])
}