在 Swift 中调用 Obj-C 时的内存管理问题

问题描述 投票:0回答:1

我目前正在为 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    

Image with Error Message

评论后更新:

提前感谢您提供信息。

不幸的是,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”中再次手动释放内存吗?

ios swift objective-c automatic-ref-counting objective-c++
1个回答
0
投票

我现在能够通过从 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
    ])

}
© www.soinside.com 2019 - 2024. All rights reserved.