Editing an element of NSArray in NSMutableArray - nsmutablearray

I'm creating NSMutableArray here:
NSMutableArray *DataBase = [NSMutableArray arrayWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:DataKey] ];
And adding object here:
[DataBase insertObject: [NSArray arrayWithObjects:#"st", #"s", #"Con, #"S1", #"S2", #"S3", #"S4",#"T1",#"T2",#"T3",#"T4", nil] atIndex: 0];
I want to edit one first element of first object. I've tried this [DataBase objectAtIndex:1][0], do i need something like this [DataBase replaceObjectAtIndex:1] withObject:TempArray]; or there is a better way?

Related

Unable to add object to NSMutableArray with TFHpple

I tried to add object to my mutable array using TFHlle parse html in this code but it return null for object in my array, but in the for loop, I log the result of '[element objectForKey:#"title"]' and it returns result I want.
How I can add the result of element [objectForKey:#"title"] to my array?
TFHpple *htmlParseResult = [TFHpple hppleWithHTMLData:self.responseData];
NSString *coursesXpathQueryString = #"//h2[#class='main']/a";
NSArray *coursesNodes = [htmlParseResult searchWithXPathQuery:coursesXpathQueryString];
NSMutableArray *fitCourse = [[NSMutableArray alloc] initWithCapacity:0];
for (TFHppleElement *element in coursesNodes) {
[fitCourse addObject:[element objectForKey:#"title"]];
}
I think
NSArray *coursesNodes = [htmlParseResult searchWithXPathQuery:coursesXpathQueryString];
should be change to:
NSArray *coursesNodes = [NSArray arrayWithArray:[htmlParseResult searchWithXPathQuery:coursesXpathQueryString]];
I am not sure this works but you can try.

Saving array of images in core data as transformable

I want to add my imageArray into coredata as transformable but this is not storing properly.
My save button coding.
- (IBAction)saveButton:(id)sender {
NSManagedObjectContext *context = [self managedObjectContext];
NSManagedObject *newEntry = [NSEntityDescription insertNewObjectForEntityForName:#"FoodInfo" inManagedObjectContext:context];
NSAttributeDescription *messageType = [[NSAttributeDescription alloc] init];
[messageType setName:#"photos"];
[messageType setAttributeType:NSTransformableAttributeType];
[imagesForShow addObject:messageType];
NSError *error = nil;
if (![context save:&error]) {
NSLog(#"Unable to save context for class" );
} else {
NSLog(#"saved all records!");
[context save:nil];
}
//[newEntry setValue:imagesForShow forKey:#"images"];
}
Here 'imagesForShow' is my array of images.
When iam going to fetch this image array , this showing nil
- (void)viewDidLoad {
[super viewDidLoad];
NSManagedObjectContext *context = [self managedObjectContext];
NSFetchRequest *request = [[NSFetchRequest alloc]initWithEntityName:#"FoodInfo"];
[request setReturnsObjectsAsFaults:NO];
arrayForPhotos = [[NSMutableArray alloc]initWithArray:[context executeFetchRequest:request error:nil]];
// Do any additional setup after loading the view.
}
What I am doing wrong with this code. Thanks.
In your save code:
NSManagedObjectContext *context = [self managedObjectContext];
NSManagedObject *newEntry = [NSEntityDescription
insertNewObjectForEntityForName:#"FoodInfo"
inManagedObjectContext:context];
NSAttributeDescription *messageType = [[NSAttributeDescription alloc] init];
[messageType setName:#"photos"];
[messageType setAttributeType:NSTransformableAttributeType];
[imagesForShow addObject:messageType];
I can't even figure out what this is supposed to do. It's completely wrong. You should never be allocating an instance of NSAttributeDescription unless you are constructing a Core Data model on the fly-- which you are not doing and which almost nobody ever does. Creating the new entry is OK. The rest, I don't know. You said that imagesForShow is your array of images, so I don't know why you're also adding an attribute description to the array.
In a more general sense, if newEntry has a transformable attribute named photos and imagesForShow is an NSArray of UIImage objects, then you could do this:
[newEntry setValue:imagesForShow forKey:#"photos"];
This is similar to a line that you have commented out, though it's not clear why it's commented out.
But whatever you do get rid of the code creating the NSAttributeDescription.

NSFetchedResultsController with NSDictionaryResultsType in NSFetchRequest

I have been looking over this issue since a week and haven't got any solution, so I thought to make the question more generalized, may be it will help the users to look into it and give me a solution.
Scenario:
I have an expense tracking iOS Application and I have a view controller called "DashBoardViewController" (table view controller - with FRC) which would basically categorize my expenses/incomes for a given week, a month, or year and display it as the section header title for example : (Oct 1- Oct 7, 2012) and it shows expenses/incomes ROWS and related stuff according to that particular week or month or year.
My Question:
What I want to accomplish is :
Show Distinct Results based on "Category" attribute of "Money" entity and calculate "Sum" based on the attribute.
But, my view controller called "dashboard view controller" is filled with NSFetchedResultsController with section name key path as "type" that can be an expense or an income. In order to get Distinct results, I shall use Result type as NSDictionaryResultsType in my fetch request which will give me unique results but FRC fails, it doesn't work with that. So, how will I get my section names then? I have posted the code below.
EDIT - BASED ON MARTIN'S SUGGESTION
- (void)userDidSelectStartDate:(NSDate *)startDate andEndDate:(NSDate *)endDate
{
AppDelegate * applicationDelegate = (AppDelegate *) [[UIApplication sharedApplication] delegate];
NSManagedObjectContext * context = [applicationDelegate managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// Edit the entity name as appropriate.
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Money" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
// Set the batch size to a suitable number.
[fetchRequest setFetchBatchSize:20];
NSPredicate *predicateDate = [NSPredicate predicateWithFormat:#"(date >= %#) AND (date <= %#)", startDate, endDate];
[fetchRequest setPredicate:predicateDate];
// Edit the sort key as appropriate.
typeSortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"type" ascending:YES];
dateSortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"date" ascending:YES];
if(self.choiceSegmentedControl.selectedIndex == 0)
{
choiceSortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"cat" ascending:NO];
}
if(self.choiceSegmentedControl.selectedIndex == 1)
{
choiceSortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"vendor" ascending:NO];
}
if(self.choiceSegmentedControl.selectedIndex == 2)
{
choiceSortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"paidBy" ascending:NO];
}
NSArray * descriptors = [NSArray arrayWithObjects:typeSortDescriptor, dateSortDescriptor,choiceSortDescriptor, nil];
[fetchRequest setSortDescriptors:descriptors];
[fetchRequest setIncludesSubentities:YES];
NSError * anyError = nil;
NSArray *propertiesToFetch = [[NSArray alloc] initWithObjects:
[entity.propertiesByName objectForKey:#"cat"],
nil];
[fetchRequest setReturnsDistinctResults:YES];
[fetchRequest setResultType:NSDictionaryResultType];
[fetchRequest setPropertiesToFetch:propertiesToFetch];
NSArray * objects = [context executeFetchRequest:fetchRequest error:&anyError];
for (NSDictionary *d in objects)
{
NSLog(#"NSDictionary = %#", d);
}
NSSet *uniqueSet = [NSSet setWithArray:[objects valueForKey:#"cat"]];
uniqueArray = [NSMutableArray arrayWithArray:[uniqueSet allObjects]];
self.categoryArray = uniqueArray;
if(_fetchedResultsController)
{
[_fetchedResultsController release]; _fetchedResultsController = nil;
}
_fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:context sectionNameKeyPath:#"type" cacheName:nil];
//self.fetchedResultsController.delegate = self; in order to stop "change tracking"
if(![_fetchedResultsController performFetch:&anyError])
{
NSLog(#"error fetching:%#", anyError);
}
[fetchRequest release];
//Finally you tell the tableView to reload it's data, it will then ask your NEW FRC for the new data
[self.dashBoardTblView reloadData];
self.startDate = startDate;
self.endDate = endDate;
}
With this code, SECTION NAME KEY PATH is not working and it's complaining that the object will be placed in unnamed section.
A fetched results controller does not support change tracking (i.e. the FRC delegate is set) in combination with a fetch request with NSDictionaryResultType.
The reason is documented with the setIncludesPendingChanges: function:
Special Considerations
A value of YES is not supported in conjunction
with the result type NSDictionaryResultType, including calculation of
aggregate results (such as max and min). For dictionaries, the array
returned from the fetch reflects the current state in the persistent
store, and does not take into account any pending changes, insertions,
or deletions in the context.
Change tracking of the FRC implies includesPendingChanges = YES for the fetch request, and that does not work with NSDictionaryResultType.
One workaround could be to use a FRC without change tracking, so you do not set the FRC delegate. But that means that to update your table view, you have to
save the managed object context, and
call performFetch on the FRC and reloadData on the table view.
Another workaround could be to use the FRC to fetch all sections and rows without the sum aggregation, and use the results to compute new table rows with the aggregation in memory (e.g. in controllerDidChangeContent).
UPDATE: (From the discussion) Another important point is that if you use a fetch request with NSDictionaryResultType, then the sectionNameKeyPath of the fetched results controller must be included in the propertiesToFetch of the fetch request.

Saving an object to array using NSMutableDictionary

I have been trying to add an object as an NSMutableDictionary to my array, which I am accessing from another view, and It doesn't seem to work. I want to be able to store the data in a plist which I access from a NSDictionary.
-(void)saveAlarm:(id)sender {
// Adding object for alarm to AlarmViewController
alarmArrayCopy = alarmViewController.alarmsTime;
NSMutableDictionary *newAlarm = [[NSMutableDictionary alloc] init];
[newAlarm setValue:labelTextField.text forKey:LABEL_KEY];
[newAlarm setValue:alarmPicker.date forKey:TIME_KEY];
[alarmArrayCopy addObject:(newAlarm)];
// Dismissing and tiding up.
[self.navigationController dismissModalViewControllerAnimated:YES];
[newAlarm release];
}
UPDATE: How do I add an NSDictionary to my plist database (my db is an array)?
Here is some new code, I updated the NSMutableDictionary to NSDictionary because in my plist you can only have normal dictionaries not a mutable one. But now it crashed and gives me a Thread 1:Program received signal: "SIGABRT".
NSString *path = [[NSBundle mainBundle] bundlePath];
NSString *finalPath = [path stringByAppendingPathComponent:#"data.plist"];
// Adding object for alarm to AlarmViewController
NSDictionary *newAlarm = [[NSDictionary alloc] init];
[newAlarm setValue:labelTextField.text forKey:LABEL_KEY];
[newAlarm setValue:[NSString stringWithFormat:#"%#", alarmPicker.date] forKey:TIME_KEY];
[newAlarm writeToFile:finalPath atomically:NO];
or
-(IBAction)saveAlarm:(id)sender {
// Adding object for alarm to AlarmViewController
NSString *time = [NSString stringWithFormat:#"%#", alarmPicker.date];
NSString *label = [NSString stringWithFormat:#"%#",labelTextField.text];
NSDictionary *newAlarm = [[NSDictionary alloc] initWithObjectsAndKeys:label, LABEL_KEY,time, TIME_KEY, nil];
self.alarmArrayCopy = alarmViewController.alarmsTime;
[alarmArrayCopy addObject:(newAlarm)];
// Dismissing and tiding up.
[newAlarm release];
[self.navigationController dismissModalViewControllerAnimated:YES];
}
First, you should use setObject:forKey: method for adding objects to NSMutableDictionary. Second, you should use initWithObjectsAndKeys: method if you are using NSDictionary.
The setValue:forKey is a method of the Key Value Coding protocol. That was described at here “
Where's the difference between setObject:forKey: and setValue:forKey: in NSMutableDictionary?
”
So, you should do that,
NSDictionary *newAlarm = [[NSDictionary alloc] initWithObjectsAndKeys:
labelTextField.text, LABEL_KEY,
alarmPicker.date, TIME_KEY, nil];
[newAlarm setValue:alarmPicker.date forKey:TIME_KEY];
I am not quite sure, but I guess your error is because you can't send an instance of NSDate object to setValue:forKey method. You may use either setObject:forKey or change NSDate to NSString by [NSString stringWithFormat:"%#", alarmPicker.date].
Hope that helps.

after i add new data in core data collection it can't be saved (multiply validation error occured)

The code bellow add to Core data issues, but after it added, I can't save with error (multiply validation error occured)
MySQLIXC *ixcDatabase = [[MySQLIXC alloc] init];
NSArray *destinationsForSaleList = [ixcDatabase destinationsForSaleList:carrier];
NSFetchRequest *request1 = [[[NSFetchRequest alloc] init] autorelease];
[request1 setEntity:[NSEntityDescription entityForName:#"DestinationsList"
inManagedObjectContext:managedObjectContext]];
for (NSDictionary *destinationsForSale in destinationsForSaleList) {
NSManagedObject *object1 = [NSEntityDescription
insertNewObjectForEntityForName:#"DestinationsList"
inManagedObjectContext:managedObjectContext];
NSLog(#"Moc: %#",managedObjectContext);
[object1 setValue:#"y" forKey:#"weAreSoldIt"];
// changeDate
NSString *chdate = [destinationsForSale objectForKey:#"chdate"];
NSDateFormatter *changeDate = [[[NSDateFormatter alloc] init] autorelease];
[object1 setValue:[changeDate dateFromString:chdate] forKey:#"changeDate"];
NSLog(#"Carrier :%# Destination name:%#",carrier, destinationsForSale);
//Country
[object1 setValue:[destinationsForSale objectForKey:#"country"] forKey:#"country"];
//rate
NSNumberFormatter *rate = [[[NSNumberFormatter alloc]init ]autorelease];
[object1 setValue:[rate numberFromString:[destinationsForSale objectForKey:#"price"]] forKey:#"rate"];
Unfortunately I can't fix a bug by the way which u propose bellow.
Bcs Entity DestinationList must have relations with Entity Carriers by project understanding.
That is how I try to fix it:
[objectDestinationList setValue:objectCarrier forKey:#"carrier"];
I was send to method my carrier object as object, but it doesn't work.
In this case, I don't know how is a way to fix it around. Bcs I see error, but don't see case why error is start.
Do u know a simple code to correct add relationships to Entity? All what I catch around internet is a core data book ,my Marcus Zarra and his very hard to understanding example. His showing a complex solution, I can understand it, but using programming style which not very easy for me at this moment (according my one month experience in cocoa programming ;)
Here is additional information: How I create Carrier instance. I have managedObjectContext, which I receive to class from AppDelegate.
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
[request setEntity:[NSEntityDescription entityForName:#"Carrier"
inManagedObjectContext:managedObjectContext]];
NSManagedObject *carrier = [managedObjectContext executeFetchRequest:request error:&error]
by the same way I prepare NSManagedObject for DestinationsList Entity.
After that I add all values to NSManagedObject for destinationsList, I have to make relationship between Carrer NSManagedObject and destinationsList. In this case I have trouble. Bellow is how I try to update relationship for Carrier entity:
NSSet *newDestSet = [NSSet setWithObjects:objectDestination,nil];
[objectCarrier setValue:newDestSet forKey:#"destinationsList"];
finally I have 2010-11-03 21:22:56.968 snow[20301:a0f] -[NSCFArray initialize]: unrecognized selector sent to instance 0x1c44e40
Bellow is my class interface deescription:
#interface InitUpdateIXC : NSObject {
NSInteger destinationType;
}
-(void) updateCarrierList:(NSManagedObjectContext *)managedObjectContext;
-(void)updateDestinationList:(NSManagedObjectContext *)managedObjectContext
forCarrier:(NSString *)carrierName
forCarrierObject:(NSManagedObject *)objectCarrier
destinationType:(NSInteger)destinationType;
#end
Yep, bellow in answer present correct model, but some different is here.
At first, i don't have separate class for Entity as u present in you model. My current class is just NSManagedObject
In second, relationship "carrier" is non-optional for Entity DestinationsList.
SOLUTION AND ERROR DESCRIPTION:
In case of trouble, what happened with my code:
When i try to add setValue forKey with back relationship from DestinationsList to Carrier, i forget that NSManagmentObject return every time array, not just object.
This is a reason why i receive error about array init problem.
Solution is not sent Carrier object to method, bcs for me was too hard to extract from array correct object without key value. I was using a predicate access to extract object to array and lastObject function to extract correct object from array. After that i set accroding value and everything working fine.
A solution not look like cocoa-style, so better way is refactor it in future, any suggestion wellcome.
Here is appropriate code:
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
[request setEntity:[NSEntityDescription entityForName:#"Carrier"
inManagedObjectContext:managedObjectContext]];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"name =%#",carrierName];
[request setPredicate:predicate];
NSError *error = nil;
NSArray *currentCarriers = [managedObjectContext executeFetchRequest:request error:&error];
[objectDestination setValue:[currentCarriers lastObject] forKey:#"carrier"];
Try adding something like this for you 'save'
NSError *error = nil;
if (![managedObjectContext save:&error])
{
// Handle the error.
NSLog(#"Failed to save to data store: %#", [error localizedDescription]);
NSArray* detailedErrors = [[error userInfo] objectForKey:NSDetailedErrorsKey];
if(detailedErrors != nil && [detailedErrors count] > 0)
{
for(NSError* detailedError in detailedErrors)
{
NSLog(#" DetailedError: %#", [detailedError userInfo]);
}
}
else
{
NSLog(#" %#", [error userInfo]);
}
}
At least, then you can see what the multiple errors are. If you post those, someone may be able to offer more help.
One thought, though, is that there is something buggy about your data model - like non-optional attribute with no value, etc.
If you create NSManagedObject subclassed Carrier and DestinationsList, then in Carrier.h you should have some method declarations like this. (Assuming that Carrier to-many DestinationsList is called 'destinationsLists'.)
#interface Carrier (CoreDataGeneratedAccessors)
- (void)addDestinationsListsObject:(Run *)destinationsList;
- (void)removeDestinationsListsObject:(Run *)destinationsList;
- (void)addDestinationsLists:(NSSet *)destinationsLists;
- (void)removeDestinationsLists:(NSSet *)destinationsLists;
#end
Once these are declared, you should be able to add a DestinationsList to a Carrier with a line like this:
[myCarrier addDestinationsListsObject:myDestinationsList];
Not seeing your full data model, it is difficult to know what is happening and what would help fix it.
Do you have something like this for your model definition?

Resources