Using multiple else if statements for NSInteger - ios

I have a section of code, in which I want a different accessoryView for the TableView cell, based off the number for that cell's entry. The code I have set up is:
NSInteger warriors = [entry.prayerWarriors intValue];
if (warriors == 0) {
//Do nothing
//NSLog(#"0");
}
else if (0 < warriors < 50) {
cell.accessoryView = firstLevel;
// NSLog(#"50");
}
else if (51 < warriors < 100) {
cell.accessoryView = secondLevel;
// NSLog(#"100");
}
else if (101 < warriors < 500) {
cell.accessoryView = thirdLevel;
// NSLog(#"500");
}
else {
cell.accessoryView = fourthLevel;
// NSLog(#"A Lot");
}
However, it always returns only the first entry for warriors == 0. What am I doing wrong?

Rather than doing this...
else if (0 < warriors < 50) {
cell.accessoryView = firstLevel;
// NSLog(#"50");
}
do this...
else if (0 < warriors && warriors < 50) {
cell.accessoryView = firstLevel;
// NSLog(#"50");
}
EDIT
To answer your comment...you probably mean to have some <= or >= in there, as it's going to the last else when warriors equals the border of your if conditionals (50, 100 or 500).
You probably want it to look like this...
NSInteger warriors = [entry.prayerWarriors intValue];
if (warriors == 0) {
//Do nothing
//NSLog(#"0");
}
else if (0 < warriors && warriors <= 50) {
cell.accessoryView = firstLevel;
// NSLog(#"50");
}
else if (50 < warriors && warriors <= 100) {
cell.accessoryView = secondLevel;
// NSLog(#"100");
}
else if (100 < warriors && warriors <= 500) {
cell.accessoryView = thirdLevel;
// NSLog(#"500");
}
else {
cell.accessoryView = fourthLevel;
// NSLog(#"A Lot");
}

The statement
if (0 < warriors < 50)
evaluates different than you might think. The first part
(0 < warriors)
evaluates as a boolean, and that boolean will be compared to 50.
So, you need to do: if (0 < warriors && warriors < 50)

The other answers make good points about the later cases needing a logical and but if you are getting stuck at if (warriors == 0) { most likely your object entry.prayerWarriors is nil. Put a break point and print it out. (and print out it's class to make sure its as expected)
Also minor but a good habit to be in your conversion of what I'm guessing is an NSNumber isn't using the same type as your variable. Since you are writing into a NSInteger you should replace intValue with integerValue

For clarity, I prefer to put the variable first in each condition and to encapsulate each part of the condition:
if (warriors == 0) {
//Do nothing
NSLog(#"0");
}
else if ((warriors > 0) && (warriors < 50))
{
cell.accessoryView = firstLevel;
NSLog(#"50");
}
else if ((warriors > 51) && (warriors < 100)) {
cell.accessoryView = secondLevel;
NSLog(#"100");
}
else if ((warriors > 101) && (warriors < 500)) {
cell.accessoryView = thirdLevel;
NSLog(#"500");
}
else {
cell.accessoryView = fourthLevel;
NSLog(#"A Lot");
}
Just be sure you've have enough parens around the conditions.

You do not need an if cascade for this:
You can store the levels one time anywhere
NSArray *levels = #[firstLevel, secondLevel, thirdLevel, fourthLevel];
And use it indexed:
if( warriors > 0) {
cell.accessoryView = levels[(warriors-1) / 50]
}
But if you want to have an if cascade, you do not have to double check:
NSInteger warriors = [entry.prayerWarriors intValue];
if (warriors == 0) {
//Do nothing
//NSLog(#"0");
}
else if (warriors <= 50) {
cell.accessoryView = firstLevel;
// NSLog(#"50");
}
else if (warriors <= 100) {
cell.accessoryView = secondLevel;
// NSLog(#"100");
}
else if (warriors <= 500) {
cell.accessoryView = thirdLevel;
// NSLog(#"500");
}
else {
cell.accessoryView = fourthLevel;
// NSLog(#"A Lot");
}
If you are in an else, it is already tested that the preceding condition failed.(That's the meaning of else.)

Related

Multiple arrays to fill tableView

I'm using a tableView to display a friend list. Each type is stored in an array.
When the viewController is presented i'm requesting each array from my web-service separately.(OUT,IN and FRIENDS)
The data i'm getting back is a array of objects, each object with three properties: pictureID, profileID and name.
Each array gets displayed in a section, but the order of those sections is important.
I want the outgoing friend request to be in the first section, incoming in the second and friends in the third, provided that there are elements in those arrays, if not, all other will move one place up in the order. I hope you understand...
The way i'm doing it right now is really awkward.
For every array i get from my server i do (friendsArray, incomingArray, outgoingArray):
for (NSDictionary*dict in data){
User *friend = [User new];
friend.profileID = [dict objectForKey:#"profileID"];
friend.pictureID = [dict objectForKey:#"pictureID"];
friend.name = [dict objectForKey:#"name"];
[friendsArray addObject:friend];
}
I think this part is completely normal.
But now numberOfSectionsInTableView:
if (outgoingArray.count > 0 && incomingArray.count == 0 && friendsArray.count == 0) {
return 1;
}
if (outgoingArray.count == 0 && incomingArray.count > 0 && friendsArray.count == 0) {
return 1;
}
if (outgoingArray.count == 0 && incomingArray.count == 0 && friendsArray.count > 0) {
return 1;
}
if (outgoingArray.count > 0 && incomingArray.count > 0 && friendsArray.count == 0) {
return 2;
}
if (outgoingArray.count > 0 && incomingArray.count == 0 && friendsArray.count > 0) {
return 2;
}
if (outgoingArray.count == 0 && incomingArray.count > 0 && friendsArray.count > 0) {
return 2;
}
if (outgoingArray.count > 0 && incomingArray.count > 0 && friendsArray.count > 0) {
return 3;
}
//default
return 0;
PLEASE... there must be a way to do this more easily?
Same goes for numberOfRowsInSection:
switch (section) {
case 0:
if (outgoingArray.count > 0){
return outgoingArray.count;
}else if (incomingArray.count > 0){
return incomingArray.count;
}else if (friendsArray.count > 0){
return friendsArray.count;
}else{
return 0;
}
break;
case 1:
if (outgoingArray.count > 0 && incomingArray.count > 0){
return incomingArray.count;
}
if (outgoingArray.count == 0 && incomingArray.count > 0) {
return friendsArray.count;
}
case 2:
return friendsArray.count;
default:
return 0;
break;
}
And i still got problems when the user selects a cell. I need to know the user id of the profile that is selected because i'm transferring it to the next viewController. Right now i'm doing this the same way im getting the number of rows.
Can you create a dictionary that contains all the objects? You could do three parent keys with array children so all you would have to do is check if the dictionary contains the parent key and then check the children for the number of rows.

IOS have a report builder generate in PDF

I have data to generate report that have header footer and content.
In the content have many group when the data in each group over the page area it add new page and write header of group and continued content data
Where can I have lib. or something to do this Task ??
Thanks For Advance.
Add for request code
NSArray *headObject = [uniqueStates allObjects];////Store head of each group
NSArray *detail; //Store all of data to present in table
int allData = [detail count]; // Tel amount of all data to show
/*
int headGroupline = 1; //Tel amount of head group line
int footGroupline = 1; //Tel amount of foot group line
*/
int detailIndex = 0; ///Tel what line we are now
int detailHeadIndex = 0; ///Tel what group we are now
int subdetail = 0; // Tel what line on group now
int aviableLineInpage = 24; // Line avilable in page for data to show
int allPage = 0; //Sum of all page
for (; detailIndex < allData; ) {
allPage++;
for (int i=0; i < aviableLineInpage;) {
if (allData - detailIndex == 0) {
///ShowgrandTotal
........
detailIndex++;
i+=25;
}else{
if (i == 0) {
//Show Head Group
......
}else{
if (subdetail == [[detail filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"(buy_date == %#)", headObject[detailHeadIndex]]] count]+1) {
detailHeadIndex++;
//Show Head Group
..........
}else{
if (subdetail == [[detail filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"(buy_date == %#)", headObject[detailHeadIndex]]] count]) {
//Show sum of each group
..........
i++;
detailIndex++;
subdetail++;
detailHeadIndex++;
}else{
//Show data of detail
........................
detailIndex++;
subdetail++;
}
}
}
i++;
}
}//for all line in page
}//for allData
It format is:
date 27/01/2014
data1
data2
data3
sum date 27/01/2014
date 28/01/2014
data1
data2
<============if page brake add new page and
date 28/01/2014
data3
sum date 28/01/2014
grand total........
But it goes
date 27/01/2014
data1
data2
data3
sum date 27/01/2014
data1
data2
<============if page brake add new page and
date 28/01/2014
data3
grand total........
Thanks very much
Use CGPDFDocumentRef and the associated functions to create the PDF document and each page it contains. When you create a page (UIGraphicsBeginPDFPageWithInfo) you can get the associated drawing context (UIGraphicsGetCurrentContext). Once you have that you can draw in a number of ways:
You could create a view with your header and footer, add content and render it into the view (using its layer)
You could draw images and text direct into the context (using CoreText (CTFrameDraw))
You need to create the logic to set how much content can fit on any one page and when you need to create a new page.
Also, depending on how you choose to draw content into the context you may need to scale and transform (CGContextScaleCTM + CGContextTranslateCTM) the context so that your content isn't upside down.
See this Apple guide.
int allData = [detail count]; // Tel amount of all data to show
/*
int headGroupline = 1; //Tel amount of head group line
int footGroupline = 1; //Tel amount of foot group line
*/
int detailIndex = 0; ///Tel what line we are now
int detailHeadIndex = 0; ///Tel what group we are now
int subdetail = 0; // Tel what line on group now
int aviableLineInpage = 24; // Line avilable in page for data to show
int allPage = 0; //Sum of all page
for (; detailIndex < allData; ) {
allPage++;
for (int i=0; i < aviableLineInpage;) {
if (allData - detailIndex == 0) {
detailIndex++;
i+=25;
}else{
if (i == 0) {
if (subdetail == -1) {
subdetail = 0;
}
}else{
if (subdetail == -1) {
subdetail = 0;
}else{
if (subdetail == [[detail filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"(buy_date == %#)", headObject[detailHeadIndex]]] count]) {
i++;
subdetail = -1;
detailHeadIndex++;
if (detailHeadIndex == [headObject count] ) {
detailIndex++;
}
}else{
detailIndex++;
subdetail++;
}
}
}
i++;
}
}//for all line in page
}//for allData

if x > 0 but less than y

Sorry for kind of stupid question.
I use an UITextField, where I can enter some numbers.
No i use this code to detect if the entered number is 0, greater than 0, and less than 15.
if (myNr <= 15){
NSLog (#"the number is OK");
}
else if (myNr > 15)
{
NSLog(#"this number doesn't existing");
}
else if (myNr == 0)
{
NSLog(#"number should be between 1 and 15");
}
I got some errors when the number is 0.
i Need to be able to insert numbers only between 1 and 15, if the number is 0 or greater then 15, NSLog should say.
thanks
you should put if(myNr == 0) at first
if (myNr == 0)
{
NSLog(#"number should be between 1 and 15");
} else if (myNr <= 15)
{
NSLog (#"the number is OK");
}
else if (myNr > 15)
{
NSLog(#"this number doesn't existing");
}
What error do you get?
Offhand, remember: Capitalization matters. NSLog is different than nslog.
Your code reduces to:
if (myNr <= 15)
{
NSLog(#"the number is OK");
}
else
{
NSLog(#"this number doesn't existing");
}
The case for 0 is never reached.
Remember the tests are considered sequentially.

Get an array of 3 ordered values whilst favouring a specified value

Sorry for the somewhat generic title, if anyone has a better suggestion please let me know.
Basically I am writing a custom leaderboard view whereby I want to show 3 scores only. If possible it will show the current user's score in the middle but, if the user is at the top or the bottom of the list, it should still show 3 scores but itll show another users above or below the list.
e.g.
Me (If I am top, then show 2 below)
User 1
User 2
or
User 1
Me (usual case where I am in the middle of two scores)
User 2
or
User 1
User 2
Me (If I am bottom show two scores above me)
I have a function written that does the first part of this but doesnt take into account edge cases which is what I am struggling with. Can anyone please advise?
-(void)getNearbyScores:(int)score{
GCLeaderboardScore *closestScoreAbove = nil; //Custom container for GC properties
GCLeaderboardScore *closestScoreBelow = nil; //Contains playerID, score, alias etc
if ([playerScores count] == 0){ //playerScores is an NSMutableDictionary
return;
}
for (NSString* key in playerScores) {
GCLeaderboardScore *playerScore = (GCLeaderboardScore *)[playerScores objectForKey:key];
if ((closestScoreAbove == nil || closestScoreAbove->score > playerScore->score) && playerScore->score > score){
closestScoreAbove = playerScore;
}
else if ((closestScoreBelow == nil || closestScoreAbove->score < playerScore->score) && playerScore->score < score){
closestScoreBelow = playerScore;
}
}
me->score = score;
me->rank = 1;
if (closestScoreAbove != nil) {
me->rank = closestScoreAbove->rank + 1;
nearbyScores = [NSMutableArray arrayWithObjects: closestScoreAbove, me, closestScoreBelow, nil];
}
else {
nearbyScores = [NSMutableArray arrayWithObjects: me, closestScoreBelow, nil];
}
}
Assuming there is a me GCLeaderboardScore object, the method below should return an array with the desired GCLeaderboardScore objects (untested):
-(NSArray *)getNearbyScores {
if(playerScores.count==0) return nil;
// Create an array sorted by score
NSArray *sortedByScore=[playerScores sortedArrayUsingComparator: ^(id object1, id object2) {
GCLeaderboardScore *score1=object1;
GCLeaderboardScore *score2=object2;
if(score1->score < score2->score) return NSOrderedAscending;
if(score1->score > score2->score) return NSOrderedDescending;
return NSOrderedSame;
}];
// Find index of me
NSUInteger idx=[sortedByScore indexOfObject:me];
// If me not found, return nil
if(idx==NSNotFound) return nil;
// Ideally we want to show the player before and behind
idx=MAX(0,(NSInteger)idx-1);
// maxIdx will be idx+2 or index of last object if lower
NSUInteger maxIdx=MIN(sortedByScore.count-1,idx+2);
// In case we are last, show two previous results (if array large enough)
if (maxIdx > 3)
idx=MAX(0,maxIdx-3);
// And return the objects, may be 1..3 objects
return [sortedByScore subarrayWithRange:NSMakeRange(idx,maxIdx-idx+1)];
}
I assume you have an array of scores. (Actual implementation can be adapted to your code)
Initialize:
firstScoreAbove = VERY_LARGE_SCORE; secondScoreAbove = VERY_LARGE_SCORE + 1;
firstScoreBelow = -1; secondScoreBelow = -2;
Scan the array elements.
if ( newScore > myScore ) {
if ( newScore < firstScoreAbove ) {
secondScoreAbove = firstScoreAbove;
firstScoreAbove = newScore;
} else if ( newScore < secondScoreAbove ) {
secondScoreAbove = newScore;
}
} else {
// similarly for below.
}
After scanning,
If firstScoreAbove has not changed, then myScore is top and output the two below scores.
If firstScoreBelow has not changed, then myScore is lowest and output the two above scores.
Else Output firstScoreAbove, myScore, firstScoreBelow.

making sure that every new position is different from previous two positions

Below is a method I wrote that takes a random number and makes sure that a sprite does repeat consecutively at the same position. I want to change it so that every new sprite takes a different position of the other two. I am not really getting it right. Please help.
- (float)randomlyChooseXValue {
CGSize s = [[CCDirector sharedDirector] winSize];
int randX = arc4random() % 3;
if (oldRandX != randX) {
if (randX == 0) {
xPos = xPos1*(s.width/480.0);
} else if (randX == 1) {
xPos = xPos2*(s.width/480.0);
} else {
xPos = xPos3*(s.width/480.0);
}
oldRandX = randX;
} else {
[self randomlyChooseXValue];
}
return xPos;
}
If I understand this correctly you need to find 3 random values and the 3rd one should be different then the 1st 2. If this is true you need to store last 2 random values and compare them in the 1st if statement:
- (float)randomlyChooseXValue {
CGSize s = [[CCDirector sharedDirector] winSize];
int randX = arc4random() % 3;
if ((oldRandX1 != randX) && (oldRandX2 != randX)) { //check for 2 values
if (randX == 0) {
xPos = xPos1*(s.width/480.0);
} else if (randX == 1) {
xPos = xPos2*(s.width/480.0);
} else {
xPos = xPos3*(s.width/480.0);
}
oldRandX2 = oldRandX1; //store 1st value to 2nd place
oldRandX1 = randX; //store new value to 1st place
} else {
[self randomlyChooseXValue];
}
return xPos;
}
Since you explained that you are okay with the sequence repeating, then you only need to really make two random choices: the first position, and the direction.
// somewhere, initialize global oldRandX = -1, dir = -1
- (float)randomlyChooseXValue {
CGSize s = [[CCDirector sharedDirector] winSize];
if (oldRandX < 0) {
oldRandX = arc4random() % 3;
dir = arc4random() % 2;
} else if (dir) {
oldRandX = (oldRandX + 1) % 3;
} else {
oldRandX = (oldRandX + 2) % 3;
}
if (randX == 0) {
xPos = xPos1*(s.width/480.0);
} else if (randX == 1) {
xPos = xPos2*(s.width/480.0);
} else {
xPos = xPos3*(s.width/480.0);
}
return xPos;
}
This can generate every possible sequence of the three positions:
0, 1, 2
0, 2, 1
1, 2, 0
1, 0, 2
2, 0, 1
2, 1, 0
and repeat them.
The other answer will achieve the same results, but like your original method, it might take several tries to get it. Your random function can keep choosing the wrong value an unbounded number of times; it becomes a worse problem when there's only one right number to pick.

Resources