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];
}
}
}