Reputation: 174
I have a record type in CloudKit. It stores one string field and one asset field. Using the dashboard I uploaded an image to the asset field.
I can retrieve the string field. I now need to retrieve the contents of the asset field and store it to an image using objective-c. Can anyone help?
I am trying to display the record type in a table view. I have a class called TJKCategoriesViewController that inherits from UIViewController.
I have this code in my viewDidLoad method for the TJKCategoriesViewController class:
// get all categories
_jokeCategories = [[NSMutableArray alloc] init];
CKDatabase *jokePublicDatabase = [[CKContainer containerWithIdentifier:JOKE_CONTAINER] publicCloudDatabase];
NSPredicate *predicateCategory = [NSPredicate predicateWithFormat:@"CategoryName != %@", CATEGORY_TO_REMOVE_OTHER];
CKQuery *queryCategory = [[CKQuery alloc] initWithRecordType:CATEGORY_RECORD_TYPE predicate:predicateCategory];
NSSortDescriptor *sortCategory = [[NSSortDescriptor alloc] initWithKey:CATEGORY_FIELD_NAME ascending:YES];
queryCategory.sortDescriptors = [NSArray arrayWithObjects:sortCategory, nil];
[jokePublicDatabase performQuery:queryCategory inZoneWithID:nil completionHandler:^(NSArray<CKRecord*>* results, NSError * error)
{
if (!error)
{
// add all categories to array
for (CKRecord* jokeCategory in results)
{
TJKCategories *categories = [TJKCategories initWithCategory:[jokeCategory valueForKey:CATEGORY_FIELD_NAME] categoryImage:[jokeCategory valueForKey:@"CategoryImage"]];
[_jokeCategories addObject:categories];
}
NSLog(@"Categories = %@",_jokeCategories);
// setup table
[self setupTableContents];
}
else
{
// display alert message and pop the view controller from the stack
GHSAlerts *alert = [[GHSAlerts alloc] initWithViewController:self];
errorActionBlock errorBlock = ^void(UIAlertAction *action) {[self closeCategories:self];};
[alert displayErrorMessage:@"Oops!" errorMessage:@"The joke categories failed to load. This screen will close. Just try again!" errorAction:errorBlock];
}
}];
This is the method "setupTableContents"
// setup the array that will hold the table's contents
-(void)setupTableContents
{
// store to property and reload the table contents
dispatch_async(dispatch_get_main_queue(), ^{
[self.categoriesTableView reloadData];
});
}
TJKCategories is a class that stores the two fields in the record type. This is the TJKCategories.h file:
#import <UIKit/UIKit.h>
@interface TJKCategories : NSObject
#pragma Properties
@property (nonatomic, copy) UIImage *categoryImage;
@property (nonatomic, copy) NSString *categoryName;
#pragma Initializers
+(instancetype)initWithCategory:(NSString *)categoryName
categoryImage:(UIImage *)categoryImage;
-(instancetype)initWithCategory:(NSString *)categoryName
categoryImage:(UIImage *)categoryImage;
@end
This is the TJKCategories.m file:
// designated initializer
-(instancetype)initWithCategory:(NSString *)categoryName categoryImage:(UIImage *)categoryImage
{
self = [super init];
if (self)
{
self.categoryImage = categoryImage;
self.categoryName = categoryName;
}
return self;
}
// class level initializer
+(instancetype)initWithCategory:(NSString *)categoryName categoryImage:(UIImage *)categoryImage
{
TJKCategories *category = [[self alloc]initWithCategory:categoryName categoryImage:categoryImage];
return category;
}
// override default initializer
-(instancetype)init
{
return [self initWithCategory:@"" categoryImage:nil];
}
In the viewDidLoad method I am using: [jokePublicDatabase performQuery:queryCategory inZoneWithID:nil completionHandler:^(NSArray* results, NSError * error)
To retrieve the results of the record type. I am then looping through the results array, I can retrieve the string "CATEGORY_FOR_NAME" (which is a constant for "CategoryName", but when I try and retrieve the field for the image "CategoryImage" I get and "unrecognized selector sent to instance" error.
If you need to know what the names behind the constants are here is my contacts file:
// declare constants
extern NSString *const DEFAULT_CATEGORY;
extern NSString *const JOKE_CONTAINER;
extern NSString *const CATEGORY_RECORD_TYPE;
extern NSString *const CATEGORY_FIELD_NAME;
extern NSString *const CATEGORY_TO_REMOVE_OTHER;
extern NSString *const CATEGORY_TO_REMOVE_RANDOM;
extern NSString *const JOKE_RECORD_TYPE;
extern NSString *const JOKE_DESCR;
extern NSString *const JOKE_SUBMITTED_BY;
extern NSString *const JOKE_TITLE;
// assign values to constants
NSString *const DEFAULT_CATEGORY = @"None";
NSString *const JOKE_CONTAINER = @"iCloud.com.glennseplowitz.Jokes";
NSString *const CATEGORY_RECORD_TYPE = @"Categories";
NSString *const CATEGORY_FIELD_NAME = @"CategoryName";
NSString *const CATEGORY_TO_REMOVE_OTHER = @"Other";
NSString *const CATEGORY_TO_REMOVE_RANDOM = @"Random";
NSString *const JOKE_RECORD_TYPE = @"Jokes";
NSString *const JOKE_DESCR = @"jokeDescr";
NSString *const JOKE_SUBMITTED_BY = @"jokeSubmittedBy";
NSString *const JOKE_TITLE = @"jokeTitle";
So what I am trying to do is retrieve the asset type "CategoryImage" from the record type and store it to a UIImage. But like I said it gives me the error "unrecognized selector sent to instance" because I believe it cannot convert an asset field to a UIImage field directly.
Thanks, Glenn
Upvotes: 1
Views: 627
Reputation: 174
Figured it out! I changed my TJKCategories class to accept a CKAsset instead of a UIImage. I then converted the CKAsset to a UIImage.
Here is the TJKCategories.h file:
#import <UIKit/UIKit.h>
#import <CloudKit/CloudKit.h>
@interface TJKCategories : NSObject
#pragma Properties
@property (nonatomic, copy) UIImage *categoryImage;
@property (nonatomic, copy) NSString *categoryName;
#pragma Initializers
+(instancetype)initWithCategory:(NSString *)categoryName
categoryImage:(CKAsset *)categoryImageAsset;
-(instancetype)initWithCategory:(NSString *)categoryName
categoryImage:(CKAsset *)categoryImageAsset;
@end
Here is the TJKCategories.m file:
#import "TJKCategories.h"
@interface TJKCategories()
#pragma Properities
@property (nonatomic, strong) CKAsset *categoryImageAsset;
@end
@implementation TJKCategories
#pragma initializers
// designated initializer
-(instancetype)initWithCategory:(NSString *)categoryName categoryImage:(CKAsset *)categoryImageAsset
{
self = [super init];
if (self)
{
self.categoryImageAsset = categoryImageAsset;
self.categoryName = categoryName;
UIImage *image = [[UIImage alloc] initWithContentsOfFile:self.categoryImageAsset.fileURL.path];
self.categoryImage = image;
}
return self;
}
// class level initializer
+(instancetype)initWithCategory:(NSString *)categoryName categoryImage:(CKAsset *)categoryImageAsset
{
TJKCategories *category = [[self alloc]initWithCategory:categoryName categoryImage:categoryImageAsset];
return category;
}
// override default initializer
-(instancetype)init
{
return [self initWithCategory:@"" categoryImage:nil];
}
I also changed the line:
TJKCategories *categories = [TJKCategories initWithCategory:[jokeCategory valueForKey:CATEGORY_FIELD_NAME] categoryImage:[jokeCategory **objectForKey**:@"CategoryImage"]];
to
TJKCategories *categories = [TJKCategories initWithCategory:[jokeCategory valueForKey:CATEGORY_FIELD_NAME] categoryImage:[jokeCategory **valueForKey**:@"CategoryImage"]];
Note that CategoryImage is now using valueForKey and not objectForKey.
Upvotes: 1