How to paste [array count] to case: - objective-c

I have switch. One of the cases must be a count of array:
int count = [array count];
switch (someValue) {
case 0:
[self foo];
break;
case count:
[self bar];
break;
default:
break;
}
But compiler tolds:
Expression is not an integer constant expression
How to make const int from [array count]?

As the error suggests, the cases must all be constants. You'll need an if statement to check the dynamic case:
int count = [array count];
switch (someValue) {
case 0:
[self foo];
break;
default:
if (someValue == count)
[self bar];
break;
}

if(some value == 0) {
[self foo];
} else if (someValue == [array count]) {
[self bar]
}

Related

Error: index 1 beyond bounds for empty array

I have created an NSMutableArray to store some character there. When I'am adding some character there it gives me an error. Here my code:
#property(strong,nonatomic) NSMutableArray *actions; < ViewController.h
#synthesize actions; < ViewController.m
actions = [[NSMutableArray alloc]init];
switch ([sender tag]) {
case 0:
currentLabel = water;
[actions insertObject:#"0" atIndex:i];
i++;
break;
case 1:
currentLabel = coke;
[actions insertObject:#"1" atIndex:i];
i++;
break;
case 2:
currentLabel = fanta;
[actions insertObject:#"2" atIndex:i];
i++;
break;
}
Use [actions addObject:#"X"] instead. If the array does not have elements, you can't insert object at index 1.

Reusable method to check if all objects are unequal using valueForKey

I have been working with this method for hours. It is supposed to simply check if the attribute of the cards passed in as otherCards isEqual to the same attribute of this (self) instance of class. But I am tearing my hair out - it is giving false results
(BOOL)otherCards: (NSArray *)otherCards allHaveUnequalAttribute: (NSString *)key
{
NSArray *values = [NSArray arrayWithArray:[otherCards valueForKey:key]];
int countUnequalMatches = 0;
for (NSNumber *setValue in values) {
if (![[self valueForKey:key] isEqual:setValue]) {
countUnequalMatches++;}
}
NSLog(#"countUnequalMatches %d values count: %d", countUnequalMatches, [values count]);
if (countUnequalMatches == [values count]) return YES ?: NO;
}
It is called like this:
if ([self otherCards:otherCards allHaveUnequalAttribute:CARD_SHAPE]) {
NSLog(#"All unequal");
} else {
NSLog(#"One or more card equal");
}
I found the bug myself
if (countUnequalMatches == [values count]) return YES ?: NO;
should be:
if (countUnequalMatches == [otherCards count]) return YES ?: NO;
as I used the Set as an way to count unique items.
This is the sort of thing that predicates are very well suited to handle.
-(BOOL)otherCards: (NSArray *)otherCards allHaveUnequalAttribute: (NSString *)key
{
NSPredicate *pred = [NSPredicate predicateWithFormat:#"%K == %#", key, [self valueForKey:key]];
NSArray *equalCards = [otherCards filteredArrayUsingPredicate:pred];
return equalCards.count == 0;
}

insertObject: atIndex: - index 3 beyond bounds for empty array

I create an array based on a dictionaries key's:
factsBuiltArray = [NSMutableArray arrayWithCapacity: 6];
if ([statusDict count] == 10) {
for (NSString *key in [statusDict allKeys]) {
if ([key isEqualToString: #"currenciesAndConversions"]) {
[factsBuiltArray insertObject:key atIndex: 0];
}
else if ([key isEqualToString: #"languageAndTranslations"]) {
[factsBuiltArray insertObject:key atIndex: 1];
}
else if ([key isEqualToString: #"plugSize"]) {
[factsBuiltArray insertObject:key atIndex: 2];
}
else if ([key isEqualToString: #"timezone"]) {
[factsBuiltArray insertObject:key atIndex: 3]; // crashes over here
}
else if ([key isEqualToString: #"population"]) {
[factsBuiltArray insertObject:key atIndex: 4];
}
else if ([key isEqualToString: #"wikipedia"]) {
[factsBuiltArray insertObject:key atIndex: 5];
}
}
}
The crash log is:
*** -[__NSArrayM insertObject:atIndex:]: index 3 beyond bounds for empty array
Why does inserting an object to an array that is specified with a capacity of 6 make it crash? Very confusing!
The capacity is merely how many objects a container class can hold. Inserting at an index requires that index to be a valid placement for the new object based on the total number of objects contained in the container (not the total number of objects that CAN be contained).
If your array's values are index dependent (which is seems like perhaps a different architecture or data structure would be better) then you can ensure that every index is filled by prepopulating the array with NSNulls. This would require you to check for NSNulls when reading from the array later on though which would likely be extra work, hence why this is probably not the best approach. In any case, you can change your code to the following to fix your crash.
factsBuiltArray = [NSMutableArray arrayWithCapacity: 6];
for (NSUInter i = 0; i < 6; i++) {
[factsBuiltArray addObject:[NSNull null]];
}
if ([statusDict count] == 10) {
for (NSString *key in [statusDict allKeys]) {
if ([key isEqualToString: #"currenciesAndConversions"]) {
[factsBuiltArray replaceObjectAtIndex:0 withObject:key];
}
else if ([key isEqualToString: #"languageAndTranslations"]) {
[factsBuiltArray replaceObjectAtIndex:1 withObject:key];
}
else if ([key isEqualToString: #"plugSize"]) {
[factsBuiltArray replaceObjectAtIndex:2 withObject:key];
}
else if ([key isEqualToString: #"timezone"]) {
[factsBuiltArray replaceObjectAtIndex:3 withObject:key];
}
else if ([key isEqualToString: #"population"]) {
[factsBuiltArray replaceObjectAtIndex:4 withObject:key];
}
else if ([key isEqualToString: #"wikipedia"]) {
[factsBuiltArray replaceObjectAtIndex:5 withObject:key];
}
}
}

ARC conversion issue with handleSearchForTerm delegate method

since converting to ARC (automatically) i have noticed with my uisearchviewcontroller delegate an issue somewhere (i think in the first if statement below). It was changed as a result but either way my app crashes when i try to perform a search:
The current code:
[self setSavedSearchTerm:searchTerm];
if ([self searchResults] == nil)
{
NSMutableArray *array = [[NSMutableArray alloc] init];
[self setSearchResults:array];
array = nil;
}
[[self searchResults] removeAllObjects];
if ([[self savedSearchTerm] length] != 0)
{
for (KABrand *currentBrand in [self brands])
{
if ([currentBrand.name rangeOfString:searchTerm options:NSCaseInsensitiveSearch].location != NSNotFound)
{
if (![searchResults containsObject:currentBrand])
[[self searchResults] addObject:currentBrand];
}
}
}
The previous code:
- (void)handleSearchForTerm:(NSString *)searchTerm
{
[self setSavedSearchTerm:searchTerm];
if ([self searchResults] == nil)
{
NSMutableArray *array = [[NSMutableArray alloc] init];
[self setSearchResults:array];
[array release], array = nil;
}
[[self searchResults] removeAllObjects];
if ([[self savedSearchTerm] length] != 0)
{
for (KABrand *currentBrand in [self brands])
{
if ([currentBrand.name rangeOfString:searchTerm options:NSCaseInsensitiveSearch].location != NSNotFound)
{
if (![searchResults containsObject:currentBrand])
[[self searchResults] addObject:currentBrand];
}
}
}
}
Thanks for your help in advance!
Thanks guys
Here is one potential problem: -rangeOfString:options: may return an NSNotFound. But you are checking if the range.location != NSNotFound.
If is if the return value of -rangeOfString:options: is NSNotFound, your if statement becomes NSNotFound.location != NSNotFound. I don't believe that's allowed.

How to Compare between Objects property's then sort using ( sortusingselector:#selector)?

I'm trying to write a simple function == " compareGPA" that compares between the GPA of two students , then sorting them in descending order by using selector as that : [array sortUsingSelector:#selector(compareGPA:)];
I've tried to write the function in 2 different ways , but nothing works ,
First way :
+(NSComparisonResult) compareGPA: (Student *) OtherStudent{
Student *tmp =[Student new];
if ([OtherStudent getGpa] < [tmp getGpa]){
return (NSComparisonResult) tmp;
}
if([tmp getGpa] < [OtherStudent getGpa])
{ return (NSComparisonResult) OtherStudent; }
}
2nd way :
+(NSComparisonResult) compareGPA: (Student *) OtherStudent{
NSComparisonResult res;
res = [[self getGpa] compare: [OtherStudent getGpa]];
return res;
Switch (res)
{
case NSOrderedAscending:
return NSOrderedDescending;
break;
case NSOrderedDescending:
return NSOrderedAscending;
break;
default:
return NSOrderedSame;
break;
}
}
Output : Nothing
Any suggestions ??
You should make your caparison method
+(NSComparisonResult) compareGPA: (Student *) OtherStudent
an instance method (not a class method, + becomes -), so that it compares the receiver's GPA with OtherStudent's GPA), like this
-(NSComparisonResult) compareGPA: (Student *) OtherStudent {
// if GPA is a float int double ...
if ([OtherStudent getGpa] == [self getGpa]
return NSOrderedSame;
if ([OtherStudent getGpa] < [self getGpa]){
return NSOrderedAscending;
return NSOrderedDescending;
// if GPA is an object which responds to the compare: message
return [[self getGPA] compare:[OtherStudent getGPA]]
}
Then sort your array of Student objects using selector #selector(compareGPA:)
As you're using compare: I have to assume that getGPA returns an NSNumber, in which case all you'd need would be this:
NSArray *students = ...;
NSArray *sortedStudents = [students sortedArrayUsingDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:#"getGPa" ascending:NO]]];
If getGPA however was to return some primitice C type (such as float in your case), then you could do it this way:
NSArray *students = ...;
NSArray *sortedStudents = [students sortedArrayUsingComparator:^NSComparisonResult(Studen *student1, Studen *student2) {
float student1GPA = [student1 getGPA];
float student2GPA = [student2 getGPA];
if (student1GPA < student2GPA) {
return NSOrderedAscending;
} else if (student1GPA > student2GPA) {
return NSOrderedDescending;
}
return NSOrderedSame;
}];
If if you need the compareGPA: elsewhere, too:
- (NSComparisonResult) compareGPA:(Studen *otherStudent) {
float student1GPA = [self getGPA];
float student2GPA = [otherStudent getGPA];
if (student1GPA < student2GPA) {
return NSOrderedAscending;
} else if (student1GPA > student2GPA) {
return NSOrderedDescending;
}
return NSOrderedSame;
}