Nicholas Muir Nicholas Muir - 3 months ago 21
Objective-C Question

Wait for result from objective C function before continuing in Swift

I have a swift app. The main class viewdidload calls an objective-c function.

The objective-c function scans a database and then puts that into a NSMutableArray.

I need to use the the NSMutable array in the swift function.

The problem is this: I call the objective-c function in swift and then use the array but it goes to use the array before it has been filled (nil).

So I need swift to wait for a successful return value from the objective-c function before sing the array.

I have seen multiple examples but not from one language to another. Some people are saying use completion handler other say that is not the best way. Then others said notification.

I am new to IOS so your help is appreciated.

EDITED ADDED CODE

scanTable function (Objective C):

#import "ScanTable.h"
#import "Mapper.h"

@implementation ScanTable

- (void) scanTableDo {
AWSDynamoDBObjectMapper *dynamoDBObjectMapper = [AWSDynamoDBObjectMapper defaultDynamoDBObjectMapper];
AWSDynamoDBScanExpression *scanExpression = [AWSDynamoDBScanExpression new];
scanExpression.limit = @10;

[[dynamoDBObjectMapper scan:[Mapper class]
expression:scanExpression]
continueWithBlock:
^id(AWSTask *task) {
if (task.error) {
NSLog(@"The request failed. Error: [%@]", task.error);
}
if (task.exception) {
NSLog(@"The request failed. Exception: [%@]", task.exception);
}
if (task.result) {
AWSDynamoDBPaginatedOutput *paginatedOutput = task.result;
NSMutableArray *scanResult = [[NSMutableArray alloc] initWithArray:paginatedOutput.items]; //// ADDED /////
}
return nil;
}];
}
@end


Main function (Swift):

override func viewDidLoad() {
super.viewDidLoad()

let scanTable = ScanTable();
scanTable.scanTableDo();

let swiftArray = scanTable.scanResult
}

Answer

The issue is that this is an asynchronous function and you are trying to access the result in a synchronous way. You need the objective c function to use a block so that you can access it when it's finished:

- (void)scanTableDoWithBlock:(void(^)(NSArray *scanResult, NSError *error))handler {

    AWSDynamoDBObjectMapper *dynamoDBObjectMapper = [AWSDynamoDBObjectMapper defaultDynamoDBObjectMapper];
    AWSDynamoDBScanExpression *scanExpression = [AWSDynamoDBScanExpression new];
    scanExpression.limit = @10;


    [[dynamoDBObjectMapper scan:[Mapper class]
                     expression:scanExpression]
     continueWithBlock:^id(AWSTask *task) {
         if (task.error) {
             NSLog(@"The request failed. Error: [%@]", task.error);
             if (handler != nil) {
                 handler(nil, task.error);
             }
         }
         if (task.exception) {
             NSLog(@"The request failed. Exception: [%@]", task.exception);
         }
         if (task.result) {
             AWSDynamoDBPaginatedOutput *paginatedOutput = task.result;
             NSMutableArray *scanResult = [[NSMutableArray alloc] initWithArray:paginatedOutput.items];  //// ADDED /////

             if (handler != nil) {
                 handler([scanResult copy], nil);
             }
         } 

         return nil;
     }];    
}

Make sure that you change the method declaration in the .h file from:

- (void)scanTableDo;

to:

- (void)scanTableDoWithBlock:(void(^)(NSArray *scanResult, NSError *error))handler;
Comments