Work with objects in NSArray - objective-c

I need to work with objects in NSMutableArray. I have NSMutableArray called "Albums"
it contains objects "Album"
#interface Album : NSObject {
NSString *aid;
NSString *title;
NSString *ownerID;
}
I push few Album objects into "Albums" NSMutableArray, and i want to delete Album object where
"title" field is "HelloWorld" for example or something else. How to do this?

This should do:
NSArray *matchingObjects = [array filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"self.title = %#", #"HelloWorld"]];
[array removeObjectsInArray:matchingObjects];

Related

Creating Array with properties for each item in Objective-c

tell me please, how do I create an array in which each element will have a number of properties. For example:
array:
|
|-item 1 ( property_1-"Name1", property_2-"LastName1", property_3-"Age1");
|-item 2 ( property_1-"Name2", property_2-"LastName2", property_3-"Age2");
|-item 3 ( property_1-"Name3", property_2-"LastName1", property_3-"Age2");
|-…
In this case, the different elements of an array can have one and the same property, such as in the code posted above - "item 3" has the "property 2" is the same as in "item 1", and "property 3" is the same as in "item 2"
Tell me, please, how best to do it and, if not difficult, write a simple example or a link to some tutorial.
Thank you in advance)
There are two methods that I would suggest:
1. Use a class to store all the properties
Here's an example:
#interface Wrapper : NSObject
#property (nonatomic, assign) NSString* property_1;
#property (nonatomic, assign) NSString* property_2;
#property (nonatomic, assign) NSString* property_3;
#end
Then you can use it as a dictionary:
NSString* value=[myWrapperInstance valueForKey: #"property_1"];
But here comes the alternative solution:
1. Use a NSDictionary to store all the properties
NSDictionary* dict= #{ #"property_1" : #"Name1" ,#"property_2" : #"Name2", #"property_3" : #"Name3" };
Then the solution comes easy:
NSMutableArray* objects=[NSMutableArray new];
for(int i=0; i<N; i++)
{
NSDictionary* dict= #{ #"property_1" : #"Name1" ,#"property_2" : #"Name2", #"property_3" : #"Name3" };
[objects addObject: dict];
}
Sounds like you want an NSArray of NSDictionary objects:
NSDictionary *dict1 = [NSDictionary dictionaryWithObjectsAndKeys:#"Name1", #"property_1", #"LastName1", #"property_2", #"Age1", #"property_3", nil);
NSDictionary *dict2 = [NSDictionary dictionaryWithObjectsAndKeys:#"Name2", #"property_1", #"LastName2", #"property_2", #"Age2", #"property_3", nil);
NSDictionary *dict3 = [NSDictionary dictionaryWithObjectsAndKeys:#"Name3", #"property_1", #"LastName3", #"property_2", #"Age3", #"property_3", nil);
NSArray *array = [NSArray arrayWithObjects:dict1, dict2, dict3, nil];
If you want to update this later then you should use NSMutableDictionary and NSMutableArray, respectively.
If you are not using ARC, the you need to release objects when you are finished with them.

SBJsonParser can't parse NSArray

I am trying to parse NSArray to JSON but I get the following error:
* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArrayM
JSONRepresentation]: unrecognized selector sent to instance 0xa93e460'
* First throw call stack: (0x21f1012 0x1feae7e 0x227c4bd 0x21e0bbc 0x21e094e 0x3445a 0x33ecc 0x26a453f 0x26b6014 0x26a72e8 0x26a7450
0x95e22e12 0x95e0acca) libc++abi.dylib: terminate called throwing an
exception
I have included all classes from SBJson_3.1.1/Classes directory.
This is code:
NSMutableArray* arr = ...get array
NSString* jsonArr = [arr JSONRepresentation]; // here I get error
When I do this in array of simple strings it works:
NSData *jsonData = [NSJSONSerialization arr
options:NSJSONWritingPrettyPrinted error:nil];
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
But my array contain list of objects (Person) maybe there is a problem.
I use Item instead of person just as example
Item.h
#interface Item : NSObject
{
BOOL IsOpen;
NSString* Description;
}
#property int ItemId;
#property int SequenceId;
#property BOOL IsOpen;
#property NSString* Description;
- (id) proxyForJson;
#end
Item.m
#implementation Item
#synthesize ItemId;
#synthesize SequenceId;
#synthesize Description;
#synthesize IsOpen;
- (id) proxyForJson {
return [NSDictionary dictionaryWithObjectsAndKeys:
[NSString stringWithFormat:#"%i", ItemId], #"ItemId",
SequenceId, #"SequenceId",
Description, #"Description",
IsScanned, #"IsOpen",
nil ];
}
#end
UPDATE
Student example
I tried to make a separate project. I copied to new project all from classes directory of sbjson framework. This is code:
#import "SBJson.h"
#interface Student : NSObject
{
NSString *name;
NSInteger sid;
NSString *email;
}
#property NSString *name;
#property NSInteger sid;
#property NSString *email;
- (id) proxyForJson;
#end
#implementation Student
#synthesize name;
#synthesize sid;
#synthesize email;
- (id) proxyForJson{
return [NSDictionary dictionaryWithObjectsAndKeys:
name, #"student_name",
[NSNumber numberWithInt:sid], #"student_id",
email, #"email",
nil ];
}
#end
NSMutableArray* studentArray = [[NSMutableArray alloc]init];
Student* s1 = [[Student alloc]init];
s1.name = #"student 1";
s1.sid = 45;
s1.email = #"test#test.com";
Student* s2 = [[Student alloc]init];
s2.name = #"student 2";
s2.sid = 46;
s2.email = #"plavi#test.com";
[studentArray addObject:s1];
[studentArray addObject:s2];
NSString *jsonString = [studentArray JSONRepresentation];
NSLog(#"%#", jsonString);
And again I get error:
Terminating app due to uncaught exception
'NSInvalidArgumentException', reason: '-[__NSArrayM
JSONRepresentation]: unrecognized selector sent to instance 0x741b100'
SBJson doesn't support serialising user-defined classes without assistance. If you implement a -proxyForJson method in your Person class (example here) it should work, however.
If you're using a recent Xcode the below should work. Header:
#interface Item : NSObject
#property int ItemId;
#property int SequenceId;
#property BOOL IsOpen;
#property(copy) NSString* Description;
- (id) proxyForJson;
#end
Implementation:
#implementation Item
- (id) proxyForJson {
return #{ #"ItemId": #(self.ItemId),
#"SequenceId": #(self.SequenceId),
#"Description": self.Description,
#"IsOpen": #(self.IsOpen)
};
}
#end
This should let SBJson serialise the Item objects to NSDictionaries. However, SBJson does not support parsing JSON into custom objects. So you will always get this back in the dictionary form. I don't know of any Objective-C JSON parser that provides bindings to custom types.
I would suggest reading the top two comments of this thread. If those don't help, it is still very likely that you are not installing the library correctly. Try removing the SBJSON files from your project and then readding them, making sure that they are added to your target. Also, make sure you are importing the SBJSON header into your class.
I would suggest that you try using JSONRepresentation on an array of NSString objects. If the framework is correctly installed, this should definitely work. This way you can narrow down whether it is an installation issue or whether it is an issue with your custom class.
Check out the following excerpt from Working with JSON in iOS 5 Tutorial
This is mainly for generating JSON.
//build an info object and convert to json
NSDictionary* info = [NSDictionary dictionaryWithObjectsAndKeys:
[loan objectForKey:#"name"],
#"who",
[(NSDictionary*)[loan objectForKey:#"location"]
objectForKey:#"country"],
#"where",
[NSNumber numberWithFloat: outstandingAmount],
#"what",nil];
//convert object to data
NSData* jsonData = [NSJSONSerialization dataWithJSONObject:info options:NSJSONWritingPrettyPrinted error:&error];
Now, the difference lies in using NSDictionary and converting that into JSON Data. Try forming the JSON in the way given above and check if the problem persists.
you are correctly linking the category? to me it kinda looks like you are missing a category

SBJSON encode Object who contain an array of another Object

i've a little json encode problem :
i need to encode an object format JSON with SBJSON before send it to a php server
At the moment this sample code work :
NSArray *arrayData = [NSArray arrayWithObjects:
user.id == nil ? [NSNumber numberWithInt:-1] : user.id,
ProfessionField.text, NameField.text, RPPSField.text, RPPSField.text,
NameField.text, SurnameField.text, StreetField.text,
TownField.text, CpField.text, MailField.text,
PhoneField.text, FaxField.text, MobileField.text,
// [user.horaires JSONRepresentation],
nil];
NSArray *arrayKey = [NSArray arrayWithObjects:
#"id", #"spe", #"name", #"rpps", #"cip",
#"name", #"surname", #"rue",
#"ville", #"cp", #"mail",
#"tel", #"fax", #"port",
// #"horaires",
nil];
NSDictionary *dataBrut = [NSDictionary dictionaryWithObjects:arrayData forKeys:arrayKey];
NSDictionary *jsonDict = [NSDictionary dictionaryWithObject:dataBrut forKey:#"data"];
NSString *jsonRequest = [jsonDict JSONRepresentation];
The problem is when i need to send the "user.horaires" (here in comment)
Application CRASH at the JSON representation of this object.
this object is an Array of the following class :
#interface Horaire : NSObject
{
BOOL morning;
}
#property (nonatomic, strong) NSNumber *id;
#property (nonatomic, strong) NSString *open;
#property (nonatomic, strong) NSString *close;
Someone know how to succes to encode this ?
You shouldn't be including the JSON representation as a JSON item. JSON does not "escape" string data very well, so the embedded JSON (unless you separately "escape" it) will cause parsing to choke.
Instead you should place the dictionary or array that was used to produce the JSON representation (ie, "user.horaires" itself) in the location where you show the representation being produced and inserted. Then the entire structure will be JSON-encoded in one operation.
Ie:
NSArray *arrayData = [NSArray arrayWithObjects:
user.id == nil ? [NSNumber numberWithInt:-1] : user.id,
ProfessionField.text, NameField.text, RPPSField.text, RPPSField.text,
NameField.text, SurnameField.text, StreetField.text,
TownField.text, CpField.text, MailField.text,
PhoneField.text, FaxField.text, MobileField.text,
user.horaires,
nil];

Can't save to plist

I have my own object class from inherited from NSObject
#interface BlockedCell : NSObject
{
NSValue *gridValue;
NSString *name;
}
#property (nonatomic, retain) NSValue *gridValue;
#property (nonatomic, retain) NSString *name;
#end
So I try to create a few objects:
NSMutableDictionary *dict = [[dict alloc] init];
for (int i = 0; i < 5; ++i)
{
BlockedCell *block = [[BlockedCell alloc] init];
block.gridValue = [NSValue valueWithCGPoint: CGPointMake(0.0f, 0.0f)];
block.name = #"something";
[dict setObject: block forKey: [NSString stringWithFormat: #"item_%d", i]];
[block release];
}
if([dict writeToFile: path atomic: YES])
NSLog(#"Saved");
else
NSLog(#"Failed to save");
[dict release];
And what I get for the output is "Failed to save"..
If my dictionary does not contains any data, then it will output "Saved"
EDIT:
After I did more testing, I found out that actually is the NSValue causing the saving failed.
So what should I do if I want to save CGPoint into plist?
As you discovered, property lists cannot store NSValue objects directly. The supported classes are NSData, NSString, NSArray, NSDictionary, NSDate, and NSNumber, as documented in the NSPropertyListSerialization Class Reference.
The easiest workaround would be to use NSString instead of NSValue:
block.gridString = NSStringFromCGPoint(CGPointZero);
CGPoint point = CGPointFromString(block.gridString);
you cant save NSValue directly.In your case you have to save a point in the form ofstring use below line
CGPoint point = CGPointMake(10.0,20.0)
//you need to translate the point into a compatible "Plist" object such as NSString
//luckily, there is a method for that
[rectArray addObject:NSStringFromPoint(point)];
//save into a plist
.....
on retrieval of this value
CGPoint Point = CGPointFromString([rectArray objectAtIndex:0]);

Save / Write NSMutableArray of objects to disk?

Initially I thought this was going to work, but now I understand it won't because artistCollection is an NSMutableArray of "Artist" objects.
#interface Artist : NSObject {
NSString *firName;
NSString *surName;
}
My question is what is the best way of recording to disk my NSMutableArray of "Artist" objects so that I can load them the next time I run my application?
artistCollection = [[NSMutableArray alloc] init];
newArtist = [[Artist alloc] init];
[newArtist setFirName:objFirName];
[newArtist setSurName:objSurName];
[artistCollection addObject:newArtist];
NSLog(#"(*) - Save All");
[artistCollection writeToFile:#"/Users/Fgx/Desktop/stuff.txt" atomically:YES];
EDIT
Many thanks, just one final thing I am curious about. If "Artist" contained an extra instance variable of NSMutableArray (softwareOwned) of further objects (Applications) how would I expand the encoding to cover this? Would I add NSCoding to the "Applications" object, then encode that before encoding "Artist" or is there a way to specify this in "Artist"?
#interface Artist : NSObject {
NSString *firName;
NSString *surName;
NSMutableArray *softwareOwned;
}
#interface Application : NSObject {
NSString *appName;
NSString *appVersion;
}
many thanks
gary
writeToFile:atomically: in Cocoa's collection classes only works for property lists, i.e. only for collections that contain standard objects like NSString, NSNumber, other collections, etc.
To elaborate on jdelStrother's answer, you can archive collections using NSKeyedArchiver if all objects the collection contains can archive themselves. To implement this for your custom class, make it conform to the NSCoding protocol:
#interface Artist : NSObject <NSCoding> {
NSString *firName;
NSString *surName;
}
#end
#implementation Artist
static NSString *FirstNameArchiveKey = #"firstName";
static NSString *LastNameArchiveKey = #"lastName";
- (id)initWithCoder:(NSCoder *)decoder {
self = [super init];
if (self != nil) {
firName = [[decoder decodeObjectForKey:FirstNameArchiveKey] retain];
surName = [[decoder decodeObjectForKey:LastNameArchiveKey] retain];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:firName forKey:FirstNameArchiveKey];
[encoder encodeObject:surName forKey:LastNameArchiveKey];
}
#end
With this, you can encode the collection:
NSData* artistData = [NSKeyedArchiver archivedDataWithRootObject:artistCollection];
[artistData writeToFile: #"/Users/Fgx/Desktop/stuff" atomically:YES];
Take a look at NSKeyedArchiver. Briefly :
NSData* artistData = [NSKeyedArchiver archivedDataWithRootObject:artistCollection];
[artistData writeToFile: #"/Users/Fgx/Desktop/stuff" atomically:YES];
You'll need to implement encodeWithCoder: on your Artist class - see Apple's docs
Unarchiving (see NSKeyedUnarchiver) is left as an exercise for the reader :)