UIImage not being displayed when retrived from NSMutableArray - iphone

Help please :)
I have set up a mutable array as follows
- (void)viewDidLoad {
[super viewDidLoad];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"TopImage" inManagedObjectContext:managedObjectContext];
[request setEntity:entity];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"topImage" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[request setSortDescriptors:sortDescriptors];
[sortDescriptor release];
[sortDescriptors release];
NSError *error = nil;
NSMutableArray *mutableFetchResultsT = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
if (mutableFetchResultsT == nil) {
}
[self setTopImageArray:mutableFetchResultsT];}
And im trying to populate a UIImageView using :
- (void)showPhoto:(NSInteger)numberToAdd
{
[topIV setImage:[topImageArray objectAtIndex:currentPI + numberToAdd]];
}
currentPI is an integer marking current image in index and number to add is set here:
- (IBAction)nextTouch
{
[self showPhoto:-1];
}
This will skip to next image (thankyou to #XenElement for this insight).
No images load in UIImageView at all.
MutableArray is getting populated through imagePickerController.
The following is my dedicated Image>Data Data>Image converter class
#implementation Image2Data
+ (BOOL)allowsReverseTransformation {
return YES;
}
+ (Class)transformedValueClass {
return [NSData class];
}
- (id)transformedValue:(id)value {
return UIImagePNGRepresentation(value);
}
- (id)reverseTransformedValue:(id)value {
return [[[UIImage alloc] initWithData:value] autorelease];
}
#end
This is initialized in my managed objects class with:
+ (void)initialize {
if (self == [Images class]) {
Image2Data *transformer = [[Image2Data alloc] init];
[NSValueTransformer setValueTransformer:transformer forName:#"Image2Data"];
}
}
Thank you in advance for any suggestions
DetartrateD
I had originally put:
[topImageArray insertObject:imageS atIndex:0];
corrected to:
[topImageArray insertObject:imageS.topImage atIndex:0];
:)))) big laugh, I was pointing to my entity not its attribute ahh well, lesson learned!

It is unlikely that you are storing the image as a UIImage object. You must be converting it into a NSData object before storing it. You must convert it back to a UIImage object using initWithData: prior to setting it to the UIImageView instance.

Related

How to convert binary data to NSData

I have converted the UIImageview into NSData and stored it as binary data. but i don't know how to retrieve the binary data to NSData and convert that to UIImageview
my code is below
image save as binary data----
-(void) save
{
UIImage *img = [UIImage imageNamed:#"back2.png"];
NSData *dataObj =UIImagePNGRepresentation(img);
NotesDetails *notesDetails = (NotesDetails *) [NSEntityDescription insertNewObjectForEntityForName:#"NotesDetails" inManagedObjectContext:managedObjectContext];
notesDetails.imageData=dataObj;
NSLog(#"NotesDetails: %#",notesDetails);
NSError *error;
if (![managedObjectContext save:&error])
{
}
}
Image Retreive------
-(void)viewDidLoad
{
NSFetchRequest *fectchreq = [[NSFetchRequest alloc] init];
NSEntityDescription *entitydes = [NSEntityDescription entityForName:#"NotesDetails"
inManagedObjectContext:self.managedObjectContext];
[fectchreq setEntity:entitydes];
NSSortDescriptor *sortdes = [[NSSortDescriptor alloc] initWithKey:#"notesTime" ascending:YES];
NSArray *sortdesarray = [[NSArray alloc] initWithObjects:sortdes, nil];
[fectchreq setSortDescriptors:sortdesarray];
NSError *error;
NSMutableArray *storeddata = [[self.managedObjectContext executeFetchRequest:fectchreq error:&error] mutableCopy];
if ([storeddata count] > 0)
{
for (NotesDetails *sc in storeddata)
{
imgFromDb=[NSData dataWithData:[#"%#",sc.imageData]];
}
}
NSLog(#"Image : %#",imgFromDb);
UIImageView *dbImage=[[UIImageView alloc]initWithFrame:CGRectMake(80,20,90,90)];
dbImage.image=[UIImage imageWithData:imgFromDb];
[NoteDetails addSubview:dbImage];
}
You can use NSKeyedUnarchiver:
imgFromDb= [NSKeyedUnarchiver unarchiveObjectWithData: sc.imageData];
And you can do the opposite (object to data) with NSKeyedArchiver if you prefer it vs UIImagePNGRepresentation().
And there are other ways to do this, for example:
imgFromDb= [UIImage imageWithData: sc.imageData];

I cant set an array with a series of images stored in a my core data store ios

This has been bugging me for 2 days now and I cant get my head around it. I want to extract several images that are stored in my core data store. The images are user selected using the image picker and rendered to a size of less then 70KB, transformed to data and popped into the core data store. The images are to be used in a slideshow. Entity is called ImageCD and the image is stored in the attribute friendsPhoto. I also allocate a date attribute to sort the images. This is done when the image is saved and is also an attribute of ImageCD.
I am using the following code to TRY and set the array but it does not return anything. im not getting a (NULL) readout on the debugger just that "Number of elements in array = 0;"
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"date" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:&sortDescriptor count:1];
NSLog(#"array's content sortDe:%#",sortDescriptors);
NSMutableArray* sortedImages = [[NSMutableArray alloc] initWithObjects:imageCD.friendsPhoto, nil];
[sortedImages sortUsingDescriptors:sortDescriptors];
[sortDescriptor release];
[sortDescriptors release];
NSLog(#"array's content:%#",sortedImages);
imageArray = [[NSMutableArray alloc]init] ;
self.imageArray = sortedImages;
NSLog (#"Number of elements in array = %i", [imageArray count]);
self.theImageView.animationImages = [[NSArray alloc] initWithArray:imageArray];
NSLog(#"animationImages:%#",self.theImageView.animationImages);
So, what am I doing wrong? I have my suspicions it is something to do with this line of code...
NSMutableArray* sortedImages = [[NSMutableArray alloc] initWithObjects:imageCD.friendsPhoto, nil];
But cant work out what the alternate should be. I will be forever indebted to whoever can correct my mistake. I thank you in advance and please, let me know if you require any further information, a beer or a bacon sandwich.
Ohh, to save my sanity, I sanity checked the images by adding a class from my previous app (My Outfit) which utilizes this approach to retrieving images from core data BUT within a tableView, so called in cellForRowInIndexPath etc. and all the images are sound.
DetartrateD
2011-08-04 19:40:33.051 My Class Book[1027:707] After managedObjectContext: <NSManagedObjectContext: 0x1821b0>
2011-08-04 19:40:33.057 My Class Book[1027:707] array's content sortDe:(
"(date, ascending, compare:)"
)
2011-08-04 19:40:33.059 My Class Book[1027:707] array's content:(
)
2011-08-04 19:40:33.061 My Class Book[1027:707] Number of elements in array = 0
2011-08-04 19:40:33.063 My Class Book[1027:707] animationImages:(
)
Now fixed with these changes
...
NSMutableArray *mutableFetchResultsA = [[managedObjectContext executeFetchRequest:requestA error:&error] mutableCopy];
if (mutableFetchResultsA == nil) {
NSLog(#"Testing: No results found");
}
else {
NSLog(#"Testing: %d Results found.", [mutableFetchResultsA count]);
NSLog(#"array's content sortDe:%#",mutableFetchResultsA);
}
[sortDescriptor release];
[sortDescriptors release];
imageArray = [[NSMutableArray alloc]init] ;
self.imageArray = [mutableFetchResultsA valueForKey:#"friendsPhoto"];
[mutableFetchResultsA release];
[requestA release];
...
Assuming that the images are stored as NSData * attributes in the ImageCD entity, here is what you need to do:
self.imageArray = [self getImagesInManagedObjectContext:self.managedObjectContext];
Here is the getImagesInManagedObjectContext: method. This method retrieves from the Core Data store the ImageCD objects, sorted using your attribute as required, then creates and returns an autoreleased NSMutableArray of UIImage * objects or nil if no objects have been found.
- (NSMutableArray *) getImagesInManagedObjectContext:(NSManagedObjectContext *)moc{
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"ImageCD" inManagedObjectContext:moc];
[request setEntity:entity];
// Edit the sort key as appropriate.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"date" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[request setSortDescriptors:sortDescriptors];
NSError *error = nil;
NSMutableArray *array = [NSMutableArray arrayWithArray: [moc executeFetchRequest:request error:&error]];
[request release];
[sortDescriptor release];
[sortDescriptors release];
if (array && [array count] && !error){
// create an array of images
NSMutableArray *images = [[NSMutableArray alloc] init];
for(ImageCD *obj in array){
UIImage *img = [UIImage imageWithData: (NSData *) obj.friendsPhoto];
[images addObject:img];
}
return [images autorelease];
}
else
return nil;
}

get NSString from NSFetchRequest issue

I'm using Core Data and I need to loop thru the result of the request, create several custom objects in the loop and store them in a NSMUtableArray, so I can send it to another view to feed a UI component. This is what I'm doing:
NSMutableArray *persons = [[NSMutableArray alloc] init];
NSError *error = nil;
NSManagedObjectContext *context = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription
entityForName:#"Person" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
for (NSManagedObject *info in fetchedObjects) {
ToggleButtonInfo *btn = [[ToggleButtonInfo alloc] init];
NSString *personName = [NSString stringWithFormat:#"ww %#", [info valueForKey:#"name"]];
NSLog(#"pn: %#", personName);
[btn setButtonInfo:personName];
[persons addObject:btn];
}
[fetchRequest release];
return persons;
The loop is working just fine, the information is there. The problem is that I get a "EXC_BAD_ACCESS" in my component if I use:
[info valueForKey:#"name"]
if I do something like this:
[btn setButtonInfo:#"something else here"];
everything works fine. So it looks like info is been de-allocated and that is causing the error, right? I try creating the scring using stringWithFormat but it doesn't work, same error.
An ideas?
Where do you get the EXC_BAD_ACCESS? I assume it's later when you're displaying the button? -setButtonInfo: probably isn't retaining, or you're over-releasing somewhere else.
Note that you're leaking btn in this code.

Example of how to make a data factory for core data access in cocoa (iPhone)?

I have been slowly learning iPhone development and seem to keep hitting walls where I can't figure out how to do what I want to do the right way :(
Basically, I want a class that handles all interactions with the data layer, for example, getting a mutable array of some list of objects from the data store.
This is pretty trivial in other languages where you have a garbage collector, but in Objective-C on the iPhone, I'm not sure what to do.
This is an example method on a DataFactory class we were creating. Note the comment on where we are not sure when to release....
- (NSMutableArray*)fetchAllDrivers{
NSMutableArray *results = [[NSMutableArray alloc] init];;
if (self.appDelegate != nil) {
NSManagedObjectContext *context = [self.appDelegate managedObjectContext];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Person" inManagedObjectContext:context];
[request setEntity: entity];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"lastName" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects: sortDescriptor, nil];
[request setSortDescriptors: sortDescriptors];
[sortDescriptors release];
[sortDescriptor release];
NSError *error;
results = [[context executeFetchRequest:request error:&error] mutableCopy];
if (results == nil) {
//something went wrong
}
//Where should this be released??? Certainly not here!
[results release];
[request release];
}
else {
[NSException raise:#"Can't fetch b/c app delgate is nil!" format: #"!!!"];
}
return results;
}
Calling code, related to my comment:
NSMutableArray* arr = [dataFactory fetchAllDrivers];
[arr retain];
//Some code where we use arr
[arr release];
Following naming conventions, your fetchAllDrivers should return an autoreleased object.
- (NSMutableArray*)fetchAllDrivers
{
if (!self.appDelegate) {
// Big Problems Raise exception immediately if you want...
return nil;
}
NSManagedObjectContext *context = [self.appDelegate managedObjectContext];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Person" inManagedObjectContext:context];
[request setEntity: entity];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"lastName" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects: sortDescriptor, nil];
[request setSortDescriptors: sortDescriptors];
[sortDescriptors release];
[sortDescriptor release];
NSError *error = nil;
NSMutableArray *results = [[NSMutableArray alloc] initWithArray:[context executeFetchRequest:request error:&error] copyItems:YES];
if (error) {
// Something went wrong
[results release];
// Error handling code here
[request release];
return nil;
}
[request release];
return [results autorelease];
}
NSMutableArray* arr = [dataFactory fetchAllDrivers];
[arr retain];
//Some code where we use arr
[arr release];
By convention, any object returned from the method of an external object is autoreleased. You don't need to retain them except in properties. If you only using arr in the local scope of the method then you don't need to retain/release it. It is autoreleased and will die after the end of the local scope.
If you need to have arr hang around inside the object. You should store it in a retained property:
#property (nonatomic,retain) NSMutableArray *arr;
... then use it with the self notation to ensure retention:
self.arr=[dataFactory fetchAllDrivers];
... then you need only release it in the class' dealloc method.
Having one object manage your data model is very good idea but it is not a "factory". Objective-c does not use factories like C++ and similar languages. Trying to think in those terms will lead to grief. The object should instead be thought of as a "controller" or "manager".

data not reloading into tableview from core data on minor update

I've got a basic photo album application, on the first view a list of albums is displayed with a subtitle showing how many images are in each album. I've got everything working to add albums, and add images to albums.
The problem is that the image count lines are accurate whenever the app loads, but I can't get them to update during execution.
The following viewdidload correctly populates all lines of the tableview when the app loads:
- (void)viewDidLoad {
[super viewDidLoad];
// Set the title.
self.title = #"Photo albums";
// Configure the add and edit buttons.
self.navigationItem.leftBarButtonItem = self.editButtonItem;
addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:#selector(addAlbum)];
addButton.enabled = YES;
self.navigationItem.rightBarButtonItem = addButton;
/*
Fetch existing albums.
Create a fetch request; find the Album entity and assign it to the request; add a sort descriptor; then execute the fetch.
*/
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Album" inManagedObjectContext:managedObjectContext];
[request setEntity:entity];
// Order the albums by name.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"albumName" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[request setSortDescriptors:sortDescriptors];
[sortDescriptor release];
[sortDescriptors release];
// Execute the fetch -- create a mutable copy of the result.
NSError *error = nil;
NSMutableArray *mutableFetchResults = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
if (mutableFetchResults == nil) {
// Handle the error.
}
LocationsAppDelegate *mainDelegate = (LocationsAppDelegate *)[[UIApplication sharedApplication] delegate];
// Set master albums array to the mutable array, then clean up.
[mainDelegate setAlbumsArray:mutableFetchResults];
[mutableFetchResults release];
[request release];
}
But when I run similar code inside viewdidappear, nothing happens:
{
/*
Fetch existing albums.
Create a fetch request; find the Album entity and assign it to the request; add a sort descriptor; then execute the fetch.
*/
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Album" inManagedObjectContext:managedObjectContext];
[request setEntity:entity];
// Order the albums by creation date, most recent first.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"albumName" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[request setSortDescriptors:sortDescriptors];
[sortDescriptor release];
[sortDescriptors release];
// Execute the fetch -- create a mutable copy of the result.
NSError *error = nil;
NSMutableArray *mutableFetchResults = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
if (mutableFetchResults == nil) {
// Handle the error.
}
LocationsAppDelegate *mainDelegate = (LocationsAppDelegate *)[[UIApplication sharedApplication] delegate];
// Set master albums array to the mutable array, then clean up.
[mainDelegate setAlbumsArray:mutableFetchResults];
[self.tableView reloadData];
[mutableFetchResults release];
[request release];
}
Apologies if I've missed the answer to this question elsewhere, but what am I missing?
To troubleshoot, put NSLog statements in a few places in -viewDidAppear:. You would use these log statements to make sure that this method is both being called properly and to examine the contents of mutableFetchResults, at least.