Home > Back-end >  add item to NSMutableArray inside a thread
add item to NSMutableArray inside a thread

Time:09-16

I want to scan the Photo library with threads, when my app logic is ok I want to add the PHAsset to finalarray:

NSMutableArray <PHAsset *> *finalarray = [[NSMutableArray alloc] init];

for (NSMutableArray *photoArray in arrayOfArrays) {
    dispatch_group_enter(aGroup);
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
        for (PHAsset *asset in photoArray) {
            [[PHImageManager defaultManager] requestImageDataForAsset:asset
                                                              options:options
                                                        resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {

                //Make some logic

                if (logic) {
                    [finalarray addObject:asset];
                }
            }];
        }
        dispatch_group_leave(aGroup);
    });
}

arrayOfArrays is array of array of PHAsset.

My code works fine, but sometimes I get a SIGABRT crash and I get this log in code console:

malloc: Incorrect checksum for freed object 0x1206d5968: probably modified after being freed.
Corrupt value: 0x100017580
malloc: *** set a breakpoint in malloc_error_break to debug
malloc: Incorrect checksum for freed object 0x1206d5968: probably modified after being freed.
Corrupt value: 0x100017580

CodePudding user response:

If you have multiple threads updating a property, you must synchronize their access. You can use a NSLock:

NSMutableArray <PHAsset *> *finalarray = [[NSMutableArray alloc] init];
NSLock *lock = [[NSLock alloc] init];

for (NSMutableArray *photoArray in arrayOfArrays) {
    dispatch_group_enter(aGroup);
    for (PHAsset *asset in photoArray) {
        [[PHImageManager defaultManager] requestImageDataForAsset:asset
                                                          options:options
                                                    resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {

            //Make some logic

            if (logic) {
                [lock lock];
                [finalarray addObject:asset];
                [lock unlock];
                dispatch_group_leave(aGroup);
            }
        }];
    }
}

Or you can use a GCD queue:

NSMutableArray <PHAsset *> *finalarray = [[NSMutableArray alloc] init];
dispatch_queue_t queue = dispatch_queue_create("...", NULL);

for (NSMutableArray *photoArray in arrayOfArrays) {
    dispatch_group_enter(aGroup);
    for (PHAsset *asset in photoArray) {
        [[PHImageManager defaultManager] requestImageDataForAsset:asset
                                                          options:options
                                                    resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {

            //Make some logic

            if (logic) {
                dispatch_async(queue, ^{
                    [finalarray addObject:asset];
                    dispatch_group_leave(aGroup);
                });
            }
        }];
    }
}

Note, above I assume you are fetching your images asynchronously, in which case your use of the global queue is unnecessary, but you need to make sure to call dispatch_group_leave inside the requestImageDataForAsset.

But, regardless, make sure you synchronize your access (either with GCD queue or some lock) when accessing properties from multiple threads.

CodePudding user response:

Try synchronizing your code with a mutex:

#import <pthread.h>

...
NSMutableArray <PHAsset *> *finalarray = [[NSMutableArray alloc] init];
pthread_mutex_t mutex;
pthread_mutex_init(&mutex, NULL);

for (NSMutableArray *photoArray in arrayOfArrays) {
    dispatch_group_enter(aGroup);
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
        for (PHAsset *asset in photoArray) {
            [[PHImageManager defaultManager] requestImageDataForAsset:asset
                                                              options:options
                                                        resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {

                //Make some logic

                if (logic) {
                    pthread_mutex_lock(&mutex);
                    [finalarray addObject:asset];
                    pthread_mutex_unlock(&mutex);
                }
            }];
        }
        dispatch_group_leave(aGroup);
    });
}

In case this didn't help, have you tried setting a breakpoint in malloc_error_break to debug, as your error suggests?

  • Related