Crashing App when try to add images..? - iphone

I am new iPhone Developer. I am upgrading existing iPhone App. I am using Core Data Model to save data.
In App, there is a 15 square boxes to add images. I am calling a Detached Thread to make a separate process. In this process, I am saving image into two size. I have added observer with image object and remove observer at last.
I am using this method to add Observer:-
[projectImage addObserver:self forKeyPath:#"fileName" options:NSKeyValueObservingOptionNew context:nil];
And this method for making separate Thread:-
[NSThread detachNewThreadSelector:#selector(addImage:) toTarget:self withObject:[dic retain]];
here AddImage is Method like:-
- (void) addImage:(NSDictionary *) dic {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
UIImage *image = [dic objectForKey:#"image"];
projectImage = nil;
projectImage = [dic objectForKey:#"managedObject"];
[projectImage importImageData:image];
[projectImage removeObserver:self forKeyPath:#"fileName"];
[pool drain];
}
And dic is Dictionary
My problem is :
It is Crashing after taking 4-5 images by Camera or Phone library.
If any can guide me to get rid to this problem.
Thanks in Advance

You are leaking memory, and probably because of this your app will crash. I think the app runs out of memory and gets killed.
remove the [dic retain] from
[NSThread detachNewThreadSelector:#selector(addImage:) toTarget:self withObject:[dic retain]];
the object is retained by the method call. See the discussion of detachNewThreadSelector:toTarget:withObject:.
The objects aTarget and anArgument are retained during the execution of the detached thread, then released. The detached thread is exited (using the exit class method) as soon as aTarget has completed executing the aSelector method.
your call should be
[NSThread detachNewThreadSelector:#selector(addImage:) toTarget:self withObject:dic];

Related

Error 133000 when using multiple contexts with core data

I've spent days trying every possible solution I can think of to this problem, but nothing seems to be working.
I run a background thread like this:
[MagicalRecord saveInBackgroundWithBlock:^(NSManagedObjectContext *localContext) {
Media *localMedia = [media inContext:localContext];
UIImage *image = localMedia.thumbnail;
dispatch_async(dispatch_get_main_queue(), ^{
[thumbnails setObject:image forKey:[NSNumber numberWithInt:i]];
[contentDict setObject:thumbnails forKey:#"MediaItems"];
[cell.entryView setNeedsDisplay];
});
}];
Or like this:
dispatch_queue_t cellSetupQueue = dispatch_queue_create("com.Journalized.SetupTimelineThumbnails", NULL);
dispatch_async(cellSetupQueue, ^{
NSManagedObjectContext *newMoc = [[NSManagedObjectContext alloc] init];
NSPersistentStoreCoordinator *coordinator = [NSManagedObjectContext contextForCurrentThread].persistentStoreCoordinator;
[newMoc setPersistentStoreCoordinator:coordinator];
NSNotificationCenter *notify = [NSNotificationCenter defaultCenter];
[notify addObserver:self
selector:#selector(mergeChanges:)
name:NSManagedObjectContextDidSaveNotification
object:newMoc];
Media *localMedia = [media inContext:[NSManagedObjectContext contextForCurrentThread];
UIImage *image = localMedia.thumbnail;
dispatch_async(dispatch_get_main_queue(), ^{
[thumbnails setObject:image forKey:[NSNumber numberWithInt:i]];
[contentDict setObject:thumbnails forKey:#"MediaItems"];
[cell.entryView setNeedsDisplay];
});
}];
Both of these give me a crash with UIImage returning as nil object, and a Cocoa Error 133000.
I've removed every other piece of background threading code, and have saved on the main thread directly before this just to make sure. Running the code above on the main thread also works, but freezes up my UI. Despite all of these efforts, the above code crashes every time.
I'm not sure what to do to make this work.
Edit:
My question, specifically, is how do I make this work without crashing? It seems to be a problem with objects from 1 context not existing in another, but how do i make them exist in another context?
Remember, the MR_inContext: method is using [NSManagedObjectContext objectWithID: ] method under the covers. You should look in there to make sure your object has:
1) Been saved prior to entering into the background context/block in your first code block
2) This method is returning something useful
I'm also not sure how you set up your thumbnail attribute. Ideally it shouldn't matter as long as you have the NSTransformable code write (there are samples on the internets that show you how to save a UIImage in core data using the transformable attribute)
Also, your code should look like this:
UIImage *image = nil;
[MagicalRecord saveInBackgroundWithBlock:^(NSManagedObjectContext *localContext) {
Media *localMedia = [media inContext:localContext]; //remember, this looks up an existing object. If your context is a child of a parent context that has contains this, the localContext should refresh the object from the parent.
//image processing/etc
image = localMedia.thumbnail;
} completion:^{
[thumbnails setObject:image forKey:#(i)]; //new literals are teh awesome
contentInfo[#"MediaItems"] = thumbnails; //as is the new indexer syntax (on the latest compiler)
[cell.entryView setNeedsDisplay];
}];
Fast answer:
NSManagedObjectReferentialIntegrityError = 133000,
// attempt to fire a fault pointing to an object that does not exist (we can see the store, we can't see the object)
EDIT:
It's pretty difficult to see something from the code. What is a managed object there?
I suppose the problem is that you are using temporary objects from one context in another context.

How to Stop a currently executing thread

Scenario is like this--
In my app there is an Scroll View with many instances of
MyCustomImageDownloaderController(containing imageViews where images are to be assigned after downloading) .
As per our requirement, an image has to be downloaded as we move on to a page.
Scroll View + (MyCustomImageDownloaderController1, MyCustomImageDownloaderController2, MyCustomImageDownloaderController3.... etc)
Let's say i am scrolling on it,
i reached to page 1 --> image for it should start downloading
i reached to page 2 --> image for it should start downloading...so on
and if i am on page 3 and images for previous pages if not been dowloaded, they should stop downloading.
So i tried it with using threads..
on API..
- (void)scrollViewDidEndDecelerating:(UIScrollView *)sender{
Step 1) calculated currentPageNumber
Step 2) started thread for downloading image with url for this currentPage
//startBackGroundThreadForPlaceImage:(NSURL *) url
Step 3)stopped thread for previous page , if that is still running
}
Now My MyCustomImageDownloaderController is as
-(void) startBackGroundThreadForPlaceImage:(NSURL *) url{
if(isImageDownloaded == NO){
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
//[self performSelectorInBackground:#selector(loadImageInBackground:) withObject:imageUrl];
myThread = [[NSThread alloc] initWithTarget:self selector:#selector(loadImageInBackground:) object:imageUrl];
//[NSThread detachNewThreadSelector:#selector(loadImageInBackground:) toTarget:self withObject:imageUrl];
[myThread start];
NSLog(#"The current thread is %# ", [[NSThread currentThread] name]);
[pool release];
}
}
NOW Here selector does the work of loading image and assigning to image view
Now Stopping the thread
-(void) stopBackgroundThread{
[myThread cancel];
//[[NSThread currentThread] cancel];
//if([[NSThread currentThread] isCancelled]) {
//[NSThread exit];
//}
[NSThread exit];
}
-(BOOL) isThreadRunning{
return [myThread isExecuting];
}
So i tried a lot of things, but could not Stop the thread in between..
Basically once instantiated thread using any of three methods
1) perform Selector in BackGround
2) NSThread detach new thread
3) NSThread alloc..init with..
In first 2 methods how to get the instance of the newly created thread, so that i could stoop it,
as NSThread currentThread doest not give that
in Method 3,
myThread = [[NSThread alloc] initWithTarget:self selector:#selector(loadImageInBackground:) object:imageUrl];
when i tried
[myThread cancel];
It did not cancel that thread,,
When i tried
[NSThread exit];
it hangs on current screen,,,,i guess it has stopped the main thread
Please help me
Thanks in Advance*strong text*
It's generally better to ask the thread to stop, rather than forcing it, which should be considered a last resort. You should, therefore, frequently check a 'stop flag' and when this gets set, terminate the current thread (by simply exiting the method, in this case). You just need to provide a property on the class the thread is operating on so callers can ask the thread to stop.
It's no different in C++ or Java.

saving NSManagedObjectContext causes the app to wait infinitely

Why is it that everytime I call save on my NSManagedObjectContext:
-(NSManagedObjectContext*)managedObjectContext {
NSMutableDictionary* threadDictionary = [[NSThread currentThread] threadDictionary];
NSManagedObjectContext* backgroundThreadContext = [threadDictionary objectForKey:RKManagedObjectStoreThreadDictionaryContextKey];
if (!backgroundThreadContext) {
backgroundThreadContext = [self newManagedObjectContext];
[threadDictionary setObject:backgroundThreadContext forKey:RKManagedObjectStoreThreadDictionaryContextKey];
[backgroundThreadContext release];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(mergeChanges:)
name:NSManagedObjectContextDidSaveNotification
object:backgroundThreadContext];
}
return backgroundThreadContext;
}
- (NSError*)save {
NSManagedObjectContext* moc = [self managedObjectContext];
NSError *error = nil;
#try {
if (![moc save:&error]) { //breakpoint in here
//some code
}
the app seems to be waiting forever and never got back to resume it's execution? Here's what I mean in a video. Can this be possibly caused because something is wrong with the entity/relationship model?
Here's a screenshot of the leaks instruments, I don't see any leaks, but it seems that the app is allocating something that builds up:
Have you tried ditching your multi-threading code to see if it works? My guess would be that you're mixing up threads here and accessing/saving the MOC from different threads. Managing threads manually is a PITA, you should try switching to Grand Central Dispatch.
I would also give your main MOC its own accessor so you can make sure it isn't called from background threads, and have some: - (NSManagedObjectContext*)newBackgroundMOC; and - (void)saveBackgroundMOC:(NSManagedObjectContext*)context; methods to quickly create and save MOCs from background queues/threads:
dispatch_async(my_queue, ^{
NSManagedObjectContext *context = [self newBackgroundMOC]; // create context, setup didSave notification to merge with main MOC, etc
// modify context
[self saveBackgroundMOC:context]; // main MOC gets updated
});
Migrating to GCD is a bit of work, but in the long run you'll see it's much more pleasant to work with. It goes without saying that it's also the most modern and recommended by Apple way to deal with threads.

UIImageView.image = mImage leak

I have thread2 loop where i do assembly (create from raw bytes data) some UIImage
in every iteration of this loop
thread2loop()
{
//make UIIamge here
[self performSelectorOnMainThread:#selector(setUiImage) withObject:nil waitUntilDone:YES];
}
there and then i call setUIImage method on the main thread
- (void) setUiImage
{
self.imageView.image = nil;
self.imageView.image = mImage;
[mImage release];
}
it is working but the Instruments , leaks application shows to me that there are
UIImage leaks here and i do not know how to ##$! get rid of it! (im sad and little tired
and bored), help, what to do, tnx
Surround your threaded code with...
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
//threaded code....
[pool release];
Classic producer/consumer problem. Your producer thread is probably outrunning the main thread (the consumer). I'd recommend keeping a queue of images (instead of the single mImage), guarded by a lock which you enqueue images onto (from your background queue), and dequeue images from your main queue. Or you could use GCD, which makes this even easier. Instead of using mImage to hold onto the created image, you could just use a block which would retain the image and then set it on your image view in the main queue. Something like:
thread2loop() {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
while (...) {
__block id self_block = self; // (don't want to retain self in the block)
UIImage *img = [[UIImage alloc] initWithCGImage:quartzImage scale:1.0 orientation:UIImageOrientationUp];
dispatch_async(dispatch_get_main_queue(), ^{
block_self.imageView.image = img;
[img release];
});
}
[pool drain]; // release is outdated for autorelease pools
}
Warning: Doing this too much will quickly run the device out of memory and cause your app to be killed. You probably want to make sure that your use of this technique is limited to creating a small number of images.

Crash - "Collection <CALayerArray: 0x645dfc0> was mutated while being enumerated."

Goal is to "launch a spinner graphic at start of viewWillAppear that loads data before showing the tableview" so the user doesn't wonder why there's a delay before seeing the table. I.e. a UIActivityIndicatorView has been added to the window, and I just want to set the alpha to hide/show it.
I get this strange error when starting a thread to make sure the "spinning gears" imageview (tag=333) gets shown, before moving on to load/calculate stuff in viewWillAppear.
I don't get it on every call to [appdel addGearz] and [appdel removeGearz], it happens for both these, and it's random. It can happen after 2 viewWillAppears, or after 15. If I comment out the line that sets the alpha, everything works.
A typical viewWillAppear looks something like this,
[super viewWillappear];
self.title=#"Products listing"; //and other simple things
[appdel addGearz];
[self getProducts];
[self getThumbnails];
[myTableView reloadData]; //in case view already loaded and coming back from subview and data changed
And here is the code that crashes if the lines with .alpha are not commented out
-(void)addGearz {
[NSThread detachNewThreadSelector:#selector(gearzOn) toTarget:self withObject:nil];
}
-(void)removeGearz {
[NSThread detachNewThreadSelector:#selector(gearzOff) toTarget:self withObject:nil];
}
- (void)gearzOn {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[window viewWithTag:333].alpha=1.0;
//
// [[window viewWithTag:333] setNeedsDisplay];
[pool drain];
}
- (void) gearzOff {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[window viewWithTag:333].alpha=0.0;
//
// [[window viewWithTag:333] setNeedsDisplay];
[pool drain];
}
I've used someone else's code, so... anything obvious you can see? Surely I must be able to change alpha of UIViews in a thread? Do I need to "embed" the alpha-change in some "stop enumerating while I change this"-code?
I made it not crash by moving that alpha-change-line to above the pool alloc or below the [pool drain], but then I get a lot of "autoreleased with no pool in place - just leaking"-messages.
Apparently, there's something I don't understand about this thread code.
You must not try to modify the UI on a separate thread. UI should only be manipulated on the main thread.
Instead of detaching a new thread, you should use performSelectorOnMainThread:withObject:waitUntilDone:. This will ensure that the method will be called on the proper thread.