While-Loop works but not the if statement? - iphone

I have this while loop in my code. The loop seems to work fine since I printed my i++ in the console. But for some reason it only checks my if statement the first time around. I can only add one title into the NSMutableArray called sectionZeroTitleArray. I have many arrays in this loop so it might get confusing. I will try my best to explain.
Here is what I am trying to do:
Loop through the length of an array(topicArray). If the array's(topicArray)is the same as this other array's(anotherArray) first object then add an object that has the same index(titleArray) as topicArray to a new MutableArray(sectionZeroTitleArray).
I'm sure I did something stupid, maybe someone that hasn't stared at this all day can fix me up? Please and thank you.
while (i < (topicArray.count)) {
if ([topicArray objectAtIndex:i] == [anotherArray objectAtIndex:0]) {
[sectionZeroTitleArray addObject:[titleArray objectAtIndex:i]];
}
NSLog(#"sectionZeroLoopCount: %d", i);
i++;
}

You are checking for pointer equality when you use ==. Are you sure you want to do this? What is the type that you're expecting? If it's a NSString, use isEqualToString:, otherwise use NSObject's isEqual: method:
If the expected type is an NSString:
if([[topicArray objectAtIndex:i] isEqualToString:[anotherArray objectAtIndex:0]]) {
//...
}
Otherwise, you should probably do this:
if([[topicArray objectAtIndex:i] isEqual:[anotherArray objectAtIndex:0]]) {
//...
}

Yeah, you're comparing the pointers and not the values. Look at the documentation of NSString, particular the isEqualToString: method for comparing strings.

Related

More efficient way to iterate through an array of NSStrings and compare them

I'm just looking for a nicer and more efficient way to iterate through a given array of objects and compare a NSString property of each to another array just containing NSStrings.
My current code uses two for-each loops but it don't think that it is the most efficient way.
for (MYClass *foo in arrayOfMyClass) {
for (NSString *ID in arrayOfStringIDs) {
if ([foo.Id isEqualToString:ID]) {
//Do something
break;
}
}
}
I think that it should be somehow possible to drop at least one loop with some cool tricks.
If all you want to know is if foo.Id exists in arrayOfStringIDs, use an NSSet of strings instead. Then you can do:
NSSet * mySetOfStringIDs = [NSSet setWithArray:arrayOfStringIDs];
for(MyClass * foo in arrayOfMyClass) {
if([mySetOfStringIDs containsObject:foo.Id]) {
// Do something
break;
}
}
This avoids the second loop, since containsObject: is generally much faster than O(n) for a set. You should, of course, do your own profiling as needed.
Check for indexofobject method of Nsarray. May be it can help you to get the index directly instead of a loop for the string in nsarray.
If you want to get an array of strings that exist in both arrayOfMyClass and arrayOfStringIDs then you could use key-value coding to pull the set of strings out of arrayOfMyClass and intersect the resulting set with arrayOfStringIDs. If your class is KVC compliant then you can get all the Id strings out of it as a set:
NSMutableSet *idSet=[NSMutableSet setWithArray:[arrayOfMyClass
valueForKeyPath:#"#distinctUnionOfObjects.Id"]];
[idSet intersectSet:[NSSet setWithArray:arrayOfStringIDs]];
NSArray *idArray=[idSet allObjects];
Unfortunately there is not a method to intersect two NSArrays which is why they have to be turned into a set first.

Accessing value from array of objects

I am having two arrays, Namely
NMutableArray* first;
NMutableArray* second;
Now I am copying first object to the second array like
for (int i=0;i<first.count; i++)
{
[second addObject:[first objectAtIndex:i];
}
This is ok. I don't know how to access the value of the First Array. I tried like this ,
[second addObject:[[first objectAtIndex:i]name]];
I want to get the name value which is in the first object of first array. I tried using the above line, it is showing some warning. Please help me
Assuming you started with an array like this:
NSArray *array1 = #[#{#name : #"Fred"},
#{#name : #"Bill"}];
You could create a second array that contains the value of a given property of each element of the first array as follows:
NSArray *array2 = [array1 valueForKey:#"name"];
If you then logged the second array...
NSLog(#"%#", array2);
...the resulting output would be
2012-04-18 16:26:11.226 ExampleRunner[23320:707] (
Fred,
Bill
)
EDIT
Note that this will work regardless of whether the objects in the first array are instances of NSDictionary as shown in the example above, or instances of a class or classes that have a name property or instance variable (or an _name instance variable, for that matter). For more information on how and why this works, see the documentation for the NSKeyValueCoding informal protocol:
http://developer.apple.com/library/ios/#DOCUMENTATION/Cocoa/Reference/Foundation/Protocols/NSKeyValueCoding_Protocol/Reference/Reference.html
The brackets are currently in the wrong place:
[second addObject:[[first objectAtIndex:i] name]];
Updated Answer:
Again, I think you should split stuff out into easy to parse lines of code:
for (id theObject in first)
{
// without an actual type, I still think the compiler might
// throw a warning on this next line of code;
// but maybe RJR III is correct and it won't warn.
// I didn't check.
NSString * nameOfObject = [theObject name];
if(nameOfObject)
{
[second addObject:nameOfObject];
}
}
Notice that I do some error checking in here as well (i.e. making sure the name is not nil).
Original Answer:
You're getting a warning because the compiler doesn't know what kind of custom object is being fetched from your call to "[first objectAtIndex: i]". In other words, it doesn't know what kind of object you're trying to get the "name" of.
Cast it to the right type and you'll get rid of the warning.
Or even better, split that one line of multiple things happening at once into two or three lines of code and make your code more readable in the process.

Why won't this simple 'if' statement work (inside fast enumeration)?

I am enumerating through the ChecklistItem entities in my table to see which ones have a priority (NSNumber attribute) of 1. checklistItems are in a to-many relationship with Checklist.
In this simple code, the first NSLog works fine, and reports that several of my ChecklistItems have a priority of 1. But the second NSLog never gets called. Why is this? I assume I'm framing the "if" statement wrong, but I don't know how.
for (ChecklistItem *eachItem in checklist.checklistItems){
NSLog(#"Going through loop. Item %# has priority %#.", eachItem.name, eachItem.priority);
if (eachItem.priority == [NSNumber numberWithInt:1]) {
NSLog(#"Item %# has priority 1", eachItem.name);
}
}
You're comparing the pointers of the return values of eachItem.priority and [NSNumber numberWithInt:1]. You should use NSNumber's equality method.
You can not compare objects as you did above. Use the following code.
for (ChecklistItem *eachItem in checklist.checklistItems){
NSLog(#"Going through loop. Item %# has priority %#.", eachItem.name, eachItem.priority);
if ([eachItem.priority intValue]== 1) {
NSLog(#"Item %# has priority 1", eachItem.name);
}
}
Thanks,
Well, you should be checking for value equality something like this:
if ( [eachItem.priority intValue] == 1 ) { ... }
However, I'm kind of surprised it doesn't accidentally work as it is, because I thought NSNumber pooled a few base instances and I'd expect 1 to be one of them. Relying on that would be very bad form, though, even if it happened to work in this case.

iPhone, objective c reassign and return pointer of method

Hey guys, lately I have been asking quite a few questions about memory management on the iPhone. Fortunately things are getting clearer. But I still struggle when it gets more complex: So is there something wrong with this in terms of memory mangement? My question and suggestions are in the comments...
//I get a text from a textfield
NSString *text = [[NSString alloc]initWithString:txtField.text];
NSMutableString *newText = [self replaceDynamicRegex:text];
[text release];
...
//The method replaces regex it finds in the text. The regex part is just pseudo code
//and I just interested in memory management
-(NSMutableString*)replaceDynamicRegex:(NSString*)txt{
NSString *currentTag = [NSString stringWithString:#"dynamiclyCreatedTag"];
//As long as we find a particuar regex (just pseuo code here) we replace it
while (currentTag != NULL) {
if([html stringByMatching:openingTag] == NULL){
break;
}
//regular expression
currentTag = [NSString stringWithString:[html stringByMatching:theRegex]];
//Get rid of the useless part of the currentTag pseudo code
NSString *uselessTagPart = #"uselessRegex";
//Reassignment of the pointer currentTag --> ok to do this? cause I did not alloc]init]?
//and instead used stringWithString wich then gets autoreleased
currentTag = [currentTag stringByReplacingOccurrencesOfRegex:uselessTagPart withString:#""];
//Reassignment of the pointer html --> Ok to do this? cause it is just a pointer and the
//object is being released after the method call (further up)
html = (NSMutableString*)[html stringByReplacingOccurrencesOfRegex:currentTag withString:replacementTag];
}
//Do I need to autorelease this?
return html;
}
Your code looks correct memory-management-wise. Just remember, if you don't have call a method with alloc, new, retain, or copy in the method name, you don't have to worry about releasing.
One small point--your first 3 lines of code are redundant and inefficient. You shouldn't usually use initWithString--copy is usually a better choice when dealing with immutable objects, since behind the scenes a copy method can be replaced by a (less expensive) retain method. In your case, you don't even need to use copy--[self replaceDynamicRegex: txtField.text] will have the same result. Likewise, instead of [NSString stringWithString:[html stringByMatching:theRegex]], you can use simply use [html stringByMatching:theRegex] (since that method returns a new string).
Another note--html = (NSMutableString*)[html stringByReplacingOccurrencesOfRegex:currentTag withString:replacementTag] is incorrect. stringByReplacingOccurrencesOfRegex: returns an NSString, which can't be cast to an NSMutableString (you'll likely get a crash later on when you send a mutating method to the string). Instead, use [[html stringByReplacingOccurrencesOfRegex:currentTag withString:replacementTag] mutableCopy]
Generally, when you see a method named xWithY, you can assume the string will be autorelease-d.
Therefore, you probably do not need to autorelease the value returned from -stringByReplacingOccurrencesOfRegex:withString:.
The rest of your code looks okay, to me.

how to write an If statement, to compare core data attribute value?

i'm an objective-c newcomer.
im trying to compare a core data entity attribute value and having trouble with the syntax.
i just want to know the best way way to write the if statement to compare values.
in this example, the someAttribute attribute is a boolean, and its default is NO.
NSString *myValue = [NSString stringWithFormat:#"%#", myObject.someAttribute];
if ([myValue isEqualToString:#"1"]) {
// do something
} else {
// do something else
}
is this the right way? i've tried other flavors, like below, but the results aren't accurate:
if (myObject.someAttribute == 1) {
if (myObject.someAttribute) {
If you look in the generated header for this entity, there's a good chance that the actual type of the property is not BOOL, but NSNumber, which is how Cocoa boxes numeric types into objects. Assuming I'm right, you might try:
if ([myObject.someAttribute boolValue]) { ... }
If your attribute is of BOOL type, this code will work fine
if(myObject.someAttribyte){
//so smth if someAttribute is YES
}
You can't convert a BOOL directly to a string.
Predicates are the preferred method of comparing CoreData values. It's more complicated to start but works better in the long run. See NSPredicate programming guide