MSSticker error - nil object

Hello and thank you for your assistance!

The error I am receiving:

<MSSticker imageFileURL file:///Users/username/Library/Developer/CoreSimulator/Devices/XXXX-XXXX-XXXX-XXXX/data/Containers/Data/PluginKitPlugin/XXXX-XXXX-XXXX-XXXX/Documents/CFNetworkDownload_41Nhn1.gif localizedDescription sticker>, exception: *** -[__NSPlaceholderArray initWithObjects:count:]: attempt to insert nil object from objects[0]

The error itself is descriptive - for some reason, a nil object is being used inside the MSSticker object. I have received this error both on device (iOS10 / July 18th build, and simulator, XCode July 18th build).

When I attempt to set a MSSticker in my custom UICollectionViewCell, I get this nil object error message. I've done this successfully in the past (using the same sticker code inside my custom UICollectionViewCell object), and have even verified with NSFileManager that the file exists via fileExistsAtPath. I realize using fileExistsAtPath is not without flaws, and Apple recommends simply trying to do something with the file instead of trying to see if it exists, so I also do that. I suspected that this might be a caching issue, so I've tried using the cache to store either fileURLs and then I tried to store actual MSSticker objects. Neither approach rectifies the below error message.

Side note but probably not relevant: I am using a custom UICollectionViewLayout, but stepping through the code shows that it appears to be working fine, though obviously nothing displays on screen due to the below error.


@interface BrowserViewController ()

@property (nonatomic, strong) NSCache *cache;

@end


@implementation BrowserViewController

// ...

- (void)loadView {

self.cache = [[NSCache alloc] init];

}


- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {

CustomCollectionViewCell *cell = // ...

__weak MyBrowserViewController *welf = self;

ImageInfo *imageInfo = // ... retrieve from array

[self getStickerForStickerInfo:imageInfo withCompletion:^(BOOL succeeded){


NSError *stickerCreationError = nil;

NSURL *fileURL = (NSURL *)[welf.cache objectForKey:imageInfo.imageUrl];

MSSticker *newSticker = [[MSSticker alloc] initWithContentsOfFileURL:fileURL localizedDescription:@"sticker" error:&stickerCreationError];

if (!stickerCreationError) {

[cell setSticker:newSticker];

}

}];

- (void)getStickerForStickerInfo:(ImageInfo *)imageInfo withCompletion:(void (^)(BOOL succeeded))completion {


if (imageInfo.thumbnailImageUrl) {

// ...

__weak MyBrowserViewController *welf = self;

NSURL *url = [NSURL URLWithString:imageInfo.imageUrl];

NSURLSessionDownloadTask *downloadTask = // ...


// ...completion handler


if (location != nil && !error) {

// ... Code to move from /tmp location to filesystem NSCachesDirectory directory...

// ... Same issue occurs when using NSDocumentDirectory as well ...

// I have verified that we are using paths when calling moveItemAtPath:toPath:error:

// eg: /Users/username/Library/Developer/CoreSimulator/Devices/***-***-***-***-XXXXXXXX/data/Containers/Data/PluginKitPlugin/***-***-***-***-XXXX/Documents/CFNetworkDownload_2w1r55.gif


if (![fileManager moveItemAtPath:[location path] toPath:newPath error:&error]) {

NSLog(@"Failed to move '%@' to '%@': %@", location, newPath, [error localizedDescription]);

}

BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:newPath];

// Returns 'file exists' every time

(fileExists) ? NSLog(@"file exists") : NSLog(@"file does not exist");


NSURL *fileURL = [NSURL fileURLWithPath:newPath];

if (fileURL) {

[welf.cache setObject:fileURL forKey:imageInfo.imageUrl];

if (completion) {

completion(YES);

}

}

} else {

//...

}

}];

[downloadTask resume];

}

}

@end


// In my Custom UICollectionViewCell


@interface CustomCollectionViewCell ()

@property (nonatomic, strong) MSStickerView *stickerView;

@end


@implementation CustomCollectionViewCell


- (instancetype) initWithFrame:(CGRect)frame {

// ...

self.stickerView = [[MSStickerView alloc] initWithFrame:CGRectZero sticker:nil];

[self addSubview:self.stickerView];

// ...

}


- (void) prepareForReuse {

[super prepareForReuse];


[self setSticker:nil];

[self.stickerView setSticker:nil];

}


- (void)setSticker:(MSSticker *)sticker {

_sticker = sticker;


BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:[sticker.imageFileURL path]];


if (fileExists) {

@try {


/* The below always fails with the error:

2016-07-21 13:13:05.825 MessagesExtension[24830:1605053] Set sticker error: <MSSticker imageFileURL file:///Users/username/Library/Developer/CoreSimulator/Devices/XXXX-XXXX-XXXX-XXXX/data/Containers/Data/PluginKitPlugin/XXXX-XXXX-XXXX-XXXX/Documents/CFNetworkDownload_41Nhn1.gif localizedDescription sticker>, exception: *** -[__NSPlaceholderArray initWithObjects:count:]: attempt to insert nil object from objects[0]

*/

[self.stickerView setSticker:self.sticker];


} @catch (NSException *exception) {

[self.stickerView setSticker:nil];

NSLog(@"Set sticker error: %@, exception: %@", self.sticker, exception);

} @finally {

// https://developer.apple.com/reference/messages/msstickerview/1648434-sticker?language=objc

[self.stickerView sizeToFit];

}

}

}

Accepted Reply

Ok, I've made some progress --


It seems like the width component of the MSStickerView frame was 0, while the height was > 0, and the framework didn't like me trying to set the MSSticker property of the MSStickerView with a width == 0. The given error message is misleading though.


In my initWithFrame method of my custom UICollectionViewCell, I use the Cell frame size when initializing the MSStickerView:


- (instancetype) initWithFrame:(CGRect)frame {


if (self = [super initWithFrame:frame]) {

self.stickerView = [[MSStickerView alloc] initWithFrame:frame sticker:nil];

[self addSubview:self.stickerView];

}

return self;

}

Replies

Ok, I've made some progress --


It seems like the width component of the MSStickerView frame was 0, while the height was > 0, and the framework didn't like me trying to set the MSSticker property of the MSStickerView with a width == 0. The given error message is misleading though.


In my initWithFrame method of my custom UICollectionViewCell, I use the Cell frame size when initializing the MSStickerView:


- (instancetype) initWithFrame:(CGRect)frame {


if (self = [super initWithFrame:frame]) {

self.stickerView = [[MSStickerView alloc] initWithFrame:frame sticker:nil];

[self addSubview:self.stickerView];

}

return self;

}

Hey ! Thank you for sharing!

I've got the exact same issue. If I load only one sticker in my collectionview it will work, but as soon as I try with more I have the exact same error as you.

Also if I use non animated sticker it works fine, but if I use apng it doesnt work anymore, even with your fix :/