Writing a for loop in Objective C way - iphone

I have a doubts in writing a for loop in Objective C way. I can do the same loop in traditional C for loop, However I am trying to learn Objective C. Here is my question.
listdata is a mutable array holding objects of ofi_vc_modal_ab_user_info objects, I want to compare each email of list data with email until list data count and find its position and if found I want to delete the object from list data.
for (ofi_vc_modal_ab_user_info *loc_obj in listData)
{
if (strcasecmp(loc_obj->email, email) == 0) {
// What need to do here.
}
}
How to proceed here... thanks for your helps :)

you can just use C's for.
in fact, it's an error to mutate the collection you iterate over when using for (e in collection).

BOOL foundObject = NO;
ofi_vc_modal_ab_user_info *loc_found_obj = nil;
for (ofi_vc_modal_ab_user_info *loc_obj in listData)
{
if (strcasecmp(loc_obj->email, email) == 0) {
// Set your flag here
loc_found_obj = loc_obj;
foundObject = YES;
break;
}
}
if(foundObject) {
// Do your stuffs as object is found
// Your found object is in loc_found_obj
[listData removeObject:loc_found_obj];
}
I hope below code explains what you want. Please explain bit more if you need more help.
EDIT : If you are using NSMutableArray then you do not need index of the object. you can directly delete object as mentioned in my edited code.

Related

How to perform logic if findBy’Field’ does match?

I trying to do some logic if my inputed form email matches one found in the database.
How do I make the comparison if the findBy’Field” returns the whole collection instead of just the field I want to compare to? I'd think it should be done without using a foreach loop as that would kinda defeat the purpose of using my findBy method.
An Example:
$formEmail = $form->get('email')->getData();
existingEmail = $em->getRepository(‘UserBundle:User’)->findOneByEmail($formEmail);
// or existingEmail = $em->getRepository(‘UserBundle:User’)->findByEmail($formEmail);
if ($formEmail == $loggedEmail){
//perform some logic here
}
try this
$formEmail = $form->get('email')->getData();
$existingEmail = $em->getRepository('UserBundle:User')->findOneByEmail($formEmail);
if ($existingEmail){
//found
}else{
//not found
}

Unsolvable memory leak IPhone

I am new to IPhone programming and am I having trouble solving the following memory leak.
while(numDeckCounter < numDecks){
int cardCounter=1;
for (int i =1; i<=52; i++) {
tempCard = [Card new]; //leaks tool says that this is leaking object
if(i>=1 && i<=13)
{
tempCard.suit = CLUBS;
tempCard.faceValue = cardCounter;
[deckArr addObject:tempCard]; //reference count 2
cardCounter++;
}
else if(i>=14 && i<=26)
{
tempCard.suit = DIAMONDS;
tempCard.faceValue = cardCounter;
[deckArr addObject:tempCard];
cardCounter++;
}
else if(i>=27 && i<=39)
{
tempCard.suit = HEARTS;
tempCard.faceValue = cardCounter;
[deckArr addObject:tempCard];
cardCounter++;
}
else
{
tempCard.suit = SPADES;
tempCard.faceValue = cardCounter;
[deckArr addObject:tempCard];
cardCounter++;
}
if(cardCounter ==14){
cardCounter=1;
}
[tempCard release]; //this causes an EXC_BAD_ACCESS -reference count should be 1
}
numDeckCounter++;
}
I was under the impression that adding an object to the array would increase its reference count by one, then it would be safe to release the object you just added because it would not be deallocated until the array was released bumping which would then release each object in the array. This is when the object should finally be deallocated.
When I add the [tempCard release]; it crashes my app because it can't access the memory location because it has already been deallocated.
From everything I have read, I think what I said above is true. Someone please correct me if I am wrong. Thanks.
I don't see any leaks in the code you presented. (There are some opportunities to slim it down, though, say by moving the identical operations out of the conditionals).
The Leaks tool output is pretty tricky to read. Is it possible that the Card object is leaking one of it's ivars?
Instead of leaks, run static analysis on your product (Product->Analyze). I think it will flag a different part of your code.
Perhaps try [[Card alloc] init] instead of [Card new]. This is just a guess. However trying the IMO more common method of object creation could be helpful.
Check this out: Use of alloc init instead of new
You could also try removing all the code for adding the Cards to the array. So you'd essentially have:
card = [Card new];
[card release];
This could help you find memory issues associated w/ the array retaining the object perhaps?

Add object to sorted NSMutable array and answer index path

I have a sorted mutable array of a class called Topic. The topics represent a an array of Publications. I present the topics in a table, and periodically fetch new publications from a web service. When a new publication arrives, I'd like to add to the table with an animation.
What's bothering me is the computational work I need to do to add into this array, and answer the correct index path. Can someone suggest a more direct way than this:
// add a publication to the topic model. if the publication has a new topic, answer
// the index path of the new topic
- (NSIndexPath *)addPublication:(Publication *)pub {
// first a search to fit into an existing topic
NSNumber *topicId = [pub valueForKey:#"topic_id"];
for (Topic *topic in self.topics) {
if ([topicId isEqualToNumber:[topic valueForKey:"id"]]) {
// this publication is part of an existing topic, no new index path
[topic addPublication:pub];
return nil;
}
}
// the publication must have a new topic, add a new topic (and therefore a new row)
Topic *topic = [[Topic alloc] initWithPublication:publication];
[self.topics addObject:topic];
// sort it into position
[self.topics sortUsingSelector:#selector(compareToTopic:)];
// oh no, we want to return an index path, but where did it sort to?
// yikes, another search!
NSInteger row = [self.topics indexOfObject:topic];
return [NSIndexPath indexPathForRow:row inSection:0];
}
// call this in a loop for all the publications I fetch from the server,
// collect the index paths for table animations
// so much computation, poor user's phone is going to melt!
There's no getting around the first search, I guess. But is there some more efficient way to add a new thing to an array, maintaining a sort and remembering where it got placed?
It's pretty straightforward to insert a value into a sorted list. Think about how you would insert the number "3" into the list "1, 2, 7, 9", for instance. You want to do exactly the same thing.
Loop through the array by index, using a for loop.
For each object, use compareToTopic: to compare it to the object you want to insert.
When you find the appropriate index to insert at, use -[NSArray insertObject:atIndex:] to insert it.
Then return an NSIndexPath with that index.
Edit: and, as the other answers point out, a binary search would be faster -- but definitely trickier to get right.
This is almost certainly not an issue; NSArrays are actually hashes, and search is a lot faster than it would be for a true array. How many topics can you possibly have anyways?
Still, if you measure the performance and find it poor, you could look into using a B-tree; Kurt Revis commented below with a link to a similar structure (a binary heap) in Core Foundation: CFBinaryHeap.
Another option (which would also need to be measured) might be to do the comparison as you walk the array the first time; you can mark the spot and do the insertion directly:
NSUInteger insertIndex = 0;
NSComparisonResult prevOrder = NSOrderedDescending;
for (Topic *topic in self.topics) {
NSComparisonResult order = [topicId compareToTopic:topic];
if (NSOrderedSame == order) {
// this publication is part of an existing topic, no new index path
[topic addPublication:pub];
return nil;
}
else if( prevOrder == NSOrderedDescending &&
order == NSOrderedAscending )
{
break;
}
insertIndex++;
prevOrder = order;
}
Please note that I haven't tested this, sorry.
I'm not sure this is actually better or faster than the way you've written it, though.
Don't worry about the work the computer is doing unless it's demonstrably doing it too slowly.
What you have done is correct I guess. There's another way. You can write your own binary search implementation method. (Which has only few lines of code). And you can retrieve the index where the new object should fit in. And add the new object to the required index using insertObject:atIndex: method.

Pass a block of code?

Is it possible to pass a block of code, for example:
int i = 0;
while (i < [array count]) {
//Code to pass in here
i++;
}
Reason being that i need to perform various actions on every item in an array at different times, it'd be nice to have 1 method and pass it a block of code to run.
Have you considered using blocks. It's just an idea and not working or compilable code
typedef int (^block_t)();
-(void) methodName:(block_t) code_block
{
int i = 0;
while (i < [array count]) {
code_block() //Code to pass in here
i++;
}
block_t youCode = ^{ NSLog("Just an example"); }
[self methodName:youCode];
You can definitely iterate an array and process a block of code on it. This feature has been a standard part of Objective C since 2.0, iOS since 4.0 and in addition was included in Snow Leopard. If you look up the NSArray class reference you will find the following functions:
enumerateObjectsAtIndexes:options:usingBlock:
Executes a given block using the
objects in the array at the specified
indexes.
enumerateObjectsUsingBlock: Executes a
given block using each object in the
array, starting with the first object
and continuing through the array to
the last object.
enumerateObjectsWithOptions:usingBlock:
Executes a given block using each
object in the array.
You can define the code block to be executed globally in your implementation file, or in place where its needed. You can find some good examples on block programming here: http://thirdcog.eu/pwcblocks/.
It sounds like you want "blocks", which are a feature of Objective-C similar to "lambdas", "anonymous functions" and "closures" in other languages.
See Apple's documentation: Blocks Programming Topics
You should put the code into a method and call the method like so:
-(void)foo{
int i = 0;
while (i < [array count]) {
[self myMethod];
i++;
}
}
-(void)myMethod{
//Code to pass in here
}
You could also store the method as a variable allowing you to change which method is called
SEL methodToCall = #selector(myMethod);
-(void)foo{
int i = 0;
while (i < [array count]){
[self performSelector:methodToCall];
i++;
}
}
-(void)myMethod{
//Code to pass in here
}
first of all you could give a more detailed example.
second you could take a look at Action or Func in case you need a return message (well something equivalent for obj-C if exists)
but again, not understanding what you need to do, it is hard to give you an answer
cause from you Q i could understand as #Trevor did that you need to run a method:
int i = 0;
while (i < [array count]) {
if (i % 2)
EvenMethod(array[i])
else
OddMethod(array[i])
i++;
}
If you can live with 4.0+ compatibility, I highly recommend the use of blocks.
- (void)enumerateObjectsUsingBlock:(void (^)(id obj, NSUInteger idx, BOOL *stop))block
gives you all you need and you can define your block right where you need it. There are some other variants of this, too. Please refer to the 'NSArray' documentation.
Why not just define functions that do what you want, and call them at various times with the items in your array as arguments?
If your concern is that you don't want redundant code with multiple while loops you have here, you could write a function that takes an array and a function as an argument, then applies that function to every element in the array.
Adapted from here:
//------------------------------------------------------------------------------------
// 2.6 How to Pass a Function Pointer
// <pt2Func> is a pointer to a function which returns void and takes an NSObject*
void DoForAllItems( NSArray* array, void (*pt2Func)(NSObject*) )
{
int i = 0;
while (i < [array count]) {
(*pt2Func)([array objectAtIndex:i]);
i++;
}
}
// 'DoIt' takes an NSObject*
void DoIt (NSObject* object){ NSLog(#"DoIt"); }
// execute example code
void Pass_A_Function_Pointer()
{
NSArray* array= [NSArray arrayWithObjects:#"1", #"2", nil];
DoForAllItems(array, &DoIt);
}
http://thirdcog.eu/pwcblocks/#objcblocks
Blocks were added recently to Objective-C I hope they have found their way to the Iphone also.
and it was anwered here also before:
Using Objective-C Blocks
Regards
If you are using Objective C++, I would strongly recommend function objects (even over blocks). They have a nice syntax, are easy to use, and are supported everywhere on modern C++ compilers (MSVC++11, GNUC++11, and LLVMC++11):
void go( function<void (int arg)> func )
{
int i = 0;
while (i < [array count]) {
//Code to pass in here
func( i ) ; // runs func on i
i++;
}
}
calling it:
go( []( int arg ){ // the square brackets are the "capture"
printf( "arg was %d\n", arg ) ; // arg takes on whatever value was passed to it,
// just like a normal C function
} ) ;

hot do i make a comparison of integers and values of text box in Objective C

i'm new to iphone programming and i encountered/noticed some problems while i was coding. which was after i typed a statement like
if (label.text > label2.text) {
do something...}
however, after typing my application can be compiled and run however when i try to validate it by comparing the values, my specified actions can run and i can change my image view image, however the conditions is not true but the specified actions can be run. Do enlighten me thanks! i will post my codes at the bottom, do comment if you spot any better practices? thanks once again.
Oh and how can i specify to check in my label that the default value is not "Label" or empty because i would like the values to be populated with number before commencing.
-(IBAction) beginMatch {
if (resultP1.text, resultP2.text = #"Label") {
errorMsg.text = #"Please Press Roll (:";
}
else
if (resultP1.text > resultP2.text) {
MG = [MainGameController alloc];
MG.player1 = playerName.text;
}
else {
MG.player1 = playerNameP2.text;
}
[self.view addSubview:MG.view];
}
this is one example that it does not work i have another one which is below.
-(IBAction) btn:(id) sender {
ptc = [playerTurnController alloc];
if (ptc.player1name = MGplayerName.text) {
if (lblDiceResultP1.text > lblDiceResultP2.text) {
img.image = [UIImage imageNamed:#"yellow.png"];
}
else if (ptc.player2name = MGplayerName.text) {
img.image = [UIImage imageNamed:#"Blue.png"];
}
}
}
Thank you.
Your code contains quite a few errors. You're trying to compare NSString values with ">", you're using the comma operator and = operator incorrectly, and you're allocating new objects in (what look to be) the wrong places.
You really should work your way through the introductory documentation on Apple's developer website first:
Learning Objective-C: A Primer
and
Your First iPhone Application
In here you're comparing string (alphabetically) addresses:
lblDiceResultP1.text > lblDiceResultP2.text
You probably want to extract NSNumbers of out the strings and compare the numeric values.
This here is an assignment and not a comparison:
ptc.player2name = MGplayerName.text
You probably meant to use == which is also wrong.
NSStrings are compared with the isEqualToString e.g.
NSString * s1 = #"String One";
NSString * s2 = #"String Two";
if([s1 isEqualToString:s2])
// do something when strings are equal