I need to check in two of string, if those string contains any particular string or not
NSString *startLocationAddress = #"Any address for start location";
NSString *endLocationAddress = #"Any address for end location";
if ([startLocationAddress rangeOfString:#"Australia"].location == NSNotFound)
{
NSLog(#"string does not contain Australia");
startLocationAddress = [startLocationAddress stringByAppendingString:#",Australia"];
}
else if ([endLocationAddress rangeOfString:#"Australia"].location == NSNotFound)
{
NSLog(#"string does not contain Australia");
endLocationAddress =[endLocationAddress stringByAppendingString:#",Australia"];
}
else {
NSLog(#"string contain Australia");
}
As my both of strings does not contains "Australia". So the first condition will be checked first and if the first condition valid then it exit out of the conditions, if the first condition is not valid then only it check the else if condition. In this way the if else if conditional works.
As my both of strings does not contains "Australia". First if condition is working fine and it append "Australia" to the string but second else if condition is not working
How on earth can an else if block execute when it's corresponding if was executed? Expectation is not logical.
If you want your else if block to also check then separate it from your main if and start a new if condition, not an else if
You better reconstruct it like:
if ([startLocationAddress rangeOfString:#"Australia"].location == NSNotFound)
{
//codes..
}
else
{
NSLog(#"startLocationAddress contain Australia");
}
if ([endLocationAddress rangeOfString:#"Australia"].location == NSNotFound)
{
//codes..
}
else
{
NSLog(#"endLocationAddress contain Australia");
}
and review how if-else if-else statement works.. See: #
Hanky 웃 Panky answer for that, since confusion is very prone to us..
if (ifcondition)
{ .. }
else if (elseifcondition)
{ .. }
else
{ .. }
/*
if `ifcondition` == true, dont expect anything from `else-if` or `else`,
compiler won't care about them anymore. that goes with `else-if` and `else` as well..
*/
In if-else if-else condition if any of one is gets satisfied it will ignore the rest of the condition.
This means if First if gets satisfied, then it will ignore the "else if - else". Hence your second condition is not executing.
You are required to read the basic if else logic of execution.
Here is the example
int x=70;
string Grade;
IF (x > 90) THEN
Grade = "O"
ELSE IF (x > 80) THEN
Grade = "A"
ELSE IF (x > 70) THEN
Grade = "B"
ELSE IF (x > 60) THEN
Grade = "C"
ELSE
Grade = "F"
Here the value for variable Grade will be only one per execution.
Related
I'm attempting to check two input textfields that the user type in to see if they put in either AM or PM (going for non-case sensitive). If they did, post the event otherwise display an alert.
I tried this, it works in some occasions, but when I type in PM and AM in the second it sometimes tells me it's not valid and returning my alert. Any idea where I got the logic wrong?
if(!([self.eventStartTimeSuffix.text isEqualToString:#"AM"] || [self.eventStartTimeSuffix.text isEqualToString:#"PM"]) && !([self.eventEndTimeSuffix.text isEqualToString:#"AM"] || [self.eventEndTimeSuffix.text isEqualToString:#"PM"]))
{
NSLog(#"Invalid Event / Start Time Suffix, AM or PM required");
}
else
{
//post event
}
In trying to test for not AM/PM you are testing for both being invalid, your test is: NOT(StartTimeSuffix is AM/PM) AND NOT(EndTimeSuffix is AM/PM). So first either use OR to join the separate conditions or test them independently so you can present a more specific error.
You are also not ignoring case as you say you wish to, and if the user enters some whitespace it might be worth ignoring that as well. You can do both of these with code such as:
NSSString *startSuffix = [[self.eventStartTimeSuffix.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] lowercaseString];
and then comparing startSuffix to #"am" and #"pm", likewise for eventEndTimeSuffix.
BTW You might be even better off if you use the international facilities of OS X and compare for the localised versions of AM & PM - but that is another topic!
Add parentheses to make your grouping clear:
Pseudocode (this is not real code!):
if (
(startText == "AM" || startText == "PM")
&&
(endText == "AM" || endText "PM")
)
{
//Both fields contain either "AM" or PM"
}
Note that if you want case insensitive comparison, you should use
if ([string caseInsensitiveCompare: #"otherString"] == NSOrderedSame)
{
//strings match, ignoring case
}
else
{
//strings don't match
}
You also may as well factor out a method to make it more readable:
- (BOOL)hasValidTimeSuffix:(NSString *)timeText {
return [[timeText lowercaseString] hasSuffix:#"am"] || [[timeText lowercaseString] hasSuffix:#"pm"]
}
and then
if ([self hasValidTimeSuffix:self.eventStartTimeSuffix.text] && [self hasValidTimeSuffix:self.eventEndTimeSuffix.text])
{
//post event
}
else
{
NSLog(#"Invalid Event / Start Time Suffix, AM or PM required");
}
Notice the use of NSString's lowercaseString and hasSuffix: methods. These help a lot.
Why would you bother checking for the input of textfields? Won't it be wiser to use a NSPopUpButton? Check the selected tag 0:AM or 1:PM. It's just an idea, but it screams for a NSPopUpButton. Cheers!
if
([sender selectedTag] == AM)
{
NSLog(#"it's AM");
}
else if([sender selectedTag] == PM)
{
NSLog(#"it's PM");
}
//Sender is one of the two NSPopUpButtons
//I made a Typedef Enum to make it more readable
/*In the .h file:
typedef enum {
AM,
PM
} TimeNotation;
*/
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.
Say I have the following block of code:
[allKeys sortUsingComparator:^NSComparisonResult(id obj1, id obj2) {
NSDictionary *firstArticle = [articles objectForKey:(NSString *)obj1];
NSNumber *firstSortID = [firstArticle objectForKey:#"sort_id"];
NSDictionary *secondArticle = [articles objectForKey:(NSString *)obj2];
NSNumber *secondSortID = [secondArticle objectForKey:#"sort_id"];
if (firstSortID == nil || secondSortID == nil) {
return nil;
}
else {
return [secondSortID compare:firstSortID];
}
}];
I get the warning:
Incompatible pointer to integer conversion returning 'void *' from a
function with result type 'NSComparisonResult' (aka 'enum
NSComparisonResult')
But basically, if one of them is nil, it crashes because the comparison doesn't make sense. How do I tell it that if it's nil, don't bother, just stop.
You have to decide how you want nil values to be sorted. Most likely they should go at the end of the list. You want something like this:
if (firstSortID) {
if (secondSortID) {
// Both set, compare
NSComparisonResult result = [firstSortID compare:secondSortID];
if (result == NSOrderedSame) {
// optionally do another comparison on a secondary value
// result = ...
}
return result;
} else {
// Have 1st but not 2nd
return NSOrderedAscending;
}
} else {
if (secondSortID) {
// Have 2nd but not 1st
return NSOrderedDescending;
} else {
// Both nil, treat as the same
// Another option here is to look at another value in the dictionary to be used as a secondary sort
return NSOrderedSame;
}
}
You cannot prematurely terminate the sort using sortUsingComparator:. So you must sort the nil values - just decide whether nil should be the least or greatest value and return NSOrderedDescending, NSOrderedAscending or NSOrderedSame as appropriate.
If you need to know whether you hit a nil then set a flag in your block which you can test afterwards. The flag needs to be declared with the __block qualifier so it can be modified within your block, e.g.:
__block BOOL nilFound = NO;
[allKeys sortUsingComparator:^NSComparisonResult(id obj1, id obj2)
{
NSDictionary *firstArticle = [articles objectForKey:(NSString *)obj1];
NSNumber *firstSortID = [firstArticle objectForKey:#"sort_id"];
NSDictionary *secondArticle = [articles objectForKey:(NSString *)obj2];
NSNumber *secondSortID = [secondArticle objectForKey:#"sort_id"];
// set flag - could alternatively be set during comparison logic below
if (firstSortID == nil || secondSortID == nil)
nilFound = YES;
// actual comparison, allowing for nil values
...
}];
// was a nil found?
if (nilFound) ...
Addendum
Others have raised the issue of a stable sort, you should be able to address this by using the original keys, e.g.:
if (firstSortID == nil)
{
if (secondSortID == nil)
{
// both nil - use original keys as secondary sort, obj1 & obj2 are strings
return [obj1 compare:obj2];
}
else
return NSSortAscending;
}
else
return secondSortID == nil ? NSSortDescending : [secondSortID compare:firstSortID];
(You can switch the NSSortAscending & NSSortDescending to have the nil values grouped at the other end.)
dumb question: lets say I'm assigning a var in a conditional statement. I don't know if the condition will be satisfied and i still want the var to be defined.. whats the correct way of writing this
example:
NSDecimalNumber *number = [[NSDecimalNumber alloc]init]; // this is pointless right?
if(x == z){
number = [whatevernum1 decimalNumberByMultiplyingBy: whatevernum2];
} else {
number = [whatevernum2 decimalNumberByDividingBy: whatevernum3];
}
// do something with number variable.
There is no need to initialize number since it will be set. Just do this:
NSDecimalNumber *number;
if(x == z){
number = [whatevernum1 decimalNumberByMultiplying: whatevernum2];
} else {
number = [whatevernum2 decimalNumberByDividing: whatevernum3];
}
// do something with number variable.
In your case number will be assigned a value one way or another. But you might have a situation like this:
if (someCondition) {
// set number to value A
} else if (anotherCondition) {
// set number to value B
}
Here, it is possible that neither condition is met. In this case you need to deal with this properly by initializing number to nil.
NSDecimalNumber *number = nil;
if (someCondition) {
// set number to value A
} else if (anotherCondition) {
// set number to value B
}
if (number) {
// process result
}
You need to declare the variable but not assign it, like this:
NSDecimalNumber *number;
if(x == z){
number = [whatevernum1 decimalNumberByMultiplying: whatevernum2];
} else {
number = [whatevernum2 decimalNumberByDividing: whatevernum3];
}
This tells the compiler that you want to use a variable named number, but don't have a value for it yet. In some cases, you may find it convenient to initialise the variable to nil rather than leaving it as a null pointer.
Normally, as others have pointed out, you would either not initialise (if you can guarantee that you will set a value, eg through an if/else pair), or you would initialise to nil.
In this simple case, a ternary statement would make your code much clearer:
NSDecimalNumber *number = x == z ? [whatevernum1 decimalNumberByMultiplyingBy:whatevernum2] : [whatevernum2 decimalNumberByDividingBy:whatevernum3];
I was using this in my iPhone app
if (title == nil) {
// do something
}
but it throws some exception, and the console shows that the title is "(null)".
So I'm using this now:
if (title == nil || [title isKindOfClass:[NSNull class]]) {
//do something
}
What is the difference, and what is the best way to determine whether a string is null?
As others have pointed out, there are many kinds of "null" under Cocoa/Objective C. But one further thing to note is that [title isKindOfClass:[NSNull class]] is pointlessly complex since [NSNull null] is documented to be a singleton so you can just check for pointer equality. See Topics for Cocoa: Using Null.
So a good test might be:
if (title == (id)[NSNull null] || title.length == 0 ) title = #"Something";
Note how you can use the fact that even if title is nil, title.length will return 0/nil/false, ie 0 in this case, so you do not have to special case it. This is something that people who are new to Objective C have trouble getting used to, especially coming form other languages where messages/method calls to nil crash.
it is just as simple as
if([object length] >0)
{
// do something
}
remember that in objective C if object is null it returns 0 as the value.
This will get you both a null string and a 0 length string.
Refer to the following related articles on this site:
Is if (variable) the same as if (variable != nil) in Objective-C
h
I think your error is related to something else as you shouldn't need to do the extra checking.
Also see this related question: Proper checking of nil sqlite text column
I have found that in order to really do it right you end up having to do something similar to
if ( ( ![myString isEqual:[NSNull null]] ) && ( [myString length] != 0 ) ) {
}
Otherwise you get weird situations where control will still bypass your check. I haven't come across one that makes it past the isEqual and length checks.
Whats with all these "works for me answers" ? We're all coding in the same language and the rules are
Ensure the reference isn't nil
Check and make sure the length of the string isn't 0
That is what will work for all. If a given solution only "works for you", its only because your application flow won't allow for a scenario where the reference may be null or the string length to be 0. The proper way to do this is the method that will handle what you want in all cases.
If you want to test against all nil/empty objects (like empty strings or empty arrays/sets) you can use the following:
static inline BOOL IsEmpty(id object) {
return object == nil
|| ([object respondsToSelector:#selector(length)]
&& [(NSData *) object length] == 0)
|| ([object respondsToSelector:#selector(count)]
&& [(NSArray *) object count] == 0);
}
There are two situations:
It is possible that an object is [NSNull null], or it is impossible.
Your application usually shouldn't use [NSNull null]; you only use it if you want to put a "null" object into an array, or use it as a dictionary value. And then you should know which arrays or dictionaries might contain null values, and which might not.
If you think that an array never contains [NSNull null] values, then don't check for it. If there is an [NSNull null], you might get an exception but that is fine: Objective-C exceptions indicate programming errors. And you have a programming error that needs fixing by changing some code.
If an object could be [NSNull null], then you check for this quite simply by testing
(object == [NSNull null]). Calling isEqual or checking the class of the object is nonsense. There is only one [NSNull null] object, and the plain old C operator checks for it just fine in the most straightforward and most efficient way.
If you check an NSString object that cannot be [NSNull null] (because you know it cannot be [NSNull null] or because you just checked that it is different from [NSNull null], then you need to ask yourself how you want to treat an empty string, that is one with length 0. If you treat it is a null string like nil, then test (object.length == 0). object.length will return 0 if object == nil, so this test covers nil objects and strings with length 0. If you treat a string of length 0 different from a nil string, just check if object == nil.
Finally, if you want to add a string to an array or a dictionary, and the string could be nil, you have the choice of not adding it, replacing it with #"", or replacing it with [NSNull null]. Replacing it with #"" means you lose the ability to distinguish between "no string" and "string of length 0". Replacing it with [NSNull null] means you have to write code when you access the array or dictionary that checks for [NSNull null] objects.
You just check for nil
if(data[#"Bonds"]==nil){
NSLog(#"it is nil");
}
or
if ([data[#"Bonds"] isKindOfClass:[NSNull class]]) {
NSLog(#"it is null");
}
MACRO Solution (2020)
Here is the macro that I use for safe string instead of getting "(null)" string on a UILabel for example:
#define SafeString(STRING) ([STRING length] == 0 ? #"" : STRING)
let say you have an member class and name property, and name is nil:
NSLog(#"%#", member.name); // prints (null) on UILabel
with macro:
NSLog(#"%#", SafeString(member.name)); // prints empty string on UILabel
nice and clean 😊
Extension Solution (2020)
If you prefer checking nil Null and empty string in your project you can use my extension line below:
NSString+Extension.h
///
/// Checks if giving String is an empty string or a nil object or a Null.
/// #param string string value to check.
///
+ (BOOL)isNullOrEmpty:(NSString*)string;
NSString+Extension.m
+ (BOOL)isNullOrEmpty:(NSString*)string {
if (string) { // is not Nil
NSRange range = [string rangeOfString:string];
BOOL isEmpty = (range.length <= 0 || [string isEqualToString:#" "]);
BOOL isNull = string == (id)[NSNull null];
return (isNull || isEmpty);
}
return YES;
}
Example Usage
if (![NSString isNullOrEmpty:someTitle]) {
// You can safely use on a Label or even add in an Array for example. Remember: Arrays don't like the nil values!
}
if(textfield.text.length == 0){
//do your desired work
}
Try this for check null
if (text == nil)
#interface NSString (StringFunctions)
- (BOOL) hasCharacters;
#end
#implementation NSString (StringFunctions)
- (BOOL) hasCharacters {
if(self == (id)[NSNull null]) {
return NO;
}else {
if([self length] == 0) {
return NO;
}
}
return YES;
}
#end
NSString *strOne = nil;
if([strOne hasCharacters]) {
NSLog(#"%#",strOne);
}else {
NSLog(#"String is Empty");
}
This would work with the following cases, NSString *strOne = #"" OR NSString *strOne = #"StackOverflow" OR NSString *strOne = [NSNull null] OR NSString *strOne.
If that kind of thing does not already exist, you can make an NSString category:
#interface NSString (TrucBiduleChoseAdditions)
- (BOOL)isEmpty;
#end
#implementation NSString (TrucBiduleChoseAdditions)
- (BOOL)isEmpty {
return self == nil || [#"" isEqualToString:self];
}
#end
What works for me is if ( !myobject )
Complete checking of a string for null conditions can be a s follows :<\br>
if(mystring)
{
if([mystring isEqualToString:#""])
{
mystring=#"some string";
}
}
else
{
//statements
}
I only check null string with
if ([myString isEqual:[NSNull null]])
if ([linkedStr isEqual:(id)[NSNull null]])
{
_linkedinLbl.text=#"No";
}else{
_linkedinLbl.text=#"Yes";
}
if ([strpass isEqual:[NSNull null]] || strpass==nil || [strpass isEqualToString:#"<null>"] || [strpass isEqualToString:#"(null)"] || strpass.length==0 || [strpass isEqualToString:#""])
{
//string is blank
}
For string:
+ (BOOL) checkStringIsNotEmpty:(NSString*)string {
if (string == nil || string.length == 0) return NO;
return YES;
}
Refer the picture below:
For string:
+ (BOOL) checkStringIsNotEmpty:(NSString*)string {
if (string == nil || string.length == 0) return NO;
return YES;}