Checking if an array contains a certain object (iOS) - ios

I need to check if a certain array contains a certain object, and if it does, delete that object. If it hasn't got that object, the funciton is suposed to add it into the array. The problem is that the object is always added because the checking statement always return false.
Here's my current function:
- (void) myFunction:(NSString *)parameter {
if (![myMutableArray containsObject:parameter]) {
[myMutableArray addObject:parameter];
NSLog(#"%# added", parameter);
} else {
[myMutableArray removeObject:parameter];
NSLog(#"%# deleted", parameter);
}
}

containsObject is calling isEqual on each of the object in the arrays. What type of object are you checking for? If it's a custom object, override and implement the method isEqual.
I'm guessing you're trying to check the value of the object, but containsObject is actually calling isEqual which is comparing the reference to the object, and not its actual value.

if (![arrList containsObject:arrObj]) {
// do something
}
containsObject:

First you need to check which type data or object you are adding in this myMutableArray. According to your method you are checking in mutable array for string type that you have passed argument parameter. It may be possible that you are containing int or float array.
There may be issue of type casting in your array.If your is STRING type of data then you can use another method like this.
- (void) myFunction:(NSString *)parameter {
for (int i = 0 ; i < [myMutableArray count ] ; i++) {
if (![[myMutableArray objectAtIndex:i] isEqualToString:parameter]) {
[myMutableArray addObject:parameter];
NSLog(#"%# added", parameter);
}
else{
[myMutableArray removeObject:parameter];
NSLog(#"%# deleted", parameter);
}
}
}
Hope this will help you. If your object is not type of NSString then you need to convert.

You should implement isEqual: in your custom class. By default two objects are only identical if they share the same reference.
Also make sure to initialize your mutable array before using it.
EDIT:
It seems that your array's variable name are most probably mistyped.
myMutableArray
myMutbaleArray

You probably forgot to initialize your NSMutableArray. If not initialized, you are sending addObject messages to a nil object, which has no effect, and the array never contains what you previously added...
Of course, if the array is nil, then the contains check will always return false. According to the Objective-C docs:
If the method returns an object, any pointer type, any integer scalar
of size less than or equal to sizeof(void*), a float, a double, a long
double, or a long long, then a message sent to nil returns 0.
And 0 is false

Related

Customized NSLog to print all type of objects

I'm trying to extend NSLog that can print any type of object. Means, my custom class gets the value that need to be printed from the user and checks its class type and then it will print as desired format.
Consider my extended class name is, MyLog (So it contains MyLog.h and MyLog.m)
MyLog.h:
void MyLog (id objectValue);
MyLog.m:
#import "MyLog.h"
void MyLog (id objectValue)
{
if ([objectValue isKindOfClass:[NSString class]])
{
NSLog(#"%#",objectValue); //Same for NSArray, NSDictionary, NSMutableArray, NSMutableDictionary
}
else if ([objectValue isKindOfClass:[NSData class]])
{
NSLog(#"%#",[[NSString alloc]initWithData:objectValue encoding:NSUTF8StringEncoding]);
}
....
....
}
So, if I include this class (MyLog.h) in prefix file, I can call the below method from any class to simply print the given object.
MyLog(valueOfObject);
Problems:
The CGRect, CGpoint, CGSize related things (which are not an object) can not be passed as id to MyLog() function.
I tried to print the object name along with its value for more readability. Refer this post.
For example,
NSString *myString = #"Welcome";
MyLog(myString);
This will print myString: Welcome instead of just printing Welcome.
I can achieve this my defining a preprocessor like
#define MYLOG(x) NSLog( #"%s:%#",#x, x)
So, I tried to customize it in the following way
#define MYLOG(x) NSLog(#"%s:%#",#x, MyLog(x))
But it throws "Argument type 'void' is incomplete" error.
Questions:
How can I pass non objects as id to a function?
How can I call a function within a preprocessor macro?
Help needed!! Just Confused!!
If you implement -(NSString*)description you can print any object in NSLog with NSLog(#"%#", myObject).
So just add -(NSString*)description in the classes of objects that you want to print out, and in them just return the NSString value that you think is relevant for that object.

How can I check for an empty object within an NSArray

I'd like to check for an empty object (i.e. an object of an array which doesn't have a value) within an array which gets its data from a file.
As an example, if my array contains 12 objects (all NSString) and the object at index 11 doesn't return a value when its description is printed into the debug section of Xcode. I want to check if that is the case and respond accordingly. I already tried
if (!([MY_ARRAY objectAtIndex:11] == nil))
{
//Some Stuff
}
else
{
//Some other Stuff
}
which didn't work.
Any help is appreciated.
The description method is for debugging. You should not use it in your program logic. What are these objects, and what do they contain? Can you modify the objects to add an "isEmpty" property?
If you use NSNull, you'd use code like this:
NSArray *array = #{#"String", #(4), [NSNull null], #"Another string");
for (id anObject in array)
{
if (anObject =! [NSNull null]))
{
//Some Stuff
}
else
{
//Some other Stuff
}
}
You can check the length of the string: [string length] > 0
an object is an array cannot be nil, but you can use [NSNull null] which is an "object equivalent" to nil
As Jerome Diaz states, objects in an array can't be nil. The only option you have is to check the count property of the array if it reflects an expected value, or you can inspect the type/class of the object in the array. A safe way to include empty object into array is [NSNull null], but this is the task for the method that fills the array, not the one that reads it.
You can check the class type of an object in array with isKindOfClass or isMemberOfClass.

how to handle boolean value with AFNetworking parsing JSON

I have some JSON that comes back like this:
"items":[
{
"has_instore_image": false
}
]
If I output the value like this:
NSLog(#"has_instore_image val: %#", [item objectForKey:#"has_instore_image"]);
I get
has_instore_image val: 0
but if I test like this:
if([item objectForKey:#"has_instore_image"]==0){
NSLog(#"no, there is not an instore image");
}else{
...
It always goes to the else statement... hmmm.. How would you suggest I get the BOOL value and test? I've read through the BOOL questions here and am just confused this is not working as I'd anticipate.
thx
NSDictionary's instance method objectForKey returns an id, not a primitive value.
If it's a boolean, int, float, etc number-like value in JSON, it will serialized to an NSNumber by Apple's NSJSONSerialization class and most/all other common JSON parsers in iOS.
If you want to get the BOOL value out of it, you can do something like this:
BOOL has_instore_image = [[item objectForKey:#"has_instore_image"] boolValue];
You are comparing a pointer with an integer here
[item objectForKey:#"has_instore_image"]==0
You should use
[item objectForKey:#"has_instore_image"].integerValue==0
Also note that a BOOL of NO equals 0.
The NSLogstatement in your code prints a 0, but only because if you give NSLogan object as parameter, the objects descriptionis called.
i will suggest to hold these id type (returned from dictionary) to NSNumber .
NSNumber *boolNum=(NSNumber*)[item objectForKey:#"has_instore_image"];
after that you can get bool value from boolNum
[boolNum boolValue]
try this
if([boolNum boolValue]==NO){
NSLog(#"no, there is not an instore image");
}else
{
}

How to add string object in nsmutable array if some string is empty

arrdata=[[NSMutableArray alloc]initWithObjects:strname,strWeb,strAdd,strPhone,strrate, nil];
[arrAllData addObject:arrdata];
I fetched data from a webservice. in my condition if strweb has no value then it simply ignores other values like stradd,sphone and strrate. How can I solve this problem?
you can do like this in a simplest way.
if(strweb==nil)
{
strweb=#"null";
}
Note: pass null in <> bracket;
Try this code,
if(strWeb == nil){
strWeb = [NSString stringWithFormat:#"%#", [NSNull null]];
}
arrdata=[[NSMutableArray alloc]initWithObjects:strname,strWeb,strAdd,strPhone,strrate, nil];
[arrAllData addObject:arrdata];
When your any object nil while creation time of array then your array will be end with than object and remaining objects will discards. That why you need to check every object should not be nil according above code stuff then add it into array.
If strWeb is nil then your array structure will be
arrdata=[[NSMutableArray alloc]initWithObjects:strname,nil]; future object will discard.,strAdd,strPhone,strrate,
output of arrdata containg only one object strname
Other way,
Set any default value if your string is nil. for example,
if(strWeb == nil){
strWeb = #"This Value is discarded"; // It could be anything identifier for your purpose.
}
arrdata=[[NSMutableArray alloc]initWithObjects:strname,strWeb,strAdd,strPhone,strrate, nil];
[arrAllData addObject:arrdata];
While retrieving time you can match above string with value inside the object.
You use the initializer -initWithObjects:. As you know the object list is terminated with nil. If one of the references has the value nil, -initWithObjects: thinks that this is the terminator.
Check the references (i. e. strweb). If it is nil, assign a default value to it or do not encounter the variable in the list.

NSMutableArray or NSMutableDictionary : which is best for this scenario?

I need to scroll through several thousands of words to categorize them... to determine which words have the same pattern. (this part works)
For example, a four letter word that has two m's in 2nd & 4th position represent a pattern ("-m-m"). Once I have gone through all the words, I will know how many words there are for any given pattern. I am scrolling through now, but the problem I have is 'remembering' how many words I have in any given pattern.
I was thinking of using NSMutableDictionary and have the key be the pattern ('-m-m-') and the object represent the count of that pattern. This means every time I come across a pattern, I look up that pattern in the dictionary, get the key, increment the key, and put it back in the dictionary.
I need help with both the decision and syntax for performing this task.
Thank You
The answer to your question was this part of your (given) question "I will know how many words there are for any given pattern.". I would use an array of dictionary. You use the dictionary to store key value pair: a known pattern and the count. And you use the array to store those KVP records. So the next time you detect a pattern, search for the array for that record (dictionary), if found, increment the count. If not, create new record and set the count to 1.
Added sample code:
#define kPattern #"Pattern"
#define kPatternCount #"PatternCount"
-(NSMutableDictionary *)createANewDictionaryRecord:(NSString *) newPattern
{
int count = 1;
NSMutableDictionary *myDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:
newPattern, kPattern,
[NSString stringWithFormat:#"%i",count], kPatternCount,
nil];
return myDictionary;
}
-(void)addANewPatternToArray:(NSMutableDictionary *)newDictionary
{
// NSMutableArray *myArrayOfDictionary = [[NSMutableArray alloc]init]; // you need to define it somewhere else and use property etc.
[self.myArrayOfDictionary addObject:newDictionary]; //or [self.myArrayOfDictionary addObject:newDictionary]; if you follow the recommendation above.
}
-(BOOL)existingPatternLookup:(NSString *)pattern
{
for (NSMutableDictionary *obj in self.myArrayOfDictionary)
{
if ([[obj objectForKey:kPattern] isEqual:pattern])
{
int count = [[obj objectForKey:kPatternCount] intValue] + 1;
[obj setValue:[NSString stringWithFormat:#"%i",count] forKey:kPatternCount];
return YES;
}
}
[self.myArrayOfDictionary addObject:[self createANewDictionaryRecord:pattern]];
return NO;
}
-(void)testData
{
NSMutableDictionary *newDict = [self createANewDictionaryRecord:#"mmm"];
[self addANewPatternToArray:newDict];
}
-(void) printArray
{
for (NSMutableDictionary * obj in self.myArrayOfDictionary)
{
NSLog(#"mydictionary: %#", obj);
}
}
- (IBAction)buttonPressed:(id)sender
{
if ([self existingPatternLookup:#"abc"])
{
[self printArray];
} else
{
[self printArray];
}
}
Not being an objective C expert but solving this problem in java before, I would say a dictionary(I used a map when doing it in java) is the best way. Check if the key(pattern) already exist if so increment that count else put a new one in the dictionary.
EDIT
If you want to not just get the count of a pattern, but in fact tell which words fall under that pattern, I would use a dictionary of strings to mutable arrays. In the arrays you store the words and the key to the array is the pattern(as a string), similar code as above but instead of just incrementing the count, you have to add the new word to the array.
The only difference in NSDictionary and NSMutableDictionary is that one can have objects added to it. I think your implementation is good, but English is a complex language. It would be more efficient to parse out the string with regex than to set a key for it.
Why don't you use NSCountedSet instead:
NSCountedSet Class Reference
..which is available in iOS 2.0 and later?
Each distinct object inserted into an NSCountedSet object has a counter associated with it. NSCountedSetkeeps track of the number of times objects are inserted [...] Thus, there is only one instance of an object in an NSSet object even if the object has been added to the set multiple times. The count method defined by the superclass NSSet has special significance; it returns the number of distinct objects, not the total number of times objects are represented in the set.
Then use:
- (NSUInteger)countForObject:(id)anObject
Use a dictionary of NSMutableArrays, and check for the existence of each search key as you recommended. If the key doesn't exist, add an NSMutableSet or NSMutableArray (depending on your needs) for the searched key type "-m-m" for example, and then add to the set or array for that key.

Resources