Adding an Attribute to a Core Data Entity - iphone

this has beed discussed alot, but nothing that I found helped me... I just want to add a single attribute to a singe entity. Of cause without loosing my data.
To do that, I followed these steps
But I don't think it worked at all. There are no errors as long as not try to use the new attribute. But in my Core Data Model (when I open the .xcdatamodel in XCode) it's there and even in my NSManagedObject Subclass of the entity, the new attribute is there as a property. But when I try to use it, this happens:
unrecognized selector sent to instance 0x74f8520
or
the entity Name is not key value coding-compliant for the key "isFavoriteName".'
The key "isFavoriteName"is the one I just added.Like I said, I did all the steps. Do I miss something?
I think, that the new Model Version is not being used, because when I delete some attributes in the Model, my app still works and the deleted information are still shown... I have set the current Core Data Model Version the the new one (Step 6).
I hope you can help me!
Nick
EDIT: Do I may have to change something in code as well? Apart from the setting the options when creating persistentStoreCoordinator... Because I have, let's say myApp.xdatamodel and inside of that, i know have myApp.xdatamodel and myApp 2,xdatamodel... but I my code I sill do:
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:#"myApp" withExtension:#"mom"];
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];

That's right-- the page you linked to left out one step that applies in your case. Even though you created a new version of the model, your code is still loading the old one by name.
Don't just change it to load version 2 though. Do this instead:
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:#"myApp" withExtension:#"momd"];
This will look in the momd folder and get whatever the current version is. In this case it will get version 2. If you change the model again in the future, it will get whatever version is current then.

Related

How to open unzip files in a unique folder each time on iOS

On my iOS application I'm unziping files in "app/temp" folder like this:
NSString *unzipFolder = [[CommonFunctions getCachePath] stringByAppendingPathComponent:#"/temp/"];
and once im done with it im deleting item with:
[[NSFileManager defaultManager] removeItemAtPath:unzipFolder error:&e];
Issue is that bcz im creating mulital copy of unzip files some of the files Images name are same and displaying wrong images, and i dont find error on why my deleting function does not work!
IS there any way that i can do unziping of folder on diffrent path for each message that open by user?
Thanks :)
It sounds like all you're asking is how to generate a unique name for your unzipFolder each time.
Just don't use a hardcoded name. Almost anything will do. For example:
NSString *unzipFolderTemplate = [[CommonFunctions getCachePath] stringByAppendingPathComponent:#"temp.XXXXXX"];
char *template = strdup([template fileSystemRepresentation]);
if (mkdtemp(template)) {
NSString *unzipFolder = [NSString stringWithFileSystemRepresentation:template
length:strlen(template)];
free(template);
// do the work
[[NSFileManager defaultManager] removeItemAtPath:unzipFolder error:&e];
}
The nice thing about mkdtemp is that it creates the directory for you, and guarantees there are no race conditions, somehow-left-over directories, or other problems. It's also more secure against, say, someone writing a crack or other jailbreak hack that exploits your code by predicting the path. The downside is, of course, that you have to drop down to C strings (which means an explicit free). But, as I said, there are many possibilities, and almost anything will do.
Also, note that I'm using #"temp.XXXXXX", not #"/temp.XXXXXX/". That's because -[stringByAppendingPathComponent:] already adds any necessary slashes for you (that is, in fact, the whole point of the method), and directory-creation functions don't need a trailing slash, so both of the slashes are unnecessary.
Meanwhile, I'm still a bit confused by what you're trying to do. If you need to keep a unique folder around for each message, and delete the folder when you're done with that message, and you could have multiple messages open at once, you need some way to remember which folder goes with which message.
For that, create an NSMutableDictionary somewhere, and right after the free(template) you'll want to do something like [tempFolderMap addObject:unzipFolder forKey:messageName]. Then, when closing a message, you'll do [tempFolderMap objectForKey:messageName] and use the result to the removeItemAtPath:error: message (and then you can also remove the key from tempFolderMap).

Proper Management Of A Singleton Data Store In IOS With Web Service

I'm currently using a singleton as a data store for my app. I essentially store a number of events that are pulled and parsed from a web service and then added as needed. Each time I make a request from the web service, I parse the results and see if the items already exist. If they do, I delete them and add the updated version provided by the web service.
Everything appeared to be working properly until I fired up the Instruments panel to find out that my system is leaking the objects every time it loads them from the web service (from the second time on). The core method where things appear to be messing up is this one, which is located in my HollerStore singleton class:
- (void)addHoller: (Holler *)h
{
//Take a holler, check to see if one like it already exists
int i = 0;
NSArray *theHollers = [NSArray arrayWithArray:allHollers];
for( Holler *th in theHollers )
{
if( [[th hollerId]isEqualToString:[h hollerId]] )
{
NSLog(#"Removing holler at index %i", i);
[allHollers removeObjectAtIndex:i];
}
i++;
}
[allHollers addObject:h];
}
Quick explanation: I decided to copy the allHollers NSMutableArray into theHollers because it's being updated asynchronously by NSURLConnection. If I update it directly, it results in a crash. As such, I switched to this model hoping to solve the problem, however the Instruments panel is telling me that my objects are leaking. All the counts are exactly the # of items I have in my data set.
From what I can tell removeObjectAtIndex isn't effectively removing the items. Would love to get the thoughts of anybody else out there on three things:
Is my analysis correct that something else must be retaining the individual hollers being added?
Should I be using CoreData or SQLite for storing information pulled from the web service?
Do you know how long data stored in a Singleton should be available for? Until the app is killed?
Update
I think I've found the source, however perhaps someone can provide some clarity on the proper way to do this. I've created a method called parseHoller which takes a dictionary object created through SBJSON and returns my own model (Holler). Here are the last couple lines:
Holler *h = [[[Holler alloc] initFromApiResponse:hollerId
creatorId:creatorId
creatorName:creatorName
creatorImageUrl:creatorImage
comments:comments
attendees:attendees
wishes:wishes
invitees:invites
createdAt:createdAt
text:text
title:title
when:when]autorelease];
//(some other autorelease stuff is here to clean up the internal method)
return h;
I figured that since I'm returning an autoreleased object, this should be fine. Do you see anything wrong with this?
Have you tried to do a retain count on the objects that is leaking? Maybe that could clear up when or where it is being retained.
The code should be
[putObjectHere retainCount];
and then write to an NSLog
Hope it gives you something
Peter

NSManagedObjectModel initWithContentsOfURL returns nil eventhough the modelURL is valid

my NSManagedObjectModel is returning nil eventhough the path is correct.
NSString *modelKey = [NSString stringWithFormat:#"/%#/Model", name];
NSString *modelPath = [((Configuration *)[Configuration shared]) stringEntry:modelKey];
NSURL *modelURL = nil;
if ( ! [modelPath contains:#"://"] ) {
modelPath = PathForBundleResource( modelPath );
modelURL = [NSURL fileURLWithPath:modelPath];
}
NSManagedObjectModel *m = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
NSString *PathForBundleResource(NSString *relativePath)
NSString* resourcePath = [[NSBundle mainBundle] resourcePath];
return [resourcePath stringByAppendingPathComponent:relativePath];
I've reset the simulator, did a clean build but nothing helped.
I'm new to iPhone programming (core data in particular).
Would appreciate any help.
Edit: I've edited the original post regarding the xcdatamodeld file. It wasn't linked up properly initially but now it is and still having the same problem.
Edit 2: Apparently the name of the xcdatamodel had some variations to the name of the xcdatamodel after linkage. It's working now. Feeling so stupid. Don't know how to delete this question.
I had the same problem after I renamed .xcdatamodeld file. The problem was solved by closing and reopening the Xcode client.
I just encountered this issue after changing the case of the name of the .xcdatamodeld file (e.g. refactored "mydatastore.xcdatamodeld" to "MyDatastore.xcdatamodeld") on a case-insensitive filesystem.
The fix includes both of the above answers:
Refactor the data model file to a distinctly different name, e.g. "MyDatastoreTemporary.xcdatamodeld"
Product > Clean
Close XCode. Re-open XCode and the project.
Refactor the data model file back to its final name, e.g. "MyDatastore.xcdatamodeld"
Product > Clean
Close XCode. Re-open XCode and the project.
I tried both of the above answers, however what fixed it for me was removing and re-adding the .xcdatamodeld file from/to the Xcode project. No cleaning was necessary. For some reason adding it back seems to fix the problem.
I resolved the problem moved to trash the model .xcdatamodeld and then added it one more time.
The by far safest way, if you have not yet versioned your model, is to do the following.
Do not rename your xcdatamodeld file.
Instead, create a brand new Data Model file with the new name.
Keep the file empty and quit Xcode
Open up a terminal and cd (change directory) into your old xcdatamodeld directory.
Inside this directory should be a directory ending in xcdatamodel. Change into this directory.
Inside the xcdatamodel directory you will find a file named contents. Copy this file into the same location under your newly named ?.xcdatamodeld/?.xcdatamodel directory.
Open up Xcode and modify your Core Data code to access this new model.
Build and test.
Remove the old xcdatamodeld from your project.
This works with basic models that have no versions.
When I ran the project the first time, I specified the extension as xcdatamodeld. But that failed since, it should be momd. But I passed a nil instead of momd assuming extension won't be mandatory. But with nil, the initWithContentsOfURL failed and when I finally entered momd,it worked fine.

iPhone: Reading a string from a file is returning the wrong results

What I'm doing:
I am reading some data off a file several times while my app runs. I use the following code to do so:
NSString *dataPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"data.txt"];
NSString *data = [NSString stringWithContentsOfFile:dataPath encoding:NSStringEncodingConversionExternalRepresentation error:NULL];
NSArray *components = [data componentsSeparatedByString:#"|||||"];
The first time this is called, it works as expected - I get an array of length 5, each section containing a relevant string.
What goes wrong:
This file is never modified. Yet, when I call the same procedure a second time (or third, fourth etc) I don't get the same result. Instead, an array of length 1 is returned, containing only part of the necessary data.
Why? I can't see any reason for this to go wrong... any help is much appreciated!
Since the file is in you AppBundle this means that you can't modify this file at all.
Are you sure that, where ever this code is called, the autorelease object are retained correctly?
If you call this block of code every time you want this data, it might be an idea to save the results of the first time and use that every time. This will speed things up a bit.
Turns out that the code works fine. The problem was elsewhere in my code, where I was (accidentally) accessing protected directories. As a result, iOS blocked my app from accessing any files at all :o

How to use ManagedObjectID the right way?

What I'm trying is this:
1) Create a new manged object
2) Get it's temporary id with [myMO objectID];
3) Convert that ID to an NSURL, so I can save it for future reference:
NSManagedObjectID *moID = [myMO objectID];
NSURL *url = [moID URIRepresentation];
4) Save the managed object context
5) Some time later, fetch that object using the NSURL as ID
NSManagedObjectID *moID = [[context persistentStoreCoordinator] managedObjectIDForURIRepresentation:url];
And guess what: It does not work. I get an empty-stupid object back from
NSManagedObject *myOldMo = [context existingObjectWithID: moID error:&error];
But...as I said...the ID is temporary when creating an managed object. So it does make sense why this doesn't work at all. I must first save the context, and then I get a persistet ID. The real one. Right?
So is that the way to go?
1) Create the managed object
2) Save the context
3) Get the ID as NSURL
4) any time later, for example on your next birthday, access the managed object with the NSURL ;-)
I try to dream of NSManagedObjectID like a DB id which I can write on some yellow postIt sheet and glue on the middle of my monitor, so I refer back to it after lunch. You know... at least like in the old days where we used databases over telnet and executed SQL commands manually to query order information and stuff like that. The ID was the most important and significant thing, all the time.
But Core Data has this somewhat strange NSManagedObjectID thing.
What are your secret strategies? Do you actually recognize many use cases where you would need that NSManagedObjectID? Or is that something I could easily forget with no pain afterwards?
I'm not sure that it's such a big secret. The documentation describes the way to get permanent IDs for managed objects from the NSManagedObjectContext:
- (BOOL)obtainPermanentIDsForObjects:(NSArray *)objects error:(NSError **)error
http://developer.apple.com/iphone/library/documentation/Cocoa/Reference/CoreDataFramework/Classes/NSManagedObjectContext_Class/NSManagedObjectContext.html#//apple_ref/occ/instm/NSManagedObjectContext/obtainPermanentIDsForObjects:error: