I have a plain XCode CoreData enabled iPhone/iPad navigation application. In this I have modifed the data it initially defines to represent some categories in the table view with associated images. For example by modifying a Event to Category elsewhere, changing the .xcdatamodel file and altering this call in RootController.m:
- (void)configureCell:(DeliciousCategoryCell *)cell atIndexPath:(NSIndexPath *)indexPath {
NSManagedObject *managedObject = [self.fetchedResultsController objectAtIndexPath:indexPath];
cell.categoryLabel.text = [[managedObject valueForKey:#"name"] description];
NSString *filePath = [[NSBundle mainBundle] pathForResource:cell.categoryLabel.text ofType:#"tiff"];
cell.categoryImage.image = [[UIImage alloc] initWithContentsOfFile:filePath];
}
If I preload the data from an xml file by putting code in:
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
The data gets loaded in fine but the app subsequentially crashes with EXC_BAD_ACCESS. If I take that code out the app loads, my data is present and my categories display fine with the associated local images. I've tried moving the code in question elsewhere such as:
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
and checking to make sure the data is empty however it still crashes yet loads the data. I can't seem to track down the cause of the EXC_BAD_ACCESS via the debugger as the stack trace is void of useful information. What I would like to know is an answer to the following as I cannot find it in apples documentation:
1) When such a Core Data based application first starts where should the calls to load in an initial data set go? I would ideally do this via the web but am currently just opening a local xml file for testing.
2) Once core data has been loaded I would like to enable the user to update the core data information by merging. Where should such code reside?
I don't have a problem with the logic just the location of the necessary code afaict. If anyone would like a listing of what I'm doing I'll provide but it is rather verbose. The code as implemented is taken straight from two apple tutorials. The latter detailing how to load in data without undue fetches/selects on the data base, however said tutorial doesn't say anything about where it should reside.
I think you're to fixated on the location of the code being the problem.
Objective-C, Core Data and the general Apple API are all very encapsulated and modular. You can plug in needed functionality almost anywhere and activate it or not at almost any time. The only critical locations/times are app delegate methods related to the starting and stopping of the app. Everything else is flexible. In your case, you only need to load data before you use it and you only need to merge data after it has changed. The possible configurations of when and where are functionally infinite. Different apps do all this at different places and times.
You should be looking at a more prosaic cause of the EXC_BAD_ACCESS. Under normal conditions, the debugger will show you the line where the crash happens. If it shows nothing, then the debugger itself most likely crashed. More likely, you just missed the display of the crashed line because the line in your code that triggered it is scrolled off the screen of the stack trace. (A lot of beginners make that mistake.)
When you see EXC_BAD_ACCESS, you have over-released an object. Here is some troubleshooting advice.
Related
I am new to IOS and I am following CS193p Stanford's lecture to learn about Core Data and in the demo the Professor used a category with somehow similar to what actually to if we check core data application checkbox while creating application and it puts the core data stuff in appDelegate. That's what professor did in demo he created managedObjectContext in AppDelegate and used a Notification to Pass the Context to controller. Now for Assignment he asked to use UIManagedDocument but I am confused about where to put it. Should I declare it in the View Controller or in AppDelegate and pass context using Notification Centre. So I just want to know which one is better for UIManagedDocument. S
Best way I found is create a new project (just as a sample), check 'Use Core Data' when asked, and look inside the AppDelegate. Use that to see how it's done and possibly, copy the appropriate parts (some adjustments will be needed of course). But mostly, use it to learn how Apple recommends it to be used.
Create a custom class with a shared instance that has managedObjectContext property.
In your application didFinishLaunchingWithOptions in AppDelegate, create your sharedInstance and pass it the 'managedObjectContext`.
MyDataManager *dataManager = [MyDataManager sharedInstance];
dataManager.managedObjectContext = self.managedObjectContext;
Notice also that if you terminate the app by hitting the 'Stop' in Xcode, the data won't be saved (since it's done, as it should, when the AppDelegate is about to close the app properly).
Make sure to also have [self saveContext]; in applicationDidEnterBackground, it supposed to be inside applicationWillTerminate as well. It is a good practice to write the database to memory only when needed (and not at every change). In the AppDelegate, it also ask if the data has changed before committing.
Of course, you can also save manually if you have the managedObjectContext instance.
If you made changes to the database you might have to delete the app from the simulator before running again (otherwise app will crash since the older DB won't match the new one).
Edit: I can't remember where I read it, but the professor does not use CoreData as a database pre-se, only to manage data (images etc.).
You can initialize your UIManagedDocument where ever you want to initiate access to your database. When I did the assignment (last year), I put in the AppDelegate. In glancing back now I see there are two ViewControllers in a UITabBarController and they both need the context. So I used the NSNotification mechanism like Paul did in lecture.
The reasons he gives for using UIManagedDocument over "User Core Data" checkbox (when creating the project) was:
It was simpler for him to explain (UIManagedDocument takes care of lots of complexities)
UIManagedDocument puts you on a fast track to using iCloud
I was just reviewing this as well. If you want to hear from Paul, he talks about it in Lecture 12 (Fall 2013-14) at 14 minutes and 25 seconds (UIManagedContext) and at 14:50 he starts talking about the two ways to get the UIManagedContext -- being UIManagedDocument or the "Use Core Data" checkbox.
Here us a link to the course on iTunes: https://itunes.apple.com/us/course/developing-ios-7-apps-for/id733644550
My app's minimum support iOS version is iOS5. And I didn't do any state save and restoration.
It works well on my self iphone4, but some users complain the app is reset when they pick up a phone call or change to other app and back.
So, I take state restoration more serious, and I want to add it into my app.
However, I have image album function, so I call ALAssetLibrary.
I need to create the exact the same thumbnail view as it was.
I have some background Operations in operationQueue, so I need to know their state and add the unfinished background operations. It's a little complicated.
Here're my questions.
1. I didn't find useful sample code, project. (session208 in WWDC2012, but they didn't release code in WWDC sample code release), Do you know any?
2. what's the best way to do it ? follow iOS6 or make it by myself?
what's the difference.
3. For ALAssetlibrary, image thumbnail viewing, how could I achieve state save and restoration?
Definitely use Apple's APIs, don't reinvent the wheel. The WWDC 2012 session about this used the WWDC 2012 app as the example to show off the feature, there was never any demo project to share to developers. However they have since (recently) released a demo to demonstrate it, you can find it here: http://developer.apple.com/library/ios/#samplecode/StateRestore/Introduction/Intro.html
It sounds like your state is complex, and I'm not sure you really want to be restoring those background operations. You probably will find it better to restore the user to a more stable part of your app.
For your ALAssetlibrary question, you would save an ID to the current image in your encodeRestorableStateWithCoder: implementation of your view controller, make sure you read up on the documentation, you'll need to conform to a protocol, set a restoration class if you're in code or using xibs (not using storyboard)... you would save the ID doing something like this:
NSString * const ImageReferenceIDKey = #"ImageReferenceID";
- (void)encodeRestorableStateWithCoder:(NSCoder *)coder
{
NSString *objectID = nil; // get some ID that can relocate your image
[coder encodeObject:objectID forKey:ImageReferenceIDKey];
[super encodeRestorableStateWithCoder:coder];
}
- (void)decodeRestorableStateWithCoder:(NSCoder *)coder
{
[super decodeRestorableStateWithCoder:coder];
NSString *objectID = [coder objectForKey:ImageReferenceIDKey];
// get into the ALAssetlibrary and use the objectID to restore which image you had.
}
Notice I call super last in the encode method, but first in the decode method.
You should be very careful about the user having changed the privacy of your access to their photos, don't crash on them, if you try to restore a photo make sure you still have permissions to do so, or you might crash.
Friends,
I have an application, ten pages, but full of buttons(with background images), big size background images, box image for set of controls, etc. I have designed all those in XIB files. It is working fine, but in few minutes, my application shows "Received memory warning level=1". Some developers suggesting me to do designs using .m files, instead of doing it in XIB file. They are telling that it will reduce memory usage of graphics.
Is it true? Will designing by .m file reduce memory usage? Please advice, Thank you.
Did you check if you have memory leaks in your app? XIB files use just constant amount of memory. Also, creating the same interface in the code consumes almost the same amount of memory.
In any case, XIB consumes only a definite amount of memory once you load it.
So, if you receive memory warning not immediately after loading the XIB, but a few second afterwards, the real reason causing the memory warning is definitely elsewhere.
Are you doing retain and release correctly? Run static analyzer from the Xcode, remove all warnings reported, and then use Instruments to see if you have memory leaks.
Designing a UI in Nib-file, or doing the same manually in code makes no difference on memory consumptions. The end result is the same amount of life objects in memory, a Nib-file is only serialized objects, no other magic.
Nib-files and Interface Builder only allows you to design UI faster with drag and drop, instead of trial-and-error in code. All the bonuses that Nib-files comes with has a small price; you must bother yourself to at least read the documentation on how to use them! Otherwise you will get into trouble. You can bet that any person advising against Nib-files flat out, have no idea what they are or how they work, and would not be bothered to learn either.
Go to http://developer.apple.com and search for "nib", you want to at least read "Core Competencies - Nib file", and "Memory Management of Nib Objects". Then decide if Nib-file is good or not for your task at hand.
Yea, it is true that you should do it in code. However, if you are receiving a memory warning, it really does not matter. You will have to remove the contents of on page before creating the contents of the other, otherwise it is the same as just using the .xib file. Infact, I once made an application with lots of windows, and I got the same memory warning message.
It is actually very easy to figure out why (I was surprised when I heard). Basically, every single thing in the .xib file is an object. When you have a lot of objects, you run out of memory. What you need to do is run code similar to te following when you change pages.
- (void) changeToPageOne {
[theSecondElement release];
//Then you make the new interface element
UIImageView *theElement = [[UIImageView alloc] initWithFrame:(CGRect)];
//You will need the coordinates from the .xib file for the CGRect there
[theElement setImage:(UIImage*)];
[theView addSubview:theElement];
}
You do the same thing for the next page. The problem here is that you will need to be able to keep track of the UIImageView, but it is basically just a local variable here. You may want to add it to an array, and just remove the objects in the array when you change pages. I hope this helps!
I'm wondering what could cause this.
I have several methods in my code that i call using performSelectorInBackground.
Within each of these methods i have an Autoreleasepool that is being alloced/initialized at the beginning and released at the end of the method.
this perfectly works on iOS 3.1.3 / 3.2 / 4.2 / 4.2.1 but it fataly crashes on iOS 4.0 with a EXC_BAD_ACCESS Exception that happens after calling [myPool release].
After I noticed this strange behaviour I was thinking about rewriting portions of my code and to make my app "less parallel" in case that the client os is 4.0.
After I did that, the next point where the app crashed was within the ReachabilityCallback-Method from Apples Reachability "Framework".
well, now I'm not quite sure what to do.
The things i do within my threaded methods is pretty simple xml parsing (no cocoa calls or stuff that would affect the UI). After each method finishes it posts a notification which the coordinating-thread listens to and once all the parallelized methods have finished, the coordinating thread calls viewcontrollers etc...
I have absolutely no clue what could cause this weird behaviour. Especially because Apples Code fails as well.
any help is greatly appreciated!
thanks,
sam
The best way to detect zombies is:
in the Groups and Files section, expand the Executables section and right click on your app name and choose Get Info
select the Arguments tab on the top and then add a new entry in the Variables to be set in the environment section. Name the new variable to NSZombieEnabled and set its value to YES.
After this you will have information in console on which released objects you make calls.
Seem's like i've solved the Issue.
The Problem was, that (as many of you suggested) I've overreleased an NSURL Object within a Method which calls [NSString stringWithContentsOfURL:urlRequest encoding:NSUTF8StringEncoding error:&error];
I assume that stringWithContentsOfURL autoreleases the NSURL object that i pass as a parameter.
after removing the release on urlRequest the issue dissapeared. Still i think that it's very strange that different iOS Versions behave differently on that matter.
the whole method looked like this:
-(NSString*)downloadContent:(NSURL*)urlRequest
{
NSString *data = nil;
NSError *error = nil;
data = [NSString stringWithContentsOfURL:urlRequest encoding:NSUTF8StringEncoding error:&error];
//[urlRequest release]; //Crashes on iOS 4.0 / 4.1 later when autoreleasepool is being released.
return data;
}
Sounds like an autoreleased object created in the scope of that autorelease pool is being released somewhere it shouldn't be. Not sure why the behaviour differs with the version of the SDK; there must be an implementation difference somewhere that's causing the issue. Have you built the code using "Build and Analyze"? Does it suggest anything might be over-released?
I've noticed some strange behavior with performSelectorInBackground also. I might be completely wrong on this, but in my case I've used:
[NSThread detachNewThreadSelector:#selector(blah) toTarget:self withObject:nil];
with better results. If, when you're in that method, you need to access the main thread (to update the UI for example), you can just:
[self performSelectorOnMainThread:#selector(blah2) withObject:nil waitUntilDone:false];
I am trying to access the UITextView delegates and have a problem
I have a UIViewController with the UITextViewDelegate protocol and a Nib containing the textView.
If I set the delegate inside viewDidLoad like "textView.delegate = self" and I touch the textView, the app crashes without logging errors.
If I start editing the textView with code like "[textView becomeFirstResponder]" all delegates get called.
When I set the delegate in the Nib creating a connection between the textView and the File's owner and deleting "textView.delegate = self" also no delegates get called.
What am I doing wrong here?
Regards,
Elias
It's not easy to help you without more description, posted code or a xib file.
You say application crashes without any logging errors - well, do you mean that there's no output in console's window ? That is normal, for an app that has crashed.
Anyway, you should be able to get the stack-trace to figure out where approximately the application has crashed. Open the debugger (⇧⌘Y), and see the position. That should give you an idea of what went wrong.
Here you can see an example of such debugger session (after EXC_BAD_CRASH):
First two lines doesn't give us much information, but later on we can see that application has crashed while loading user interface from a NIB file. Well, usually the only code that executes during such load are awakeFromNib methods - it's up to you to find a problem along those lines.
Often top of code's execution doesn't make any sense - for example you might see your ViewController method somewhere, but the top few function calls (those where the code crashed) are located in methods/classes which you never call in your code. In most cases that is a sign of wrong memory de-/allocation. What might happened is that you forgot to retain some of your objects, it has already been released, but you are still keeping reference (a pointer) to its memory. Because that memory has been in fact freed, another object took its place later on, usually some Apple's internal object you've never heard about. Later on your code tries to message your poor object but it sends a message to something completely different. BUMMER! That's how you get those crashes and strange stack traces.
To fix the kind of problem I've just described you can use Instruments and its Zombies instrument. Unfortunately you can't start Zombies from within Xcode, you need to start Instruments standalone, then choose the Zombies under iPhone Simulator/Memory, then Choose Target from the toolbar, you should see your application in there, or be able to navigate to it on filesystem.
What Zombies instrument does is that it never really frees memory after objects are deallocated. Instead, it will mutate those objects into NSZombie class. That class intercepts all calls to itself, and informs you when some code is trying to send a message to it.
This is how such Instruments session looks like (this is the same crash as seen in debugger above):
In the table you can see that we're trying to message UIScrollView that has already been deallocated. You can as well see the whole history of retain/release calls to this particular object. That way you can find a missing retain or wrong release/autorelease.
Remember - Zombies Instruments can only be used with Simulator, because there's not enough memory on the real device to keep all those memory blocks.
Hopefully I could help you with further analysis of your problem.