Using a function argument inside a function in Objective-C - objective-c

I am new to Objective-C development and I have already run into the first problem. I am trying to write a function that takes a string as argument and compares that string with other strings. The pseudo code for the function would be the following:
String string2
String string3
function compare_string (String string) {
if (string == "a specific string" &&
string == string2 &&
string == string3) {
// do something
}
}
Until now I only have the following:
NSString *string2 = #"Second string";
NSString *string3 = #"Third string";
(void) compare_string: (NSString *) string {
but now I am already stuck because I don't know how to call the input string string inside the function. Should I simply do something like
if (string == string2) { ... }
or is there another way to use function arguments in Objective-C?

This will be like this:
-(void)compareString:(NSString *string){
if ( [string isEqualToString:#"a specific string"] && [string isEqualToString:string2] && [string isEqualToString:string3] ){
// do something
}
}
NOTE: str1==str2 will compare the memory address, and isEqualToString: compares the contents of the strings.

Check out the docs for NSString there are a bunch of methods that do this for you already - so you don't need to make your own string comparison code
An example would look like
if ([string compare:string2] == NSOrderedSame) { ... }
This is handy if you wish to do complex comparisons like case insensitive etc
for simple equality you could just use
if ([string isEqualToString:string2]) { ... }
Edit
I mis read the question - here is an answer that actually relates to what you asked
You need to use the isEqual: methods defined on object for checking equally. == will only check the pointer values.
You could write your method like this
- (void)compareString:(NSString *)string;
{
if ([#[string, string, string] isEqual:#[ #"a specific string", string1, string2]]) {
// do stuff
}
}
Then later calling it would look like this
[self compareString:#"A string to compare"];
NB
Wrapping it up in arrays reads slightly nicer than comparing them all individually

Related

Convert Swift convenience init with Switch statement to Objective-C

I am trying to convert this swift code to Objective-C
convenience init(fromString string: String, format:DateFormat)
{
if string.isEmpty {
self.init()
return
}
let string = string as NSString
switch format {
case .DotNet:
let startIndex = string.rangeOfString("(").location + 1
let endIndex = string.rangeOfString(")").location
let range = NSRange(location: startIndex, length: endIndex-startIndex)
let milliseconds = (string.substringWithRange(range) as NSString).longLongValue
let interval = NSTimeInterval(milliseconds / 1000)
self.init(timeIntervalSince1970: interval)
So far, I am doing this:
-(id) initFromString: (NSString *) string format: (DateFormat *) format{
if (string == nil) {
self = [self init];
return self;
}
switch (format) {
case .DotNet:
NSRange *startIndex = [[string rangeOfString:#"("] location]+1;
}
}
and have already run into the following errors:
for the switch(format): statement requires expression of integer type (DateFormat * __strong' invalid)
and for the 2 following lines: Expected expression
Any ideas ?
In Objective-C, the string is impliedly optional. Testing for nil merely tests whether a string was supplied. It doesn't check whether an empty string was supplied. You probably want to switch to string.length == 0 as, by the magic of nil-messaging, that'll work to check for either an empty string or no string at all.
Objective-C uses C's switch statement. So you can switch on integral types only. If this were Objective-C code originally, DateFormat would probably be an NS_ENUM — an integral type rather than an object type. It looks like the original was an enumeration from your use of dot syntax? If you can make it an Objective-C enumeration then do so and simply use:
- (id)initFromString:(NSString *)string format:(DateFormat)format {
....
switch(format)
{
case DateFormatDotNet: {
....
} break;
}
(with the curly brackets within the case being because you want to declare variables in there).
Otherwise, if it must be an object format then you're looking at a painful construction like:
if([format isEqual:[DateFormat dotNetFormat]]) {
}
else if([format isEqual:[DateFormat otherFormat]]) {
}
... etc ...
Also Objective-C has a syntactic distinction between structs, which are exactly what they are in C — named fields but no built-in behaviour — and object types, which is again because it's a strict superset of C. NSRange is a struct. So square bracket messaging syntax doesn't work on it. Instead of:
[[string rangeOfString:#"("] location]
Use:
[string rangeOfString:#"("].location
Square brackets around the rangeOfString call because it's a message dispatch to an object, then a dot for location because you get back a C struct as a value, and that's how one accesses a field in a C struct.
(dot syntax also works for properties on Objective-C objects, but explicitly to alias to getter and setter calls, and only for about the most recent of Objective-C's three decades)
Assuming this code is related to How to convert a Swift enum: String into an Objective-C enum: NSString?
Since your DateFormat variable is an object with a dateFormatType that is an NSString, you are going to have to use a chained if-else construct to select from the various possibilities:
if([format.dateFormatType compare: DotNetDateFormatType] == NSOrderedSame) {
[self handleDotNetDateFormat: format]
} else if ([format.dateFormatType compare: RSSDateFormatType] == NSOrderedSame) {
[self handleRSSDateFormat: format]
...
Objective-C has no concept of the dot-value syntax for enum values (so ".DotNet" is not a valid term in Objective-C). That's why the compiler is complaining about those either lines.

Get a Objective-C method to return several NSStrings

I need to use a method that returns several strings, different ones, according to a value.
My code looks like:
- (void) returnStringsAccordingToSet:(NSString *)string1: (NSString *)string2: (NSInteger)setNo {
switch (setNo){
case 1:
if (generalStringSettings){
string1 = #"The first string";
string2 = #"The second string";
} else {
string1 = #"The first other string";
string2 = #"The second other string";
}
break;
case 2:
...
break;
case 3:
...
break;
}
}
I call that method with:
NSString *firstString = [[NSString alloc]init];
NSString *secondString = [[NSString alloc]init];
NSUInteger set = 1;
[self getStringsAccordingToSet: firstString: secondString: set];
I can't get it to work! All I get is empty strings. I've got a feeling that the call for the strings is somewhat wrong. Please help.
You can't mae it work because when you do
string1 = #"The first string";
you just override the local parameter and update its reference but nothing outside the callee is modified. So the value is changed just inside the scope of the function.
You should change the signature of the method to
- (NSArray*) returnStringsAccordingToSet:(NSString *)string1: (NSString *)string2: (NSInteger)setNo {
so that it returns a NSArray instead that nothing and then inside the function
case1:
return [NSArray arrayWithObjects:#"The first string",#"The second string",nil];
so you return the array and store it from the caller, then you can access the returned values.
NSArray *v = [returnStringAccordingTo: ..];
[v objectAtIndex:0]
Technically, since ObjectiveC is a superset of C, I guess it is possible to pass a pointer to a pointer to NSString by reference through (but this is discouraged in ObjC):
NSString *string = nil;
[self callMethod:&string];
-(void)callMethod:(NSString**)refToString {
*refToString = #"foobar";
You could do this by filling a NSArray, but just to show how C works I'll show the error that you made.
string1 and string2 are just pointers, so you can pass either mutable or immutable strings as arguments.But the original pointer never gets modified, for example:
NSString* string1=#"Hello"; // Let's suppose string1 is on the 0x8000 address
// And points to the 0x9000 address
NSString* string2=#"How are you?"; // string2: 0x1000 , pointing to 0x2000
[self returnStringsAccordingToSet: string1: string1 string2: string2];
Then when you call a method a copy is made for every pointer that you pass to the method:
- (void) returnStringsAccordingToSet:(NSString *)string1: (NSString *)string2: (NSInteger)setNo {
// string1 and string2 both point on the same address, but they are other pointers
// for example string1 is on 0x7000 and string2 on 0x7400, pointing to 0x9000
// and 0x2000
switch (setNo){
case 1:
if (generalStringSettings){
string1 = #"The first string"; // You just create another instance
string2 = #"The second string"; // of the string, but the original
// pointers aren't affected
} else {
string1 = #"The first other string";
string2 = #"The second other string";
}
break;
case 2:
...
break;
case 3:
...
break;
}
}
The solutions:
Pass a NSMutableString as argument and instead of assigning them, just modify the contents;
Pass a pointer to pointer;
Return a NSArray containing the new strings.
Update note: I personally don't use the method as a first thing to do. I use arrays if that's possible. Not sure if it's OK to use this with ARC. Some Apple methods use this approach to return error value, so it's good to be aware of it.
When method is called, those arguments you pass to function are copied (of course they are not getting the copy message, pointer is copied as far as you pass pointer), and those copies are used inside the function (or more technically initiated with the argument value). So if you change the copy (i.e. try to replace object on pointer, mutable objects are OK to modify) this will not reflect on the value. You may solve this using pointers (i.e. pass pointer to pointer).
So:
NSString* string = #"one string";
NSLog(string); // one string
// [self method:string]
- (void) method: (NSString*) string {
// Local copy created:
// NSString* string = copy of string (second pointer created, object not copied in memory)
string = #"other string";
NSLog(string); // other string
}
NSLog(string); // one string
You may do this like that:
- (void) method: (NSString**)str {
*str = #"Some string";
}
and then:
// string = "old vlalue"
NSString* string = #"old value";
// string = "Some string"
[self method:&string];

Objective-C String Function: Contains String

How can I check if an NSString contains another substring, at which point it will return a Boolean Value.
This is what I'm thinking of:
If myString.contains("string") then
{
//Stuff Happens
}
But, from the research I've done, it seems as if Obj-C has no function for this. This Wikipedia article gives numerous string functions, their differences, and all in different languages, but I see no Obj-C support for any Contain Function.
Does anyone know of a simple-to-use function like the once above (which is similar to the C# and VB.NET function)?
Would a "Find" Function work? If so, how?
If this is not supported in Obj-C, is there a workaround I can use?
Any help is very appreciated.
if ([myString rangeOfString:#"string"].location != NSNotFound)
{
// Stuff happens
}
NSString *someString = #"Time for an egg hunt";
if ( [someString rangeOfString:#"egg" options:NSCaseInsensitiveSearch].location != NSNotFound ) {
NSLog( #"Found it!" );
}
If you want to be case insensitive.
NSRange range = [string rangeOfString:#"string" options:NSCaseInsensitiveSearch];
if (range.location != NSNotFound)
{
return range.location;
}
else
{
return nil;
}
Documentation
Create a NSString category, and put that in...
Code :
- (BOOL)contains:(NSString *)str
{
NSRange aRange = [self rangeOfString:str];
return (aRange.location!=NSNotFound);
}
Usage :
NSString* testStr = #"This is my string";
if ([testStr contains:#"is"])
{
// do something
}
if([string rangeOfString:substring].length > 0)
...

Compare the text of two text fields

How do you compare the text in two text fields to see if they are the same, such as in "Password" and "Confirm Password" text fields?
if (passwordField == passwordConfirmField) {
//they are equal to each other
} else {
//they are not equal to each other
}
In Objective-C you should use isEqualToString:, like so:
if ([passwordField.text isEqualToString:passwordConfirmField.text]) {
//they are equal to each other
} else {
//they are *not* equal to each other
}
NSString is a pointer type. When you use == you are actually comparing two memory addresses, not two values. The text properties of your fields are 2 different objects, with different addresses.
So == will always1 return false.
In Swift things are a bit different. The Swift String type conforms to the Equatable protocol. Meaning it provides you with equality by implementing the operator ==. Making the following code safe to use:
let string1: String = "text"
let string2: String = "text"
if string1 == string2 {
print("equal")
}
And what if string2 was declared as an NSString?
let string2: NSString = "text"
The use of == remains safe, thanks to some bridging done between String and NSString in Swift.
1: Funnily, if two NSString object have the same value, the compiler may do some optimization under the hood and re-use the same object. So it is possible that == could return true in some cases. Obviously this not something you want to rely upon.
You can do this by using the isEqualToString: method of NSString like so:
NSString *password = passwordField.text;
NSString *confirmPassword = passwordConfirmField.text;
if([password isEqualToString: confirmPassword]) {
// password correctly repeated
} else {
// nope, passwords don't match
}
Hope this helps!

Checking for equality in Objective-C

How do i check the key in dictionary is same as the string in method parameter?
i.e in below code , dictobj is NSMutableDictionary's object , and for each key in dictobj i need to compare with string. How to achieve this ? Should i typecase key to NSString??
-(void)CheckKeyWithString:(NSString *)string
{
//foreach key in NSMutableDictionary
for(id key in dictobj)
{
//Check if key is equal to string
if(key == string)// this is wrong since key is of type id and string is of NSString,Control doesn't come into this line
{
//do some operation
}
}
}
When you use the == operator, you are comparing pointer values. This will only work when the objects you are comparing are exactly the same object, at the same memory address. For example, this code will return These objects are different because although the strings are the same, they are stored at different locations in memory:
NSString* foo = #"Foo";
NSString* bar = [NSString stringWithFormat:#"%#",foo];
if(foo == bar)
NSLog(#"These objects are the same");
else
NSLog(#"These objects are different");
When you compare strings, you usually want to compare the textual content of the strings rather than their pointers, so you should the -isEqualToString: method of NSString. This code will return These strings are the same because it compares the value of the string objects rather than their pointer values:
NSString* foo = #"Foo";
NSString* bar = [NSString stringWithFormat:#"%#",foo];
if([foo isEqualToString:bar])
NSLog(#"These strings are the same");
else
NSLog(#"These string are different");
To compare arbitrary Objective-C objects you should use the more general isEqual: method of NSObject. -isEqualToString: is an optimized version of -isEqual: that you should use when you know both objects are NSString objects.
- (void)CheckKeyWithString:(NSString *)string
{
//foreach key in NSMutableDictionary
for(id key in dictobj)
{
//Check if key is equal to string
if([key isEqual:string])
{
//do some operation
}
}
}