iOS Arrays with custom classes to arrays with NSStrings - ios

I have my own class with several properties and I have them in NSArray. I need to use them for method which takes NSArray of strings. So I am asking what is best aproach to get array with strings from my array which has custom classes. I can create second array and use it but I think there could be better way. I need to have it for different custom classes (from one, I want to use for example name property to new NSArray, in second title property and so).
I hope I explained well but I tried it once more on example:
NSArray *arrayWitCustomClasses = ... fill with custom classes;
// setValues method takes NSArray with NSStrings
// when arrayWithCustomClasses used it returns copyWithZone: error on custom class
[someObject setValues:[arrayWithCustomClasses toArrayWithStrings]];

As long as your object exposes the required values as NSString properties you can use the valueForKey method of NSArray.
For example
NSArray *arrayOfTitles=[arrayWithCustomClasses valueForKey:#"title"];
NSArray *arrayOfNames=[arrayWithCustomClasses valueForKey:#"name"];
Or
[someObject setValues:[arrayWithCustomClasses valueForKey:#"title"]];
and so on

NSMutableArray *strings = [NSMutableArray array];
for (NSObject *item in arrayWithCustomClasses) {
/* You can use a different property as well. */
[strings addObject:item.description];
}
[someObject setValues:strings.copy];

Like #Tim says, but you could shorten it by just using:
[someObject setValues:[arrayWithCustomClasses valueForKey:#"description"]];
Same result. One line of code.
Then implement the description method of your custom classes to return whatever properties and formatting you want.

Related

Adding array of dictionary to array of dictionary

I had two NSDictionary elements in the finalOrderArray before addingObject. Then I added sharedData.comboItems but this object is also an array of NSDictionary.
Now,I have a mix of NSDictionary and NSArray which is difficult to handle.
Is there an easy way to add NSDictionary all together?
[finalOrderArray addObject:sharedData.comboItems];
Desired output in this example, finalOrderArray would have 6 dictionaries rather than having 2 dictionaries and one array of dictionary.
Use addObjectsFromArray: method.
Adds the objects contained in another given array to the end of the
receiving array’s content.
Here is the link to NSMutableArray and all its methods.
Use addObjectsFromArray method. It will add all the objects from sharedData.comboItems. Try this.
[finalOrderArray addObjectsFromArray: sharedData.comboItems];
sharedData.comboItems is an array that's why you get one array in your finalOrderArray. You need to iterate through the array, get the dictionary and add to finalOrderArray.
Like this:
for (NSDictionary *item in sharedData.comboItems) {
[finalOrderArray addObject:item];
}

Check if NSMutableArray has a specific Object

I am trying to check if the NSMutableArray has a specific object, before adding the object to it, if exists then don't add.
i looked over many posts explaining how to do this, managed to implement it like this, but it always gives me that the object "doesn't exist", though i already added it !
//get row details into FieldLables Object
AllItemsFieldNames *FieldLabels = feedItems[row];
// object to hold single row detailes
AllItemsFieldNames *SelectedRowDetails = [[AllItemsFieldNames alloc] init];
SelectedRowDetails.item_name = FieldLabels.item_name;
//SelectedRowDetails.item_img = FieldLabels.item_img;
SelectedRowDetails.item_price = FieldLabels.item_price;
//NSLog(#"item has been added %#", SelectedRowDetails.item_name);
//NSLog(#"shopcartLength %lu", (unsigned long)SelectedFieldsNames.count);
if([SelectedFieldsNames containsObject:SelectedRowDetails])
{
NSLog(#"Already Exists!");
}
else
{
NSLog(#"Doesn't Exist!");
[SelectedFieldsNames addObject:SelectedRowDetails];
}
I can display all object from the NSMutableArray into a table, what i need to do in the above code is stop the addition of duplicate objects.
The first method listed on the NSArray documentation under the section "querying an array" is containsObject:. If it's not working, that suggests that your implementation of isEqual: is not correct. Make sure you follow the note in the documentation:
If two objects are equal, they must have the same hash value. This
last point is particularly important if you define isEqual: in a
subclass and intend to put instances of that subclass into a
collection. Make sure you also define hash in your subclass.
You might also consider using an NSSet since you can't add duplicates to that. Of course, this would also require a working version of isEqual:.
Sets are composed of unique elements, so this serves as a convenient way to remove all duplicates in an array.
here some sample,
NSMutableArray*array=[[NSMutableArray alloc]initWithObjects:#"1",#"2",#"3",#"4", nil];
[array addObject:#"4"];
NSMutableSet*chk=[[NSMutableSet alloc ]initWithArray:array]; //finally initialize NSMutableArray to NSMutableSet
array= [[NSMutableArray alloc] initWithArray:[[chk allObjects] sortedArrayUsingSelector:#selector(compare:)]]; //after assign NSMutableSet to your NSMutableArray and sort your array,because sets are unordered.
NSLog(#"%#",array);//1,2,3,4

iOS how does NSMutableArray check if it contains NSNumber objects?

I'm writing some code that will be using NSMutableArray and storing int values within it, wrapped within NSNumbers.
I would like to confirm that querying an iOS NSArray or NSMutableArray using new NSNumbers with same values is legal, of if I need to explicitly iterate over the array, and check if each int value is equal to the value I want to test against?
This appears to work:
NSMutableArray* walkableTiles = [NSMutableArray array];
[walkableTiles addObject:#(1)];
[walkableTiles addObject:#(2)];
[walkableTiles addObject:#(3)];
if([walkableTiles containsObject:#(1)])
{
DLog(#"contains 1"); //test passes
}
if([walkableTiles containsObject:[NSNumber numberWithFloat:2.0]])
{
DLog(#"contains 2");//test passes
}
if([walkableTiles containsObject:[NSNumber numberWithInt:3]])
{
DLog(#"contains 3");//test passes
}
What you are doing is fine. Why wouldn't it be?
The containsObject: method actually iterates over the array and calls the isEqual: method on each object passing in the object you are checking for.
BTW - there is nothing special here about using NSNumber. It's the same with an array of any object type. As long as the object's class has a valid isEqual: method, it will work.
Per the Apple's NSNumber documentation, you should use isEqualToNumber:
isEqualToNumber: Returns a Boolean value that indicates whether the
receiver and a given number are equal.
- (BOOL)isEqualToNumber:(NSNumber *)aNumber

UITableView Setup

I have an unsorted NSArray of names. I know how to build a static table, but I am not sure how to make a dynamic table that will have a section with the first letter of the name and then the names for that letter in put into each section. I know this sounds like a beginner level programming question, and well it is. Any help would be great. New to iOS programming so I am just trying to get a feel for everything.
You can do this easily with TLIndexPathTools using the block-based data model initializer:
NSArray *items = ...; // and array containing your unorganized data (items of type NSString assumed here)
TLIndexPathDataModel *dataModel = [[TLIndexPathDataModel alloc] initWithItems:items sectionNameBlock:^NSString *(id item) {
return [[((NSString *)item) substringToIndex:1] upperCaseString];
} identifierBlock:nil];
The sectionNameBlock argument is a block that returns the first letter of the given item, which the initializer uses to organize the data into sections. Then you'd use dataModel (instead of an array) in your data source and delegate methods using the various APIs like [dataModel numberRowsInSection:], [dataModel itemAtIndexPath:], [dataModel indexPathForItem:], etc.
Try running the "Blocks" sample project for a working example.

Objective-c adding to array same instance with different properties

I'm trying the following code to create an instance, assign properties, add to array.
Then, assigning new properties and adding again.
However array will contain 2 identical objects (equal to the second one added). The class Message simply has several (nonatomic, retain) NSStrings/Integer properties.
This probably has something to do with my understanding of pointer, can someone explain?
self.messages=[[NSMutableArray alloc]init];
Message *m=[[Message alloc]init];
m.cb=#"2402";
m.ck=1001;
m.msg=#"as";
[self.messages addObject:m];
m.cb=#"2422";
m.ck=1002;
m.msg=#"aadfsdsdfdssdklsdflkh";
[self.messages addObject:m];
NSLog(#"%#",self.messages);
When you add an object to an array, it does not add a copy of the object to the array, but instead just a reference to it. If you want two different objects, then you need to create two different objects instead of re-using the same one (or, as #Brendon points out, create a copy when you add it to your array).
To fix your example, the most common technique would be to add the following line right before you start modifying the properties for the second object:
m=[[Message alloc]init];
Or, use a second pointer and object instead of reusing m.
EDIT:
To add a copy, change [self.messages addObject:m]; to [self.messages addObject:[m copy]];, assuming that the Message class conforms to the NSCopying protocol.
Yes, after executing the posted code self.messages contains the Message object twice, at indexes 0 and 1. That's not a problem, though. Arrays can contain any object, even themselves.
It seems that you want two distict objects, so you would just create a second Message.
You can either implement the NSCopy protocol — as mentioned by lnafziger — or just create new instances quite easily in a for loop.
«Two or more, use a for»
— Edsger W. Dijkstra
self.messages=[[NSMutableArray alloc] init];
NSArray *dataArray = #[ #{#"cb": #"2402", #"ck": #(1001), #"msg": #"as"},
#{#"cb": #"2422", #"ck": #(1002), #"msg": #"aadfsdsdfdssdklsdflkh"}
];
for(NSDictionary *data in dataArray) {
Message *m=[[Message alloc] init];
m.cb = data[#"cb"];
m.ck = [data[#"ck"] integerValue];
m.msg = data[#"msg"];
[self.messages addObject:m];
}

Resources