I created an NSArray from a CoreData fetch like so:
self.farSiman = [self.managedObjectContext executeFetchRequest:request error:&error];
In a tableview I used this code to get my custom objects:
Holiday *holiday = [self.dates objectAtIndex:indexPath.row];
cell.nameLabel.text = holiday.name;
But Im now in another viewcontroller, trying to plot the data on a mapkit, so in the plotting method i originally did this because i was getting an array from a plist file. But now my array is of custom Holiday objects so this doesnt work anymore:
NSLog(#"dictionary is %#", self.farSiman);
for (NSDictionary * dict in self.farSiman) {
NSNumber * latitude = [dict objectForKey:#"latitude"];
NSNumber * longitude = [dict objectForKey:#"longitude"];
NSString * storeDescription = [dict objectForKey:#"name"];
NSString * address = [dict objectForKey:#"address"];
NSLog(#"logging location %#", storeDescription);
CLLocationCoordinate2D coordinate;
coordinate.latitude = latitude.doubleValue;
coordinate.longitude = longitude.doubleValue;
MyLocation *annotation = [[MyLocation alloc] initWithName:storeDescription address:address coordinate:coordinate];
[_mapView addAnnotation:annotation];
}
My dictionary log prints out this:
dictionary is (
"<Holiday: 0x838bc80> (entity: Holiday; id: 0x838ca60 <x-coredata://E41B0CCD-2F03-4C4F-B054-18537096771C/Holiday/p1> ; data: <fault>)",
"<Holiday: 0x838e330> (entity: Holiday; id: 0x838ca70 <x-coredata://E41B0CCD-2F03-4C4F-B054-18537096771C/Holiday/p2> ; data: <fault>)"
Which means its an array of holiday objects.
How do I get each object in my for loop since Im using enumeration instead of a traditional for i = 0; i<count; i++?
It looks like you are using a custom object with CoreData, so it will be returning an array of your class.
Does this work:
for (Holiday *holiday in self.farSiman) {
// your code here
// [holiday foo]
}
If CoreData is not using your custom object, it will return an array of NSManagedObject, in which case use this:
for (NSManagedObject *holiday in self.farSiman) {
// your code here
//[holiday valueForKey:#"foo"]
}
Related
Suppose I have this Json :
{ "arrayOfDates" : [ "7-28-2013", "7-29-2013", "7-30-2013"]}
And my object is :
#interface MyObject : NSObject
#property (nonatomic, retain) NSArray* dates;
#end
I tried to map the arrayOfDates with dates.
RKObjectMapping* mapping = [RKObjectMapping mappingForClass:[MyObject class]];
[mapping addAttributeMappingsFromDictionary:#{#"arrayOfDates" : #"dates"}];
NSDateFormatter *dateFormatter = [NSDateFormatter new];
[dateFormatter setDateFormat:#"MM-dd-yyyy"];
mapping.preferredDateFormatter = dateFormatter;
The mapping result was an array of NSString !
Is that a way to get an array of NSDate instead of NSString ?
You can't get RestKit to do it. Instead, iterate over dates in the completion block called by RestKit and use your formatter to convert the strings, then update dates.
RestKit usually translates the string to a date if the destination property is an NSDate, but in your case it's an array so RestKit doesn't know that it should be transformed.
I came across this answer trying to solve a similar problem. I found a way to get RestKit to do this using a custom RKValueTransformer.
RKObjectMapping* objectMapping = [RKObjectMapping mappingForClass:[MyObjectWithAnNSArrayProperty class]];
RKAttributeMapping* datesAttributeMapping = [RKAttributeMapping attributeMappingFromKeyPath:#"arrayOfDates" toKeyPath:NSStringFromSelector(#selector(myArrayOfDates))];
datesAttributeMapping.valueTransformer = [RKBlockValueTransformer
valueTransformerWithValidationBlock:^BOOL(__unsafe_unretained Class sourceClass, __unsafe_unretained Class destinationClass)
{
// We transform a `NSArray` into another `NSArray`
return ([sourceClass isSubclassOfClass:[NSArray class]] &&
[destinationClass isSubclassOfClass:[NSArray class]]);
}
transformationBlock:^BOOL(id inputValue, __autoreleasing id *outputValue, Class outputValueClass, NSError *__autoreleasing *error)
{
// Validate the input and output
RKValueTransformerTestInputValueIsKindOfClass(inputValue, [NSArray class], error);
RKValueTransformerTestOutputValueClassIsSubclassOfClass(outputValueClass, [NSArray class], error);
NSArray* inputValueArray = inputValue;
NSMutableArray* result = [[NSMutableArray alloc] initWithCapacity:inputValueArray.count];
// Convert strings to dates
for (NSString* inputDate in inputValueArray)
{
[result addObject:RKDateFromString(inputDate)];
}
// Get a non-mutable copy
*outputValue = [result copy];
return YES;
}];
[objectMapping addPropertyMapping:datesAttributeMapping];
After parsing a XML File,i want to create dynamic objects like textbox and buttons based on the contents of xml.
I have parsed my xml and retrieved the data.
I have created a seperate class for XMLParser and made the call in my vieDidload method.
Is it possible to call a method in my mainViewController class from my XMLParser class to create and the dynamic objects.
You can create your own class which will read the parsed value and based on that you go on to create all the GUI Objects.That is not very difficult. Even you can add binding, connections, constraints etc.
I actually did same thing while creating a framework for my project. I cant post the code as its copyright but I can share some of the hits. One basic hint I have mentioned.
well... you can do it with a NSMutableDictionary.
OR you can fill objects that you modeled before from xml
basically just alloc init the existing object and set its properties:
example:
//parse xml
NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path]];
parser.delegate = (id<NSXMLParserDelegate>)self;
[parser parse];
e.g. company objects
//callback from parser
- (void)didStartFirmaWithParser:(NSXMLParser*)parser andAttributes:(NSDictionary*)dict {
[[self __didStartEntity:#"RLStoreFirma" withParser:parser] didStartFirmaWithParser:parser andAttributes:dict];
}
//general callback, sets the parsers delegate to THIS new object which then gets filled
- (id)__didStartEntity:(NSString*)name withParser:(AQXMLParser*)parser {
NSEntityDescription *entity = [[store.managedObjectModel entitiesByName] objectForKey:name];
M42StoreEntry *entry = (id)[[NSManagedObject alloc] initWithEntity:entity insertIntoManagedObjectContext:store.managedObjectContext];
entry.store = self->store;
parser.delegate = entry;
return entry;
}
the object that is to be filled
#import "RLStoreFirma(info).h"
#implementation RLStoreFirma (info)
- (void)didStartFirmaWithParser:(AQXMLParser*)parser andAttributes:(NSDictionary*)dict {
}
- (void)didEndFfkbWithParser:(AQXMLParser*)parser {
self.fkb = currentXMLCharacters;
}
- (void)didEndFfirWithParser:(AQXMLParser*)parser {
self.name = currentXMLCharacters;
}
- (void)didEndFirmaWithParser:(AQXMLParser*)parser {
if(!self.name) {
self.name = self.fkb;
}
[self didEndMainWithParser:(AQXMLParser*)parser];
}
generating new objects at runtime isnt allowed with the iphone sdk / its objc runtime
#pragma mark parser magic
- (SEL) __startSelectorForElement: (NSString *) element
{
NSString * str = nil;
NSMutableString * eSel = [NSMutableString stringWithString: [[element substringWithRange: NSMakeRange(0,1)] uppercaseString]];
if ( [element length] > 1 )
{
[eSel appendString: [element substringFromIndex: 1]];
NSRange range = [eSel rangeOfString: #"-"];
for ( ; range.location != NSNotFound; range = [eSel rangeOfString: #"-"] )
{
NSString * cap = [[eSel substringWithRange: NSMakeRange(range.location+1, 1)] uppercaseString];
range.length += 1;
[eSel replaceCharactersInRange: range withString: cap];
}
}
str = [NSString stringWithFormat: #"didStart%#WithParser:andAttributes:", eSel];
return ( NSSelectorFromString(str) );
}
syntactic sugar to make NSParser nicer.. I cant give you ALL code but I think this might help - i hope
This seems to be a fairly common problem, but the solutions that I have looked at do not solve the error. I am trying to read an NSMutableArray from a JSON file. Many of the suggestions I have seen involve using mutableCopy or [NSMutableArray arrayWithArray:] but both of these solutions do not fix the problem when using the call replaceObjectAtIndex:withObject: seen below. Please let me know if you have any advice on how to solve this problem.
EDIT: I would also like to add that the inventory list is an NSMutableArray of NSMutableArray objects.
The exact error reads:
Terminating app due to uncaught exception 'NSInternalInconsistencyException',
reason: '-[__NSCFArray replaceObjectAtIndex:withObject:]:
mutating method sent to immutable object'
I have the property defined as follows at the top of my implementation file:
NSMutableArray *inventoryData;
I am trying to read it from a JSON file as follows:
- (void)readJSON
{
//Code to get dictionary full of saves from JSON file (overworld.json) - includes the file path on the ipad as well as
//the dictionary itself
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *localPath = [[NSString alloc] initWithString:[documentsDirectory stringByAppendingPathComponent:#"savedPaintGameData.json"]];
NSString *filePath = [localPath mutableCopy];
NSError *e = nil;
// Read data from file saved previously - read the raw data from the path, then parse it into a dictionary using JSONObjectWithData
NSData *RawJSON = [NSData dataWithContentsOfFile:filePath options:NSDataReadingMappedIfSafe error:&e];
if (RawJSON == nil) {
[self saveGameInitialize];
} else {
NSMutableDictionary *localDictionary = [[NSMutableDictionary alloc] initWithDictionary:[NSJSONSerialization JSONObjectWithData:RawJSON options:NSJSONReadingAllowFragments error:&e]];
NSMutableDictionary *savedDataDictionary = [localDictionary mutableCopy];
//inventoryData = [[savedDataDictionary objectForKey:#"inventory"] mutableCopy];
inventoryData = [NSMutableArray arrayWithArray:[savedDataDictionary objectForKey:#"inventory"]];
}
}
I am then trying to replace an object at the given index of the NSMutableArray as seen here:
- (void)setInventoryData: (NSString *) colorKey: (int) change
{
// Check if inventory already contains the paint and change the amount
bool foundPaint = false;
int newAmount = 100; // Magic number prevents crashing # removal check
for (int i = 0; i < [inventoryData count]; i++) {
NSMutableArray *object = [inventoryData objectAtIndex:i];
if ([[object objectAtIndex:0] isEqualToString:colorKey]) {
newAmount = [[object objectAtIndex:1] integerValue] + change;
[[inventoryData objectAtIndex:i] replaceObjectAtIndex:1 withObject:[NSNumber numberWithInt:newAmount]];
foundPaint = true;
break;
}
}
if (newAmount == 0) {
[self removeInventoryColor:colorKey];
}
}
The issue appears to be surround the depth at which you are working... the mutable versions of containers you are creating only apply to that "level". You are later indexing into that level (i.e. accessing a container one level deeper) which is still immutable. Try passing the NSJSONReadingMutableContainers option when you first unserialize the JSON:
NSUInteger jsonReadingOptions = NSJSONReadingAllowFragments | NSJSONReadingMutableContainers;
NSMutableDictionary *localDictionary = [[NSMutableDictionary alloc] initWithDictionary:[NSJSONSerialization JSONObjectWithData:RawJSON options:jsonReadinOptions error:&e]];
hi at all ,I've this code :
+(NSArray *)splatterUrls
{
NSString *jsonString = [ ApiMethod jsonOfStores];
NSDictionary *results =[jsonString objectFromJSONString];
NSArray *movieArray = [results objectForKey:#"Seasons"];
//int i=0;
// Search for year to match
for (NSDictionary *movie in movieArray)
{
NSNumber *idSplatterMovie = [movie objectForKey:#"Id"];
// NSLog(#" %#", idSplatterMovie );
NSArray *try = [movie objectForKey:#"Episodes"];
// NSLog(#"%#", try);
for (NSDictionary *op in try)
{
if([idSplatterMovie integerValue] == 46)
{
//i++;
NSArray *movieArrayString = [op objectForKey:#"Url"];
// NSLog(#" %#", movieArrayString);
return movieArrayString;
}
}
}
}
I want to return movieArrayString with all his objects and how many object contains in it. I think that I should use this method : + (id)arrayWithObjects:(const id *)objects count:(NSUInteger)count. It's possible? If yes, can you tell me how can use it?
Thank you so much!
by the way , i have to call splatterUrls method and implement in home.m that it is :
- (void)viewDidLoad
{
[super viewDidLoad];
NSArray *urlSplatter= [GetSplatterUrlsMovie splatterUrls];
NSLog(#" %#", urlSplatter);
}
Looks good as it is to me.
Do this to return your movies array, array will be equal to your movies array:
NSArray *array = [self splatterUrls];
Then to get the count/number of objects in your array do this, i is equal to the number of objects in the array:
int i = [array count];
What is the problem ??
You return a NSarray ... call the method count on your NSarray object!
Im working on a simple "point based" app.
under settings the user set´s the number of points needed to get a "goodie" using a slider.
-(IBAction) sliderChanged: (id)sender {
UISlider *slider = (UISlider *) sender;
int progressAsInt =(int)(slider.value +0.5);
NSString *newText = [[NSString alloc] initWithFormat:#"%d",progressAsInt];
sliderLabel.text = newText;
[newText release];
this works fine, but how so i store the slider value in my core data model, and how do make my slider show the stored value when view loads.
hope u can help me out :-D
Hey gerry3 i found my error. i never set my toD-object in my settingsViewController, with:
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:[NSEntityDescription
entityForName:#"ToDo" inManagedObjectContext:_context]];
NSError *error = nil;
NSArray *array = [_context executeFetchRequest:request error:&error];
if (array == nil)
{
// Deal with error...
}
if(array.count > 0){
toDo = [array objectAtIndex:0];
} else { // no one to fetch - generate one
toDo = [NSEntityDescription
insertNewObjectForEntityForName:#"ToDo"
inManagedObjectContext:_context];
[toDo retain];
your code works like a charm .....
Thanks
Skov
The key here is that Core Data stores numeric attributes (e.g. integers, floats, etc) as NSNumber objects.
Say that your entity is called Record and it has a integer attribute called 'progress'.
If you create a managed object instance of Record named 'record', then you can set its progress like this:
[record setValue:[NSNumber numberWithInteger:progressAsInt] forKey:#"progress"];
When you want to update your view with the value from your model (usually in viewWillAppear:), you can get its progress like this:
NSNumber *progressNumber = [record valueForKey:#"progress"];
slider.value = [progressNumber floatValue];
Alternatively, if you generate the class files for the Record entity, you can just do:
record.progress = [NSNumber numberWithInteger:progressAsInt];
and:
slider.value = [record.progress floatValue];