What causes a "Virtual Memory exhausted" error? - objective-c

Alright.. Here's the thing.. I am building an app in which when the user taps on download button it downloads a bunch on images (296, to be exact).
In simulator everything works flawless, on my iPhone (4S) on around 100th image it crashes with error:
malloc: * mach_vm_map(size= "some random number") failed (error code= 3)* error: can't allocate region
libBacktraceRecording.dylib: allocate_free_list_pages() -- virtual memory exhausted!
Here's the code I wrote for downloading those images:
-(void)getData
{
NSError *error;
int i;
NSArray *brojLinije = [[NSArray alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"linije" ofType:#"plist"]];
NSArray *urlSlike = [[NSArray alloc] initWithContentsOfFile:[[NSBundle mainBundle]pathForResource:#"urlSlike" ofType:#"plist"]];
NSArray *pocetno = [[NSArray alloc] initWithContentsOfFile:[[NSBundle mainBundle]pathForResource:#"pocetno" ofType:#"plist"]];
NSArray *sortiranje = [[NSArray alloc] initWithContentsOfFile:[[NSBundle mainBundle]pathForResource:#"sort" ofType:#"plist"]];
NSArray*paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *desktopDir = [paths firstObject];
UIImage *image1 = [[UIImage alloc] init];
for (i = 0; i<296; i++) {
NSString *brojLinije1 = [NSString stringWithFormat:#"%#",[brojLinije objectAtIndex:i]];
NSString *pocetno1 = [NSString stringWithFormat: #"%#", [pocetno objectAtIndex:i]];
NSString *tableSort = [NSString stringWithFormat: #"%#", [sortiranje objectAtIndex:i]];
image1 = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat: #"http://www.busevi.com/images/stories/Red-Voznje/Gradski-Prevoz-BG/linija.%#.png", [urlSlike objectAtIndex:i ] ]]]];
NSData *data1 = [NSData dataWithData:UIImageJPEGRepresentation(image1, 0.1)];
NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext];
NSEntityDescription *entity = [[self.fetchedResultsController fetchRequest] entity];
NSManagedObject *newManagedObject = [NSEntityDescription insertNewObjectForEntityForName:[entity name] inManagedObjectContext:context];
NSString *pngFilePath = [NSString stringWithFormat:#"%#%#.jpg",desktopDir,[urlSlike objectAtIndex:i]];
[data1 writeToFile:pngFilePath atomically:YES];
[newManagedObject setValue:brojLinije1 forKey:#"brojLinije"];
[newManagedObject setValue:data1 forKey:#"imageData"];
[newManagedObject setValue:pocetno1 forKey:#"pocetnoStajaliste"];
[newManagedObject setValue:tableSort forKey:#"sort"];
NSLog(#"%d / 296", i);
}
[self.managedObjectContext save:&error];
}
Only thing I know is that the image allocation frequency (too much allocating and no time to automatically release) is making the problem, AND that I have tried every method I know so far, AND I HAVE watched A LOT of "Instruments" app tutorials and only one helped (to find the source of filling virtual memory) but I still can't solve my problem.

You can use a local autorelease pool inside of the loop to immediately release any objects that were created in the body of the loop.
for (i = 0; i<296; i++) {
#autoreleasepool {
// loop body goes here...
}
}

While using SDWebImage framework I encountered a lot of bugs and unanswered crashes from the app. SDWebImage is awesome if the count of images that are about to be downloaded is lower that, let's say 50. Because, when downloading one by one image that are showed in TableViewCell + fast scrolling (fast flicking), the app receives memory warning a couple of times while the TableView is still scrolling (SDWebImage will clear memory ONLY when TableView is slowly scrolling or not scrolling at all) so it crashes the app.
So my only solace with app crashing while downloading 300+ images was simple Apple's method called dispatch_async. More about it here.
And this is how I solved my problem (I just had to move everything from my original -(void)getdata method to dispatch_async block. DONE!
So now it looks like this:
-(void)getData {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(#"Downloading Started");
slike = [[NSArray alloc]initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"slike" ofType: #"plist"]];
brojevi = [[NSArray alloc]initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"linije" ofType:#"plist"]];
pocetnaStajalista = [[NSArray alloc]initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"pocetno" ofType:#"plist"]];
sort = [[NSArray alloc]initWithContentsOfFile:[[NSBundle mainBundle]pathForResource:#"sort" ofType:#"plist"]];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Linija" inManagedObjectContext:self.managedObjectContext];
NSString *brojLinije;
NSString *pocetnoStajaliste;
NSString *sortiranje;
NSData *data;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [NSString stringWithFormat:#"%#/%#", documentsDirectory,#"filename.png"];
for (int i = 0; i<314; i++) {
NSManagedObject *novaLinija = [[NSManagedObject alloc]initWithEntity:entity insertIntoManagedObjectContext:self.managedObjectContext];
brojLinije = [NSString stringWithFormat:#"%#",brojevi[i]];
pocetnoStajaliste = [NSString stringWithFormat:#"%#",pocetnaStajalista[i]];
data = [NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat: #"http://www.busevi.com/images/stories/Red-Voznje/Gradski-Prevoz-BG/linija.%#.png",slike[i]]]];
[data writeToFile:filePath atomically:YES];
sortiranje = [NSString stringWithFormat: #"%#", sort[i]];
[novaLinija setValue:data forKey:#"slikaLinije" ];
[novaLinija setValue:brojLinije forKey:#"brojLinije"];
[novaLinija setValue:pocetnoStajaliste forKey:#"pocetnoStajaliste"];
[novaLinija setValue:sortiranje forKey: #"sort"];
NSLog(#"%d / 314", i+1);
NSError *error;
[self.managedObjectContext save:&error];
} }
Hope this helps others with same problem. Good Luck and Happy Coding!

Used all of your and my suggestions and possible solutions, but, I'm sorry, none worked.
The point in this case, when app needs to download A LOT of photos, you really should use SDWebImageDownloader Class Reference.
I know It's frustrating to change the whole method and to realize the previous method (of downloading photos) is useless, so HERE is the tutorial and example on how to use SDWebImageDownloader Class. Good Luck.

Related

How to save data locally in app? [duplicate]

This question already has answers here:
Working with data in iOS Apps (What to choose? NSData, CoreData, sqlite, PList, NSUserDefaults)
(2 answers)
Closed 9 years ago.
I've been struggling with this for ages now and I really need some good help here. :)
I have an app where I'm parsing a quite big JSON into appdelegate's didFinishLaunchingWithOptions.
My Model Objects are:
Tab:
NSString *title
NSMutableArray *categories
Category:
NSString *title
NSMutableArray *items
Item
NSString *title
NSString *description
UIImage *image
I need to save the data locally, cause the parsing takes about 15 seconds every time my app starts. I'm using the SBJSON framework.
Here's my code for parsing:
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"json_template" ofType:#"json"];
NSString *contents = [NSString stringWithContentsOfFile: filePath encoding: NSUTF8StringEncoding error: nil];
SBJsonParser *jsonParser = [[SBJsonParser alloc] init];
NSMutableDictionary *json = [jsonParser objectWithString: contents];
tabs = [[NSMutableArray alloc] init];
jsonParser = nil;
for (NSString *tab in json)
{
Tab *tabObj = [[Tab alloc] init];
tabObj.title = tab;
NSDictionary *categoryDict = [[json valueForKey: tabObj.title] objectAtIndex: 0];
for (NSString *key in categoryDict)
{
Category *catObj = [[Category alloc] init];
catObj.name = key;
NSArray *items = [categoryDict objectForKey:key];
for (NSDictionary *dict in items)
{
Item *item = [[Item alloc] init];
item.title = [dict objectForKey: #"title"];
item.desc = [dict objectForKey: #"description"];
item.url = [dict objectForKey: #"url"];
if([dict objectForKey: #"image"] != [NSNull null])
{
NSURL *imgUrl = [NSURL URLWithString: [dict objectForKey: #"image"]];
NSData *imageData = [NSData dataWithContentsOfURL: imgUrl];
item.image = [UIImage imageWithData: imageData];
}
else
{
UIImage *image = [UIImage imageNamed: #"standard.png"];
item.image = image;
}
[catObj.items addObject: item];
}
[tabObj.categories addObject: catObj];
}
[tabs addObject: tabObj];
}
What is the best way of doing this? Using Core Data or NSFileManager?
If you have som code example too it will make me very happy.
This is the last thing i need to fix before the app is ready for app store and it just kills me! I can't solve this problem.
If you are working on iOS then you save a file to the Documents folder. On Mac OS X it would be in the Application Support folder. Since you are on iOS, read this answer for how to access the Documents folder.
All of the objects that you want to store should implement NSCoding. The above variables already do. Should you want to store the tabs, categories and items directly they would need to implement NSCoding. Then all you need is to serialize them to a file. When opening you app you can look for this file and get your objects back without parsing.
The code should look something like this (untested and error checking is ommited for brevity):
- (void) saveStateToDocumentNamed:(NSString*)docName
{
NSError *error;
NSFileManager *fileMan = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docPath = [paths[0] stringByAppendingPathComponent:docName];
if ([fileMan fileExistsAtPath:docPath])
[fileMan removeItemAtPath:docPath error:&error];
// Create the dictionary with all the stuff you want to store locally
NSDictionary *state = #{ ... };
// There are many ways to write the state to a file. This is the simplest
// but lacks error checking and recovery options.
[NSKeyedArchiver archiveRootObject:state toFile:docPath];
}
- (NSDictionary*) stateFromDocumentNamed:(NSString*)docName
{
NSError *error;
NSFileManager *fileMan = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docPath = [paths[0] stringByAppendingPathComponent:docName];
if ([fileMan fileExistsAtPath:docPath])
return [NSKeyedUnarchiver unarchiveObjectWithFile:docPath];
return nil;
}

How can I read supporting files by line in Xcode?

I'm currently making a web browsing program in Xcode 4.5.1 for OS X and I am trying to work on a list of bookmarks. What I hope to do is to have a supporting file called Bookmarks.txt in which I would list bookmarks like this:
Google
http://www.google.com/
Apple
http://www.apple.com/
Microsoft
http://www.microsoft.com/
I have already looked at a lot of pages discussing this, but none of them apply to what I'm doing. What I have now is
NSMutableArray *list;
NSString *contents;
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"Bookmarks" ofType:#"txt"];
if (filePath) {
content = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
for (NSString *line in [contents componentsSeparatedByString:#"\n"]) {
[list addObject:line];
}
}
as well as Dave DeLong's method, but I get all kinds of errors with Dave DeLong's and with this one nothing happens. Any help would be great, but I am just starting out at Xcode and know very little.
Thanks!
Your objects aren't initialized.
NSMutableArray *list = [[NSMutableArray alloc] init];
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"Bookmarks" ofType:#"txt"];
if (filePath) {
NSString * content = [NSString initWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
for (NSString *line in [contents componentsSeparatedByString:#"\n"]) {
[list addObject:line];
}
}

loading AVAudioPlayer file URLs from a Plist

I'm working with about 50 AVAudioPlayers that each load a separate audio file. The files are fixed and within the app bundle. They are triggered by events later on in the app. Currently I'm hardcoding the creation of each player instance, like so:
//No01
NSURL *no01URL = [[NSURL alloc] initFileURLWithPath: [[NSBundle mainBundle] pathForResource:#"audio1" ofType:#"aiff"]];
self.no01Player = [[AVAudioPlayer alloc] initWithContentsOfURL:no01URL error:nil];
no01Player.numberOfLoops = 0;
no01Player.volume = 0;
no01Player.delegate = self;
//No02
NSURL *no02URL = [[NSURL alloc] initFileURLWithPath: [[NSBundle mainBundle] pathForResource:#"audio2" ofType:#"aiff"]];
self.no02Player = [[AVAudioPlayer alloc] initWithContentsOfURL:no02URL error:nil];
no02Player.numberOfLoops = 0;
no02Player.volume = 0;
no02Player.delegate = self;
//No03 and so on...
Obviously this is labourious and bad coding practice. I'd like to instead have the list of files in a Plist and load these into variables that populate just one example of the above code. I'd like to learn how to be DRY with this but have limited experience of loading data from Plists, arrays, dictionaries, etc.
Any help is appreciated, even if it is to point me in the direction of a relevant tutorial.
Thank you.
You can simply place the audio file names in text file using 'new line' separator. And read the file and store the names in an array. To create the URL take the file names dynamically from array as given below
// Read description from text file
NSBundle *audioBundle = [NSBundle mainBundle];
NSString *audioPath = [audioBundle pathForResource:audioFileNames ofType:#"txt"];
NSString *audioContent = [NSString stringWithContentsOfFile:audioPath encoding:NSUTF8StringEncoding error:nil];
// ===========Make an array using audioContent=============
NSArray *audioFiles = [audioContent componentsSeparatedByString:#"\n"];
Use the array to get file names :
NSURL *no01URL = [[NSURL alloc] initFileURLWithPath: [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:#"%#",[audioFiles objectAtIndex:audioCount]] ofType:#"aiff"]];
If your file names are like audio1,audio2.. no need of using all these. Just change in URL like :
NSURL *no01URL = [[NSURL alloc] initFileURLWithPath: [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:#"audio%d",audioCount] ofType:#"aiff"]];
OK for anyone else needing to do this, here's what I ended up with:
//Load location data from Plist file into an Array
NSString *path = [[NSBundle mainBundle] pathForResource:#"Audionodes" ofType:#"plist"];
locationArray = [[NSArray alloc] initWithContentsOfFile:path];
// Create AVAudioPlayers for this view
self.audioPlayerArray = [[NSMutableArray alloc] init];
for (int i = 0; i < [locationArray count]; i++) {
NSString *filename = [[locationArray objectAtIndex:i] valueForKey:#"filename"];
NSString *filetype = [[locationArray objectAtIndex:i] valueForKey:#"filetype"];
int loops = [[[locationArray objectAtIndex:i] valueForKey:#"loops"] intValue];
NSURL *url = [[NSURL alloc]initFileURLWithPath:[[NSBundle mainBundle] pathForResource:filename ofType:filetype]];
AVAudioPlayer *player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
player.delegate = self;
player.numberOfLoops = loops;
player.volume = 0;
[self.audioPlayerArray addObject:player];
[url release];
[player release];
}
Putting the generated players in audioPlayerArray means I can get at them later.

Overwrite with remote .plist a local .plist file

My application loads a local list.plist file at launch.
Then it has a refreshTable button which fetch a remote version of the .plist file from my website.
App Launch
local list.plist loads
user hits refreshList button
local list.plist is overwritten by remote list.plist
local list.plist updated until remote list.plist updates again
Method to initialize data:
//Remote data
list = [[NSMutableArray alloc] initWithContentsOfURL:[NSURL URLWithString:#"http://mywebsite.com/list.plist"]];
NSSortDescriptor *descriptor = [[[NSSortDescriptor alloc] initWithKey:#"name" ascending:YES selector:#selector(localizedCaseInsensitiveCompare:)] autorelease];
sortedList = [[list sortedArrayUsingDescriptors:[NSArray arrayWithObject:descriptor]] retain];
//Local data
NSString *localPath = [[NSBundle mainBundle] pathForResource:#"list" ofType:#"plist"];
localList = [[NSMutableArray alloc] initWithContentsOfFile:localPath];
NSSortDescriptor *localDescriptor = [[[NSSortDescriptor alloc] initWithKey:#"name" ascending:YES selector:#selector(localizedCaseInsensitiveCompare:)] autorelease];
localSortedList = [[localList sortedArrayUsingDescriptors:[NSArray arrayWithObject:localDescriptor]] retain];
This is the method to refresh:
- (void) refreshTable:(id)sender
{
//Remote .plist
list = [[NSMutableArray alloc] initWithContentsOfURL:[NSURL URLWithString:#"http://mywebsite.com/list.plist"]];
NSSortDescriptor *descriptor = [[[NSSortDescriptor alloc] initWithKey:#"name" ascending:YES selector:#selector(localizedCaseInsensitiveCompare:)] autorelease];
sortedList = [[list sortedArrayUsingDescriptors:[NSArray arrayWithObject:descriptor]] retain];
[self.tableView reloadData];
//now write remote plist to local plist
}
After i downloaded the remote plist how can i write over the local plist?
I was thinking to empty the local array containing the local plist and fill it with the remote array and i did it this way:
I solved in the way i thought:
//Remote .plist
list = [[NSMutableArray alloc] initWithContentsOfURL:[NSURL URLWithString:#"http://phillipapps.com/mntlion/list.plist"]];
NSSortDescriptor *descriptor = [[[NSSortDescriptor alloc] initWithKey:#"name" ascending:YES selector:#selector(localizedCaseInsensitiveCompare:)] autorelease];
sortedList = [[list sortedArrayUsingDescriptors:[NSArray arrayWithObject:descriptor]] retain];
NSLog(#"list: %#",list);
[localList removeAllObjects];
[localList addObjectsFromArray:list];
localSortedList = [[localList sortedArrayUsingDescriptors:[NSArray arrayWithObject:descriptor]] retain];
NSLog(#"locallist: %#",localList);
[self.tableView reloadData];
It works, but how can i write over localList with the contents of list?
so … after a view hours in chat we got the problem solved.
- (NSArray*)readPlist
{
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *plistPath = [[documentPaths lastObject] stringByAppendingPathComponent:#"localFile.plist"];
NSFileManager *fMgr = [NSFileManager defaultManager];
if (![fMgr fileExistsAtPath:plistPath]) {
plistPath = [[NSBundle mainBundle] pathForResource:#"template" ofType:#"plist"];
}
return [NSArray arrayWithContentsOfFile:plistPath];
}
- (void)writePlist:(NSArray*)arr
{
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *plistPath = [[documentPaths lastObject] stringByAppendingPathComponent:#"localFile.plist"];
NSFileManager *fMgr = [NSFileManager defaultManager];
if (![fMgr fileExistsAtPath:plistPath])
[fMgr removeItemAtPath:plistPath error:nil];
[arr writeToFile:plistPath atomically:YES];
}
initializing the ivar:
self.plistArray = [self readPlist];
and after loading the new plist from the server you have to call this code:
self.plistArray = [NSArray arrayWithContentsOfURL:[NSURL URLWithString:#"http://mywebsite.com/list.plist"]];
[self writePlist:plistArray]; // e.g. for caching
[self.tableView reloadData];
I do almost the exact thing you're looking for in an application of mine. You can't write to the NSBundle so the steps are something like this:
Try to load plist from cache directory, if it succeeds go to 3.
Load plist from bundle
Check if loaded plist is up to date (or, trigger further steps by the press of a button)
Download new plist
Save to cache directory
The code looks something like this:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cache = [paths objectAtIndex:0];
ratios = [NSDictionary dictionaryWithContentsOfFile:[cache stringByAppendingPathComponent:#"devices.plist"]];
if (ratios == nil) {
ratios = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"devices" ofType:#"plist"]];
}
NSString *device = [[UIDevice currentDevice] machine];
NSDictionary *d = [ratios objectForKey:device];
if (d!=nil) {
pixelInchRatio = [[d objectForKey:#"pixelInchRatio"] doubleValue];
bezelWidth = [[d objectForKey:#"bezelWidth"] doubleValue];
bezelHeight = [[d objectForKey:#"bezelHeight"] doubleValue];
} else if (fetch) {
[[[[RulerDimensionDownload alloc] init] autorelease] startDownload];
}
Then in the downloader it saves like so:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cache = [paths objectAtIndex:0];
[[NSFileManager defaultManager] createDirectoryAtPath:cache withIntermediateDirectories:YES attributes:nil error:nil];
[ratios writeToFile:[cache stringByAppendingPathComponent:#"devices.plist"] atomically:YES];
Some explanations:
The first few lines in each sample, the paths and cache definition, simply get the location of the cache directory for the application. I use this to store the most up-to-date version I'm my plist.
So, in the loading code, I first try to load the plist from the cache directory. If this fails (ratios is null) I then load it from my application bundle (this is the version of the plist that I ship with the app).
After that, I check to see if the plist has the information needed. (the plist has a definition for each device type. If the device isn't in the plist then I know I need to try to update the plist)
If the plist is out of date I start the download using a class I wrote: RulerDimensionDownload. Once it completes the download I save the file into the cache directory. Then, next time the plist needs to be loaded it will be loaded first and the shipped plist will never be looked at. (I also send a notification with the new plist)

Can't figure out about saving files

I am trying to save my object to the file system on an iPad, but I seem to be doing something wrong. Here is how I have archived the object:
NSString *localizedPath = [self getPlistFilePath];
NSString *fileName = [NSString stringWithFormat:#"%#.plist", character.infoName];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:character];
fileName = [fileName stringByReplacingOccurrencesOfString:#" " withString:#"_"];
localizedPath = [localizedPath stringByAppendingPathComponent:fileName];
NSLog(#"File Path: %#", localizedPath);
if(data) {
NSError *writingError;
BOOL wasWritten = [data writeToFile:localizedPath options:NSDataWritingAtomic error:&writingError];
if(!wasWritten) {
NSLog(#"%#", [writingError localizedDescription]);
}
}
Now, this creates a plist file that I can see and read on the file system. When I try to use the following to unarchive it though:
NSError *error;
NSString *directory = [self getPlistFilePath];
NSArray *files = [[NSFileManager defaultManager]contentsOfDirectoryAtPath:directory error:&error];
NSMutableArray *characters = [[NSMutableArray alloc]init];
for(NSString *path in files) {
if(![path hasSuffix:#"plist"]) {
continue;
}
NSString *fullPath = [directory stringByAppendingPathComponent:path];
NSData *data = [NSData dataWithContentsOfFile:fullPath];
IRSkillsObject *object = [NSKeyedUnarchiver unarchiveObjectWithData:data]; // get EXEC_BAD_ACCESS here...
[data release];
[characters addObject:object];
}
I get an EXEC_BAD_ACCESS error.
The IRSkillsObject conforms to the NSCoding protocol. You can see, I commented the line that I get the error on.
I am sure it's something I am doing wrong, but I just can't see it. I have tried to step through with the debugger (placing a break point in the initWithCoder: method of the object) but I don't get any errors then. In fact, it places the data in the object properly as I watch. But once it's done loading the data, it gives the error. I have tried using the retain method, but that doesn't help.
Any help that you can provide would be greatly appreciated!
You are releasing data without allocating it.
NSData *data = [NSData dataWithContentsOfFile:fullPath];
IRSkillsObject *object = [NSKeyedUnarchiver unarchiveObjectWithData:data];
[data release];
So try this:
NSData *data = [[NSData alloc] initWithContentsOfFile:fullPath];
IRSkillsObject *object = [NSKeyedUnarchiver unarchiveObjectWithData:data];
[data release];
When an EXEC_BAD_ACCESS error is found. Usually is because some data has been released but it is still needed in the code.
Maybe there is a property inside your IRSkillsObject not retained in -initWithCoder: