Here's my program so far. My intention is to have it so the if statement compares the letter in the string letterGuessed to a character in the string userInputPhraseString. Here's what I have. While coding in xCode, I get an "expected '['"error. I have no idea why.
NSString *letterGuessed = userInputGuessedLetter.text;
NSString *userInputPhraseString = userInputPhraseString.text;
int loopCounter = 0;
int stringLength = userInputPhraseString.length;
while (loopCounter < stringLength){
if (guessedLetter isEqualToString:[userInputPhraseString characterAtIndex:loopIndexTwo])
{
//if statement true
}
loopCounter++;
}
You are missing enclosing square brackets on this line:
if (guessedLetter isEqualToString:[userInputPhraseString characterAtIndex:loopIndexTwo])
It should be:
if ([guessedLetter isEqualToString:[userInputPhraseString characterAtIndex:loopIndexTwo]])
Edit that won’t fix your problem, though, because characterAtIndex: returns a unichar, not an NSString.
It's not clear what you are trying to do.. But I suppose that letterGuessed has one character... And that userInputPhraseString has many characters. So you want to know if letterGuessed is inside userInputPhraseString correct?
This is one solution without loops involved.. I replaced the input with fixed values for testing and tested the code.. It works.
NSString *letterGuessed = #"A"; //Change to your inputs
NSString *userInputPhraseString = #"BBBA"; //Since it has A it will be true in the test
NSCharacterSet *cset = [NSCharacterSet characterSetWithCharactersInString:letterGuessed];
NSRange range = [userInputPhraseString rangeOfCharacterFromSet:cset];
if (range.location != NSNotFound) { //Does letterGuessed is in UserInputPhraseString?
NSLog(#"YES"); //userInput Does contain A...
} else {
NSLog(#"NO");
}
In regards to your code... I fixed a couple of errors, first you are trying to get a UniChar (Integer) value for the character and want to compare it to a NSString which is an Object. Also fixed a couple of issues with syntax you had and used the right approach which is to return a range of characters. Again for doing what you want to accomplish the example above is the best approach I know, but for the sake of learning, here is your code fixed.
NSString *letterGuessed = #"A"; //Change to your inputs
NSString *userInputPhraseString = #"BBBA"; //Since it has A it will be true in the test
NSInteger loopCounter = 0; //Use NSInteger instead of int.
NSInteger stringLength = userInputPhraseString.length;
BOOL foundChar = NO; //Just for the sake of returning NOT FOUND in NSLOG
while (loopCounter < stringLength){
//Here we will get a letter for each iteration.
NSString *scannedLetter = [userInputPhraseString substringWithRange:NSMakeRange(loopCounter, 1)]; // Removed loopCounterTwo
if ([scannedLetter isEqualToString:letterGuessed])
{
NSLog(#"FOUND CHARACTER");
foundChar = YES;
}
loopCounter++;
}
if (!foundChar) NSLog(#"NOT FOUND");
NSRange holds the position, length.. So we move to a new position on every iteration and then get 1 character.
Also if this approach is what you want, I would strongly suggest a for-loop.
I'm having the most basic of problems with an objective C method.
Based on a suggestion from:
How can I truncate an NSString to a set length?
I am trying to write a method to return a truncated NSString. However, it is not working. When I send in "555" for example, the length (as shown by the variable 'test') comes back as 0. I determined this by setting a break point after the line int test and hovering over the variables fullString and test. Do I somehow need to dereference the pointer to fullString or some other thing? I am a complete newbie in objective C. Many thanks
-(NSString*) getTruncatedString:(NSString *) fullString {
int test = fullString.length;
int test2 = MIN(0,test);
NSRange stringRangeTest = {0, MIN([#"Test" length], 20)};
// define the range you're interested in
NSRange stringRange = {0, MIN([fullString length], 20)};
// adjust the range to include dependent chars
stringRange = [fullString rangeOfComposedCharacterSequencesForRange:stringRange];
// Now you can create the short string
NSString* shortString = [_sentToBrainDisplay.text substringWithRange:stringRange];
return shortString;
}
Based on comments and research, I got it working. Thank you everyone. In case anyone is interested:
-(NSString*) getTruncatedString:(NSString *) fullString {
if (fullString == nil || fullString.length == 0) {
return fullString;
}
NSLog(#"String length: %d", fullString.length);
// define the range you're interested in
NSRange stringRange = {MAX(0, (int)[fullString length]-20),MIN(20, [fullString length])};
// adjust the range to include dependent chars
stringRange = [fullString rangeOfComposedCharacterSequencesForRange:stringRange];
// Now you can create the short string
NSString* shortString = [fullString substringWithRange:stringRange];
return shortString;
}
Check if you are passing #"555" to this method, not "555".
Also, better way is to
NSLog(#"String length: %d", fullString.length).
I am trying to grab a string in my array, change nth letter in the string to a ?, then print the result in a textfield. The problem is my NSMutableArray is being stored into a UIPickerView and I think it would be best just to read the string from the PickerView then change the nth char and print the result. I am struggling with how to grab the string from the picker and change the nth letter.
- (UIView *)viewForRow:(NSInteger)row forComponent:(NSInteger)component
{
if (row == 0 ) {
NSString *originalStringTwo = #"%#", *arrayDictionary;
NSRange two = [originalStringTwo rangeOfString:#"2"];
NSString *newStringTwo = [originalStringTwo stringByReplacingCharactersInRange:two withString:#"?"];
_resultLabel.text = newStringTwo;
}
if (row == 1 ) {
NSString *originalStringThree = #"%#", *arrayDictionary;
NSRange three = [originalStringThree rangeOfString:#"3"];
NSString *newStringThree = [originalStringThreestringByReplacingCharactersInRange:three withString:#"?"];
_resultLabel.text = newStringThree;
}
if ( row == 2 ) {
NSString *originalStringFour = #"%#", *arrayDictionary;
NSRange four = [originalStringFour rangeOfString:#"4"];
NSString *newStringFour = [originalStringFour stringByReplacingCharactersInRange:four withString:#"?"];
_resultLabel.text = newStringFour;
}
return 0;
}
That's not how you create an NSRange. Use NSMakeRange instead.
// Range from index 1 with length 1, eg. 2nd character:
NSRange two = NSMakeRange(2, 1);
NSString *newStringTwo = [originalStringTwo stringByReplacingCharactersInRange:two
withString:#"?"];
Note, that it's never a good idea to grab any data from a GUI element (except user input). What if the text field applies custom formatting?
You should keep your data in your array and use that.
hi here is my function, but everytime when i try to init and alloc foo it falls, can you tell me why?
-(NSString*)modifyTheCode:(NSString*) theCode{
if ([[theCode substringToIndex:1]isEqualToString:#"0"]) {
if ([theCode length] == 1 ) {
return #"0000000000";
}
NSString* foo = [[NSString alloc]initWithString:[theCode substringWithRange:NSMakeRange(2, [theCode length]-1)]];
return [self modifyTheCode:foo];
} else {
return theCode;
}
}
the error message:
warning: Unable to read symbols for /Developer/Platforms/iPhoneOS.platform/DeviceSupport/4.3.2 (8H7)/Symbols/Developer/usr/lib/libXcodeDebuggerSupport.dylib (file not found).
replace this line
NSString* foo = [[NSString alloc]initWithString:[theCode substringWithRange:NSMakeRange(2, [theCode length]-1)]];
with this line
NSString* foo = [[NSString alloc]initWithString:[theCode substringWithRange:NSMakeRange(1, [theCode length]-1)]];
and try..
What is the error message?
If you are working with NSRange maybe you should check the length of theCode first.
Because the range is invalid. NSRange has two members, location and length. The range you give starts at the third character of the string and has the length of the string minus one. So your length is one character longer than the amount of characters left in the string.
Suppose theCode is #"0123". The range you create is { .location = 2, .length = 3 } This represents:
0123
^ start of range is here
^ start of range + 3 off the end of the string.
By the way, you'll be pleased to know that there are convenience methods so you don't have to mess with ranges. You could do:
if ([theCode hasPrefix: #"0"])
{
NSString* foo = [theCode substringFromIndex: 1]; // assumes you just want to strip off the leading #"0"
return [self modifyTheCode:foo];
} else {
return theCode;
}
By the way, your original code leaked foo because you never released it.
I want to get the type of NSNumber instance.
I found out on http://www.cocoadev.com/index.pl?NSNumber this:
NSNumber *myNum = [[NSNumber alloc] initWithBool:TRUE];
if ([[myNum className] isEqualToString:#"NSCFNumber"]) {
// process NSNumber as integer
} else if ([[myNum className] isEqualToString:#"NSCFBoolean"]) {
// process NSNumber as boolean
}
Ok, but this doesn't work, the [myNum className] isn't recognized by the compiler.
I'm compiling for iPhone.
I recommend using the -[NSNumber objCType] method.
It allows you to do:
NSNumber * n = [NSNumber numberWithBool:YES];
if (strcmp([n objCType], #encode(BOOL)) == 0) {
NSLog(#"this is a bool");
} else if (strcmp([n objCType], #encode(int)) == 0) {
NSLog(#"this is an int");
}
For more information on type encodings, check out the Objective-C Runtime Reference.
You can get the type this way, no string comparisons needed:
CFNumberType numberType = CFNumberGetType((CFNumberRef)someNSNumber);
numberType will then be one of:
enum CFNumberType {
kCFNumberSInt8Type = 1,
kCFNumberSInt16Type = 2,
kCFNumberSInt32Type = 3,
kCFNumberSInt64Type = 4,
kCFNumberFloat32Type = 5,
kCFNumberFloat64Type = 6,
kCFNumberCharType = 7,
kCFNumberShortType = 8,
kCFNumberIntType = 9,
kCFNumberLongType = 10,
kCFNumberLongLongType = 11,
kCFNumberFloatType = 12,
kCFNumberDoubleType = 13,
kCFNumberCFIndexType = 14,
kCFNumberNSIntegerType = 15,
kCFNumberCGFloatType = 16,
kCFNumberMaxType = 16
};
typedef enum CFNumberType CFNumberType;
If all you want is to differentiate between booleans and anything else, you can make use of the fact that boolean NSNumbers always return a shared instance:
NSNumber *num = ...;
if (num == (void*)kCFBooleanFalse || num == (void*)kCFBooleanTrue) {
// num is boolean
} else {
// num is not boolean
}
NSNumber explicitly doesn't guarantee that the returned type will match the method used to create it, so doing this at all is probably a bad idea.
However, you could probably do something like this (you could also compare to objc_getClass("NSCFNumber") etc., but this is arguably more portable):
Class boolClass = [[NSNumber numberWithBool:YES] class];
/* ... */
if([myNum isKindOfClass:boolClass]) {
/* ... */
}
In Swift:
let numberType = CFNumberGetType(answer)
switch numberType {
case .charType:
//Bool
case .sInt8Type, .sInt16Type, .sInt32Type, .sInt64Type, .shortType, .intType, .longType, .longLongType, .cfIndexType, .nsIntegerType:
//Int
case .float32Type, .float64Type, .floatType, .doubleType, .cgFloatType:
//Double
}
Use the method -[NSNumber objCType] method to get the type.
If the type's equal to #encode(BOOL), or the number itself is kCFBooleanFalse, or kCFBooleanTrue, it's a boolean.
If it's anything else but 'c', it's a number.
If it's 'c', what appears to be the only way supported way, without checking against private class names, or comparing against undocumented singletons, is to turn make an array of one element, the number, and then use NSJSONSerialization to get the string representation. Finally, check if the string representation contains the string "true" or "false". Here is the full code for checking if an NSNumber is a BOOL:
-(BOOL)isBool
{
if(!strcmp(self.objCType, #encode(BOOL)) ||
self == (void*)kCFBooleanFalse ||
self == (void*)kCFBooleanTrue)
{
return YES;
}
if(strcmp(self.objCType, "c"))
{
return NO;
}
NSString * asString = [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:#[self] options:kNilOptions error:nil] encoding:NSUTF8StringEncoding];
return [asString containsString:#"true"] || [asString containsString:#"false"];
}
Note that using NSJSONSerialization is slow and if #NO/#YES ever stops always equalling kCFBooleanFalse/kCFBooleanTrue, then this method probably shouldn't be used in a tight loop.
The reason the compiler warns you and it doesn't work is because -[NSObject className] is declared in a category on NSObject on Mac OS X (in NSScriptClassDescription.h) and not declared on iPhone. (It doesn't support AppleScript, obviously.) NSStringFromClass([myNum class]) is what you should use to be safe across all platforms. Odds are that -className is declared as a simple wrapper around NSStringFromClass() anyway...
NSString *classString = NSStringFromClass([myNum class]);
That should ger the string you want.
To check that NSNumber contains a bool value Try this:
if (strcmp([myNumber objCType], [#(YES) objCType]) == 0)
NSLog(#"%#", [myNumber boolValue] ? #"true" : #"false");
objCType documentation states that The returned type does not necessarily match the method the number object was created with
Secondly, other methods of comparing the class of number to a given class type or assuming boolean number instances to be shared singletons are not documented behaviour.
A more(not completely though) reliable way is to depend on NSJSONSerialisation as it correctly recognises number instances created with bool and outputs true/false in json. This is something we can expect Apple to take care of while moving with new SDKs and on different architectures. Below is the code:
+(BOOL) isBoolType:(NSNumber*) number {
NSError* err;
NSData* jsonData = [NSJSONSerialization dataWithJSONObject:#{#"key":number}
options:0
error:&err];
NSString* jsonString = [[NSString alloc]
initWithData:jsonData
encoding:NSUTF8StringEncoding];
return [jsonString containsString:#"true"]
|| [jsonString containsString:#"false"];
}
Swift Version
NSNumber is a class-cluster so each underlying type can be figured from the instance. This code avoids hard-coding the different NSNumber types by creating an instance of the expected type, and then comparing it against the unknown type.
extension NSNumber {
var isBool: Bool {
return type(of: self) == type(of: NSNumber(booleanLiteral: true))
}
}
check object is of NSNumber type :
if([obj isKindOfClass:NSClassFromString(#"__NSCFNumber")])
{
//NSNumber
}