NSMutableArray sorting - objective-c

I have 5 NSMutableArrays in cell. I need to sort cells by one value.
Example I need to sort cell by time.
[MyArray1 sortUsingSelector:#selector(compare:)];
but how I will be with other 4 NSMutableArray in cell?

It's not a good idea to store data for your cells in 5 arrays, don't separate them; create a data container class, store all values for each cell inside one data container object and then you can sort your array with data containers by one of the values.
e.g.:
DataContainer.h:
#interface DataContainer : NSObject
{
NSDate *date1;
NSDate *date2;
NSString *upperTitle;
NSString *mainTitle;
NSString *subtitle;
}
#property (nonatomic, strong) NSDate *date1;
#property (nonatomic, strong) NSDate *date2;
#property (nonatomic, strong) NSString *upperTitle;
#property (nonatomic, strong) NSString *mainTitle;
#property (nonatomic, strong) NSString *subtitle;
#end
DataContainer.m:
#implementation DataContainer
#synthesize date1, date2, upperTitle, mainTitle, subtitle;
#end
Then you can create your DataContainer's (one for each cell) and store them in one NSMutableArray.
e.g.:
DataContainer *container = [[DataContainer alloc] init];
[container setDate1:[NSDate date]];
[container setMainTitle:#"blahblah"];
///...
[cellArr addObject:container];
To sort this array, use:
cellArr = [cellArr sortedArrayUsingComparator:^(id cont1, id cont2) {
return [[(DataContainer *) cont1 date1] compare:[(DataContainer *) cont2 date1]];
}];
and then use them in your cellForRowAtIndexPath:
DataContainer *container = [cellArr objectAtIndex:indexPath.row];
//container.date1, container.date2, container.upperTitle, container.mainTitle and container.subtitle are the values that you need for your cell.
Notice that this code is suitable if you're using ARC (Automatic Reference Counting) for your project; if you're not using ARC, then you need to change strong to retain in property definitions and add release's to needed places to avoid memory leaks.

I agree with Andrey. You stick everything from your arrays in containers and then you sort the containers.
Your container should have as members everything you store in one cell (date, time, text, text2, Englis/mathematic, etc).
And then you sort the cell container array.
cellArr = [cellArr sortedArrayUsingComparator:^(id cont1, id cont2) {
// if date in container 1 is earlier than in container 2
return (NSComparisonResult)NSOrderedDescending;
// if date is later
return (NSComparisonResult)NSOrderedAscending;
// if none of the above
return (NSComparisonResult)NSOrderedSame;
}];

Related

Using MagicalRecord, how do I get data out of NSArray and into a NSManagedObject?

I am using MagicalRecord to work with Core Data objects. I am having problems with retrieving Core Data objects using the NSArray that MR puts them into... I can't seem to get the data out of the array and into a NSManagedObject so I can work with it. Here is my code:
// create the predicate
NSArray *apptDataArray = [NSMutableArray new];
NSPredicate *predicate = ([NSPredicate predicateWithFormat:#"((aStartTime > %#) AND (aStartTime <= %#))", startDate, endDate]);
// find all appointments with that selected date
apptDataArray = [AppointmentInfo MR_findAllWithPredicate:predicate];
// now find the appointments for the selected date and put them in the schedule
if(apptDataArray.count > 0) {
for (NSManagedObject *AppointmentInfo in apptDataArray) {
NSLog(#"\n\n-->apptDataArray: %#", apptDataArray);
}
}
This is the definition for AppointmentInfo which is in a different class:
#interface AppointmentInfo : NSManagedObject
#property (nonatomic, retain) NSDate * aStartTime;
#property (nonatomic, retain) NSDate * aEndTime;
#property (nonatomic, retain) NSString * aServiceTech;
#property (nonatomic, retain) NSString * aApptKey;
#property (nonatomic, retain) NSDate *aShortDate;
Somehow, I need to get to the data which is in the returned array and place it in AppointmentInfo. I have tried all kinds of permutations, looked in Google and SO, but I couldn't find anything. I'm stumped! How do I do it?
I am not sure if I understand your problem correctly, but
the result apptDataArray of the fetch request is just an array of AppointmentInfo objects, so you can access individual objects with
AppointmentInfo *appt = [apptDataArray objectAtIndex:i]; // 0 <= i < apptDataArray.count
or enumerate all objects of the result array with
for (AppointmentInfo *appt in apptDataArray) {
NSLog(#"startTime=%#, endTime=%#", appt.aStartTime, appt.aEndTime);
}

What does this warning mean in Xcode?

I have a resource which is fetched from a JSON API.
The JSON is parsed into a NSDictionary which, in this case is called game.
I'm creating a new instance of my Game class based on the attributes from the JSON.
Game class has a property called userRegistered which is defined as follows:
// in Game.h
#interface
#property (nonatomic, assign) BOOL userRegistered;
// elsewhere in my code I have
Game *newGame = [[Game alloc] init];
newGame.userRegistered = ([game objectForKey:#"user_registered"] > 0);
The "user_registered" key in the dictionary will always be either 1 or 0.
Xcode warns me the I have -
warning: Semantic Issue: Incompatible integer to pointer conversion passing 'int' to parameter of type 'BOOL *' (aka 'signed char *')
Can someone please explain the issue and how I might resolve it?
Update
My full game class is defined as follows:
#import <Foundation/Foundation.h>
#interface Game : NSObject
#property (nonatomic, copy) NSString *name;
#property (nonatomic, copy) NSString *photoURL;
#property (nonatomic, copy) NSString *gameURL;
#property (nonatomic, assign) BOOL *userRegistered;
#end
// Game.m
#import "Game.h"
#implementation Game
#synthesize name = _name;
#synthesize partnerName = _partnerName;
#synthesize photoURL = _photoURL;
#synthesize gameURL = _gameURL;
#synthesize userRegistered = _userRegistered;
#end
I'm getting the error in one of my ViewControllers in this method
// api_response.body has just been set to an __NSCFArray containing
// NSDictionaries by AFNetworking
NSDictionary *game;
Game *newGame;
for (game in api_response.body){
newGame = [[Game alloc] init];
NSLog(#"Creating a new game");
// set attributes for new game instance
newGame.name = [game objectForKey:#"name"];
newGame.photoURL = [game objectForKey:#"photoURL"];
// user registered is either 0 (false) or 1 (true)
newGame.userRegistered = [[game objectForKey:#"user_registered"] intValue];
// add the game instance to the appropriate array
[self addGameToGamesArray:newGame];
newGame = nil;
}
The warning shows over newGame.userRegistered = [[game objectForKey:#"user_registered"] intValue];
[game objectForKey:#"user_registered"] is likely giving you an NSNumber object. You probably mean instead to compare the integer value inside that NSNumber object.
([[game objectForKey:#"user_registered"] intValue] > 0)
UPDATE in response to your update:
Your problem is with how you're declaring your BOOL property - you have a * that you need to remove.
#property (nonatomic, assign) BOOL *userRegistered;
should be
#property (nonatomic, assign) BOOL userRegistered;
I was able to solve this issue by simply using boolValue
game.userRegistered = [[json objectForKey:#"user_registered"] boolValue];
Thanks all for the help
objectForKey function will return an objective-c instance.
([[game objectForKey:#"user_registered"] boolValue] > 0)
([game boolForKey:#"user_registered"]==YES)

Mapping nested objects with RestKit in Xcode using Objective-C

With the help of mja, I managed to successfully set up simple object mapping using RestKit and Objective-C. Please see my previous question here.
My next step was to attempt to deal with nested JSON in the same way.
My JSON looks like this, with the outer being a CandidatePhrase with some nested 'Votes':
{ "Id":33696,
"Phrase": "phrase",
"BadCount":0,
"Votes":[{"Id":447,"OriginalId":33696,"Votes":2,"Translation":"translation 1"},
{"Id":746,"OriginalId":33696,"Votes":1,"Translation":"translation 2"},
{"Id":747,"OriginalId":33696,"Votes":1,"Translation":"translation 3"}
]}
I created a relationship in my AppDelegate as follows:
[candidatePhraseMapping mapKeyPath:#"votes" toRelationship:#"vote" withMapping:voteMapping];
When I call make my request in my controller, I'm able to deal with the rest of the CandidatePhrase okay, but am not really sure how to map the nested 'Vote' objects into an array so I can use them in a TableView
(pseudo-code something like this...)
// Store the votes in an array
_votes = [[NSArray alloc] initWithObjects:myCandidatePhrase.votes, nil];
Here's my CandidatePhrase Object
#interface CandidatePhrase : NSObject
#property (nonatomic, retain) NSNumber* ident;
#property (nonatomic, retain) NSNumber* badcount;
#property (nonatomic, retain) NSString* phrase;
#property (nonatomic, retain) NSArray* votes;
#end
and my Vote object
#interface Vote : NSObject
#property (nonatomic, retain) NSNumber* ident;
#property (nonatomic, retain) NSNumber* originalId;
#property (nonatomic, retain) NSNumber* votecount;
#property (nonatomic, retain) NSString* translation;
+ (id)voteWithTranslationId:(NSNumber *)ident translation:(NSString *)translation;
#end
Any help would be much appreciated.
EDIT
Below is my mapping code
// Votes Mapping
RKObjectMapping* voteMapping = [RKObjectMapping mappingForClass:[Vote class]];
[voteMapping mapKeyPath:#"Id" toAttribute:#"ident"];
[voteMapping mapKeyPath:#"OriginalId" toAttribute:#"originalId"];
[voteMapping mapKeyPath:#"Votes" toAttribute:#"votecount"];
[voteMapping mapKeyPath:#"Translation" toAttribute:#"translation"];
[[manager mappingProvider] addObjectMapping:voteMapping];
// Candidate Phrase Mapping
RKObjectMapping *candidatePhraseMapping = [RKObjectMapping mappingForClass:[CandidatePhrase class]];
[candidatePhraseMapping mapKeyPath:#"Id" toAttribute:#"ident"];
[candidatePhraseMapping mapKeyPath:#"Phrase" toAttribute:#"phrase"];
[candidatePhraseMapping mapKeyPath:#"BadCount" toAttribute:#"badcount"];
[candidatePhraseMapping mapKeyPath:#"Votes" toRelationship:#"votes" withMapping:voteMapping];
[[manager mappingProvider] addObjectMapping:candidatePhraseMapping];
For clarity also, here's how I'm attempting to access the vote items on the controller
- (void)objectLoader:(RKObjectLoader*)objectLoader didLoadObject:(id)object
{
CandidatePhrase *myCandidatePhrase = (CandidatePhrase*)object;
self.candidateText.text = myCandidatePhrase.phrase; <-- works fine
_votes = [[NSArray alloc] initWithObjects:myCandidatePhrase.votes, nil];
for (id o2 in _votes) {
//Vote *vote = o2;
NSLog(#"Item name: %#", o2); <-- sees object but crashes
}
NSLog(#"Votes: %#", myCandidatePhrase.votes);
_votes = [[NSArray alloc] initWithObjects:myCandidatePhrase.votes, nil];
[_votesTableView reloadData];
}
and my table is binding with
Vote *vote = [_votes objectAtIndex:indexPath.row];
cell.textLabel.text = vote.translation;
You do not need to manually manage the nested NSArray. I believe the problem might be just a simple typo, as you map keyPath "votes", but your json contain "Votes" with capital "V".
[candidatePhraseMapping mapKeyPath:#"Votes" toRelationship:#"votes" withMapping:voteMapping];
If this doesn't help feel free to leave a comment and update your question with voteMapping.
Also, the contents of the didLoadObject can be simplified:
//in .h file
#property (nonatomic, retain) NSArray* votes;
// in implementation
#synthesize votes;
...
- (void)objectLoader:(RKObjectLoader*)objectLoader didLoadObject:(id)object
{
CandidatePhrase *myCandidatePhrase = (CandidatePhrase*)object;
self.candidateText.text = myCandidatePhrase.phrase;
self.votes = myCandidatePhrase.votes;
}

Model Object called in NSOutlineView DataSource Method Crashing App

I have a bewildering problem, hoping someone can assist:
I have a model object, called Road. Here's the interface.
###
#interface RoadModel : NSObject {
NSString *_id;
NSString *roadmapID;
NSString *routeID;
NSString *title;
NSString *description;
NSNumber *collapsed;
NSNumber *isRoute;
NSString *staff;
NSNumber *start;
NSArray *staffList;
NSMutableArray *updates;
NSMutableArray *uploads;
NSMutableArray *subRoads;
}
#property (nonatomic, copy) NSString *_id;
#property (nonatomic, copy) NSString *roadmapID;
#property (nonatomic, copy) NSString *routeID;
#property (nonatomic, copy) NSString *title;
#property (nonatomic, copy) NSString *description;
#property (nonatomic, copy) NSNumber *collapsed;
#property (nonatomic, copy) NSNumber *isRoute;
#property (nonatomic, copy) NSString *staff;
#property (nonatomic, copy) NSNumber *start;
#property (nonatomic, copy) NSArray *staffList;
#property (nonatomic, copy) NSMutableArray *updates;
#property (nonatomic, copy) NSMutableArray *uploads;
#property (nonatomic, copy) NSMutableArray *subRoads;
- (id)initWithJSONObject:(NSDictionary *)JSONObject;
#end
This part is fine.
To give you some background, I'm translating a bunch of JSON into a proper model object so it's easier to work with.
Now, I'm trying to display this in an NSOutlineView. This is where the problem is. In particular, I have created the table and a datasource.
- (id)initWithRoads:(NSArray *)roads {
if (self = [super init])
root = [[NSMutableArray alloc] initWithArray:roads];
return self;
}
- (NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item {
if (item == nil)
return root.count;
return 0;
}
- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item {
return NO;
}
- (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item {
if (item == nil)
item = root;
if (item == root)
return [root objectAtIndex:index];
return nil;
}
- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item {
return [item title];
}
In the final datasource method, it attempts to return the "title" string property of the model object, but for some reason crashes each time. I have checked that the method is taking in the correct object (I checked [item class] description], and it is the right object), but for some reason if I call any of the objects accessors the app immediately crashes.
This is totally puzzling because in the init method, I can iterate through root (an array of RoadModel objects), and print any of its properties without issue. It is only when I'm trying to access the properties in any of the datasource methods that this occurs. I wonder if there is something memory-wise that is going on behind the scenes and I am not providing for it.
If you can shed some light on to this situation, it would be greatly appreciated!
Thanks in advance!
Usually, this kind of thing is caused by over-releasing of objects. By the time you get to the method that crashes, either your data source or your root array has been deallocated. Don't forget that NSOutlineView maintains a weak reference to its data source. This means that in reference counted world it does not retain the data source and in GC world, the reference is not enough to stop the data source from being collected.
You need to maintain a retained/strong reference elsewhere.

Objective-C NSArray

I'm new to Obj-C and iPhone SDK. The test application I'm stock with is a color switcher containing two buttons ("Back", "Forward") and one text label. The idea is to switch between rainbow colors (background) and setting an appropriate text label in a cyclic manner.
I declared NSArray (which is to contain colors names) in RainbowViewController.h, synthesized it in RainbowViewController.h and I can't add any string into that array.
This is "h" file:
#import <UIKit/UIKit.h>
#interface RainbowViewController : UIViewController {
IBOutlet UILabel *currentColorTextLabel;
NSArray *colorsArray;
NSString *msg;
}
#property (nonatomic, retain) IBOutlet UILabel *currentColorTextLabel;
#property (nonatomic, retain) NSArray *colorsArray;
#property (nonatomic, retain) NSString *msg;
- (IBAction) pressForwardButton;
- (IBAction) pressBackButton;
#end
This is "m" file:
#import "RainbowViewController.h"
#import <Foundation/Foundation.h>
#implementation RainbowViewController
#synthesize currentColorTextLabel;
#synthesize colorsArray;
#synthesize msg;
int currentArrayIndex = 0;
colorsArray = [[NSArray alloc] init]; //here i get "Initializer element is not constant" error message
[coloursArray addObject:#"Red"]; //here I get "Expected identifier or '(' before '[' token"
[coloursArray addObject:#"Orange"];
//etc
- (IBAction) pressForwardButton {
//here I'm going to increment currentArrayIndex, set an appropriate color, and update a currentColorTextLabel based on currentArrayIndex.
}
- (IBAction) pressBackButton {
}
//auto-genereted code here
#end
I'm new to obj-c as well, but I think you need to initialize the array with objects, or use an NSMutableArray if you want to add objects after it is created.
You have the code that should go in your init method just sitting out in the middle of the file. You can't set instance variables like that.
jasongetsdown is correct. You need to instantiate the NSArray object with the objects it will contain and nil terminated.
#"Red", #"Blue", nil
If you wish to have an array that you can change you need to make it a Mutable Array.
However, you have another problem here. Your property that you are synthesizing and allocating for is an object named colorsArray and you are trying to pass a method to a coloursArray object, two different spellings.