【问题标题】:How to call two React Native native module methods at the same time?如何同时调用两个 React Native 原生模块方法?
【发布时间】:2022-12-12 07:07:11
【问题描述】:

好的,这有点复杂。我无法链接我的所有代码,因为它很大,但我会尽力在其中提供一些有代表性的伪代码。

我有一个 ios React Native 项目,在 xcode 中,我在我的项目中嵌入了一个自定义目标 C 框架。为了访问目标 C 框架,我创建了一个充当包装器/桥接器的本机模块。

到目前为止,这一切都很好——基本上我的用户点击了一个按钮,它通过一个本机模块触发了 objective c 框架,objective c 框架需要大约 30 秒到一分钟来完成处理用户选择的数据,然后吐出已处理文件的 uri。

我遇到的问题是我的用户对我的应用程序是否被冻结感到困惑。碰巧我的框架的主要功能使用 for 循环,所以我决定向框架的主类添加两个属性并添加一个返回属性的函数,以便我们可以看到进度。它看起来像这样:


@implementation MyFramework {

   int currentBlock;
   int allBlocks;

}

- (NSArray<NSString*>*)processFile:(NSString *)file
{
    int totalBlocks = examineFile(file);
    for( int iBlock= 0; iBlock<totalBlocks; iBlock++) {
        currentBlock = iBlock;

        //other code that actually does stuff to the file goes here

    }

    //code that stitches the blocks together and generates files goes here

    NSArray* files = @[filePath1, filePath2, filepath3];
    return files;
}

- (NSArray<NSString*>*)getProgress:(NSString *)msg
{
    int* pCurrentBlock = &currentBlock;
    int* pAllBlocks = &allBlocks;
    
    NSString* currentBlockString = [NSString stringWithFormat:@"%d", *pCurrentBlock];
    NSString* allBlocksString = [NSString stringWithFormat:@"%d", *pAllBlocks];
    
    NSArray* progressArray = @[currentBlockString, allBlocksString];
    return progressArray;
}

回到 Javascript 中,我为上面的代码调用了一个 Native Module wrapper。因此,当用户单击一个按钮时,我会触发一个名为 getFiles() 的本机模块方法,该方法又会调用上面 Objective C 代码中的 processFile() 方法。

现在,当 processFile() 方法运行时,我每 2 秒同时启动一个 setInterval() 调用第二个名为 status() 的本机模块方法,该方法调用上面显示的 getProgress() 函数。我遇到的大问题是 getProgress() 在 processFile() 运行时不会返回结果。相反,它会等到 processFile() 方法完成,然后一次返回大约 20 个结果。

所以不要像这样获取更新:

['1','37']
['2','37']
['3','37']
['4','37']
['5','37']

最后我得到了这样的东西

['36','37']
['36','37']
['36','37']
['36','37']
['36','37']

这是我的本机模块代码

const MyFramework *myLocalFramework = [[MyFramework alloc]init];

RCT_EXPORT_MODULE();

RCT_EXPORT_METHOD(getFiles:(NSString *)path
                 resolver:(RCTPromiseResolveBlock)resolve
                 rejecter:(RCTPromiseRejectBlock)reject)
{
    NSString *modelFilePath = [[NSBundle mainBundle] pathForResource:@"converted_model_float16" ofType:@"tflite"];

    NSArray * files = [myLocalFramework localFile:path tfModel:modelFilePath];
    if (files) {
        resolve(files);
    } else {
        reject(@"event_failure", @"no event id returned", nil);
    }
}

RCT_EXPORT_METHOD(status:(NSString *)path 
                 resolver:(RCTPromiseResolveBlock)resolve 
                 rejecter:(RCTPromiseRejectBlock)reject)
{
    NSString* hi = @"hi";

    NSArray* percentages = [myLocalFramework getProgress:hi];

    if (percentages) {
        resolve(percentages);
    } else {
        reject(@"event_failure", @"no event id returned", nil);
    }
}

因此,综上所述,如果有人对我如何让本机模块运行 status() 方法而不等待 getFiles() 首先完成有任何想法,我会喜欢你的意见!

【问题讨论】:

  • 可以选择事件侦听器,而不是添加用于获取进度状态的本机模块。

标签: objective-c react-native


【解决方案1】:
It sounds like you want to update the progress of your for-loop in the Objective-C code so that it can be displayed in the React Native app. There are a few ways you could go about this, but one possible solution would be to use an NSTimer to periodically check the progress of your for-loop and update a property that can be accessed from the React Native side of your app. Here's an example of how this could work:

First, add a property to your Objective-C class that can be used to store the progress of your for-loop. For example:

@interface MyFramework : NSObject

@property (nonatomic, assign) float progress;

@end

Next, create an NSTimer that will be used to update the progress property of your class at regular intervals. You can do this in your init method, like this:
```
(instancetype)init
{
self = [super init];
if (self) {
self.progress = 0.0;

    enter code here

  // Create and start the NSTimer
  NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:0.5
                                                    target:self
                                                  selector:@selector(updateProgress)
                                                  userInfo:nil
                                                   repeats:YES];
  [timer fire];

}
return self;
}
```
Then, implement the updateProgress method that will be called by the timer. This method should update the progress property based on the current state of your for-loop. For example:

(void)updateProgress
{
if (self.currentBlock > 0 && self.allBlocks > 0) {
// Calculate the progress as a percentage
self.progress = (float)self.currentBlock / (float)self.allBlocks * 100.0;
}
}
Now, in your React Native code, you can use the status method in your Native Module to check the progress property of your Objective-C class and update the progress in your app accordingly. Here's an example of how this could work:

// Import the Native Module
const MyFrameworkModule = NativeModules.MyFrameworkModule;

// Create a function that will be called by the setInterval
function checkProgress() {
// Call the status method in your Native Module
MyFrameworkModule.status((percentages) => {
// Use the progress to update the UI of your app
console.log(percentages);
});
}

// Start the setInterval
setInterval(checkProgress, 2000);

This is just one possible solution to your problem, but hopefully it gives you an idea of how you can use an NSTimer to update the progress of your for-loop in your Objective-C code so that it can be displayed in your React Native app.

【讨论】:

    猜你喜欢
    • 2022-11-11
    • 1970-01-01
    • 1970-01-01
    • 2020-02-13
    • 2019-02-25
    • 1970-01-01
    • 1970-01-01
    • 2018-02-23
    • 2015-06-15
    相关资源
    最近更新 更多