Search NSArray and add to NSMutableArray - ios

I have an Xcode project with two NSArrays of objects, one named completionArray filled with #"yes" and #"no" and one named allRequirements with objects that represent college classes such as #"ITCS 1215". My goal is to search completionArray until I reach #"no", then copy the object at that index from allRequirements in to suggestionArray, a NSMutableArray.
Here is my code so far, which does not work because it is throwing the error "Expected Identifier" after the last closing bracket.
for (int i = 0; i < [self.allRequirements count]; i++)
{
if([self.completionArray[i] isEqual:#"no"])
[self.suggestionArray addObject:[self.allRequirements[i]];
}
Thanks all.

Change this line:
[self.suggestionArray addObject:[self.allRequirements[i]];
to:
[self.suggestionArray addObject:self.allRequirements[i]];

Related

Xcode 13 - Count not working on NSMutableArray anymore

I have something like this in my code which worked fine for many years
NSMutableArray* DeviceList = [NSMutableArray alloc] init]; // Multi-dimensional (n x m) mutable Array filled throughout the code before arriving here:
if ([[DeviceList objectAtIndex:i] count] == 9))
{
[DeviceList removeObjectAtIndex:i];
}
I haven't touched the project for a while and now upgraded to Xcode 13 and get the following error:
Multiple methods named 'count' found with mismatched result, parameter type or attributes
The error list on the left pane shows 12 options where count has been declared.
So what has changed that the simple
someNSUInteger = [[someArray] count];
creates an error and what would be a good way to fix it in 100+ instances without casting every instance with (NSMutableArray*)?
Thanks a lot!
objectAtIndex returns "id" (objects of any type). Before it used to be permissive, and you were allowed to call any method on such (such as "count").
A better way to write this code would be to declare an intermediate variable:
NSArray *deviceRow = [DeviceList objectAtIndex:i];
if ([deviceRow count] == 9) {
or if you know the type if the items inside the array, let's say you have strings:
NSArray<NSString *> *deviceRow = [DeviceList objectAtIndex:i];
if ([deviceRow count] == 9) {
and even better:
NSArray<NSString *> *deviceRow = DeviceList[i];
if (deviceRow.count == 9) {
Another problem is that there's too many instances of that, and you'd rather not touch it everywhere.
One way to fix most of the 100 occurences is to define a wrapper class for DeviceList instead of using a "naked" NSMutableArray:
#interface MyDeviceList
- (nonnull instancetype)init;
- (nullable NSArray *)objectAtIndex:(NSUInteger)index;
... any other NSMutableArray methods used in the code ...
#end
and replace the array instantiation with:
MyDeviceList *DeviceList = [MyDeviceList new];
Hopefully you have much less instantiations than unsafe usages.
You could also have some helper methods in MyDeviceList like "countAtIndex" if it happens that you need it a lot.

IOS/Objective-C: Detect What is Different About Arrays

I have a bug whereby an array of NSNumbers that is dynamically created is not producing the expected results. To see what is in the array, I have logged it out. I also manually created an equivalent array that does produce expected results and logged it out. The elements appear to be identical when logged but when I do an isEqualArray test they are different. Can anyone suggest a way to detect what is different so that I can fix it? Thanks for any suggestions.
Here is the code that logs out the arrays:
-(NSMutableDictionary *) getExistingContactsWithUIDs:(NSArray *)uids
{
int numElements = (int) uids.count;
NSLog(#"num elements in uids%d",numElements); //logs as 3
NSLog(#"first elementzzz%#zzz",uids[0]); //logs as zzz2101zzz
NSLog(#"2nd elementzzz%#zzz",uids[1]); //logs as zzz2098zzz
NSLog(#"3rd elementzzz%#zzz",uids[2]);//logs as zzz2100zzz
//Manually created array
NSArray*ualtids = #[#2101, #2098, #2100];
int numElementsAlt = (int) ualtids.count;
NSLog(#"num elements in uids%d",numElementsAlt); //logs as 3
NSLog(#"first alt elementzzz%#zzz",ualtids[0]);//logs as zzz2101zzz
NSLog(#"2nd alt elementzzz%#zzz",ualtids[1]);//logs as zzz2098zzz
NSLog(#"3rd alt elementzzz%#zzz",ualtids[2]);//logs as zzz2100zzz
//code to compare says they are different
if ([uids isEqualToArray:ualtids]) {
NSLog(#"Arrays same");
}
else{
NSLog(#"Arrays different ");
}
//Finally the code that creates the uids array is:
NSMutableArray *newUIDs = [NSMutableArray array];
for (i=0;i<max;i++)
{
uid = importContact.cid;
[newUIDs addObject:uid];
}
[Voice of ObiWan Kenobi:] Uuuuuuse the debugggerrrrr, Luuuuuuke!
The problem is that you are using the NSLog command. That calls description so you don't learn what the class of the NSArray's elements is. An NSNumber wrapping 1 and an NSString #"1" log exactly the same. So you learn nothing.
But if you will simply pause in the debugger at a breakpoint after the arrays are configured, you can examine them in the variables list, as shown here:
Those two arrays (arr1 and arr2) log the same, but in the variables list it is perfectly plain that one contains NSStrings and the other contains NSNumbers.

How to compare every pair of elements inside a NSArray?

I have an NSArray filled with only NSStrings
I understand that to iterate over a NSArray of n elements, all I have to do is use for (NSString *element in arrayOfElements). However, I was wondering if there is specific function that will perform a comparison between every string element in the array with each other. For example, if I have the array:
[#"apple", #"banana", #"peach", #"kiwi"],
how would I do the comparison so apple is compared to banana, peach and then kiwi; and then banana is against peach and wiki, and finally peach is against kiwi?
Try using nested for loops, ex:
for (int i = 0 ; i < array.count ; i ++) {
for (int j = i + 1 ; j < array.count ; j ++) {
// compare array[i] to array [j]
}
}
Edit: And although wottle's suggestion would work, I'd recommend mine in this case, since it won't waste iterations going over the same comparisons multiple times. What I've done in this algorithm by setting j = i + 1 is compare each element in the array only to the ones after it.
Given "the array will not have any duplicates, and every NSString will be unique" this sounds like a great case for using NSSet classes instead of NSArray. NSMutableSet provides:
minusSet:
Removes each object in another given set from the receiving
set, if present.
and
intersectSet:
Removes from the receiving set each object that isn’t a
member of another given set.
I'm not sure which operation you're looking for but it sounds like one of those should cover your exact use case.
What you're trying to do is a bit beyond what custom comparators were meant to do. Typically when you have a list and you want to run a custom comparator, you're doing it to sort the list. You seem to want to do some specific action when certain items in the list compare to others, and for that, I think a loop within a loop is your best bet. It won't be very good performance, so hopefully you are not expecting a large array:
-(void) compareArrayToSelf
{
NSArray *array=#[#"apple", #"bananna", #"peach", #"kiwi"];
for( NSString *value1 in array)
{
for( NSString *value2 in array)
{
if( ![value1 isEqualToString:value2] && [self compareArrayValue:value1 toOtherValue:value2])
{
//Do something with either value1 or value2
}
}
}
}

How to avoid NSMutable array add object values changes before adding object to NSMutable array?

I am new to Objective C. I had used following code.
for (int i = 0; i < [ValueisFound count]; i++)
{
NSString* ObjectName = [NSString stringWithUTF8String:name];
ObjectName = [[NSClassFromString([NSString stringWithUTF8String:samType]) alloc]init];
NSMutableDictionary* jsonDictionary=[TemplateClass SeparateArray:jsonValue_1 key:[arrayofKeys objectAtIndex:j] index:i];
ObjectName = [TemplateClass JsonPharser:str1 jsonObject:jsonDictionary];
NSMutableArray *samArray=[[NSMutableArray alloc]initWithObjects:[TemplateClass JsonPharser:str1 jsonObject:jsonDictionary], nil];
[manoj_Array addObject:samArray];
[samArray release];
[ObjectName release];
}
While executing for loop:
at i=0, Object has value(number=10), now manoj_Array also has (number=10).
at i=1, Object has value(number=12), now manoj_Array has (number=12,number=12).
But i want the result as manoj_Array has (number=10,number=12). I don't know how that array values are changing to last value.
My mind
samArray and manoj_Array is shared the memory Reference Thats why last value is insert to the manoj_Array
i = 0 value is Store by the address of 1000
i = 1 value is Store by the address of 1002
but manoj_Array share the memory so change the Last value is Added to manoj_Array
You can implement KVO in order to know when a value has changed and handle its behaviour.

How for in loop works internally - Objective C - Foundation

I found this answer:
https://stackoverflow.com/a/5163334/1364174
Which presents how for in loop is implemented.
NSFastEnumerationState __enumState = {0};
id __objects[MAX_STACKBUFF_SIZE];
NSUInteger __count;
while ((__count = [myArray countByEnumeratingWithState:&__enumState objects:__objects count:MAX_STACKBUFF_SIZE]) > 0) {
for (NSUInteger i = 0; i < __count; i++) {
id obj = __objects[i];
[obj doSomething];
}
}
The problem is that, I found it wrong.
First of all, when you have Automatic Reference Counting (ARC) turned on, you got an error
Sending '__strong id *' to parameter of type '__unsafe_unretained_id*' changes retain/release properties of pointer
But even when I turn ARC off I found out that I __object array seems to behave strangely :
This is actual Code (I assumed MAX_STACKBUFF_SIZE to be 40):
#autoreleasepool {
NSArray *myArray = #[#"a", #"b", #"c", #"d", #"e", #"f", #"g"];
int MAX_STACKBUFF_SIZE = 40;
NSFastEnumerationState __enumState = {0};
id __objects[MAX_STACKBUFF_SIZE];
NSUInteger __count;
while ((__count = [myArray countByEnumeratingWithState:&__enumState objects:__objects count:MAX_STACKBUFF_SIZE]) > 0) {
for (NSUInteger i = 0; i < __count; i++) {
id obj = __objects[i];
__enumState.itemsPtr
NSLog(#" Object from __objects ! %#", obj); // on screenshot different message
}
}
}
return 0;
I got EXC_BAD_ACESS when I try to get the contents of the __object array.
I also found out that when you try to iterate through __enumState.itemsPtr it actually works.
Could you explain me what is going on here ? Why my __objects seems to be "shrunken down". And why it doesn't contains desired object? And why is that error when ARC is turned on.
Thank you very very much in advance for your time and effort! (I provided screenshot for better understanding what causes an error)
First of all, strong pointers cannot be used in C-structures, as explained in the "Transitioning to ARC Release Notes", therefore the objects array has be be declared
as
__unsafe_unretained id __objects[MAX_STACKBUFF_SIZE];
if you compile with ARC.
Now it is not obvious (to me) from the NSFastEnumeration documentation, but it is
explained in Cocoa With Love:Implementing countByEnumeratingWithState:objects:count:
that the implementation need not fill the supplied objects array, but can just set
__enumState.itemsPtr to an existing array (e.g. some internal storage). In that case, the contents of the
__objects array is undefined, which causes the crash.
Replacing
id obj = __objects[i];
by
id obj = __enumState.itemsPtr[i];
gives the expected result, which is what you observed.
Another reference can be found in the "FastEnumerationSample" sample code:
You have two choices when implementing this method:
1) Use the stack
based array provided by stackbuf. If you do this, then you must
respect the value of 'len'.
2) Return your own array of objects. If
you do this, return the full length of the array returned until you
run out of objects, then return 0. For example, a linked-array
implementation may return each array in order until you iterate
through all arrays.
In either case, state->itemsPtr MUST be a valid
array (non-nil). ...

Resources