I want to call a method which returns two values
basically lets say my method is like the below (want to return 2 values)
NSString* myfunc
{
NSString *myString = #"MYDATA";
NSString *myString2 = #"MYDATA2";
return myString;
return myString2;
}
So when i call it, i would use??
NSString* Value1 = [self myfunc:mystring];
NSString* Value2 = [self myfunc:mystring2];
I guess im doing something wrong with it, can anyone help me out?
Thanks
You can only return 1 value. That value can be a struct or an object or a simple type. If you return a struct or object it can contain multiple values.
The other way to return multiple values is with out parameters. Pass by reference or pointer in C.
Here is a code snippet showing how you could return a struct containing two NSStrings:
typedef struct {
NSString* str1;
NSString* str2;
} TwoStrings;
TwoStrings myfunc(void) {
TwoStrings result;
result.str1 = #"data";
result.str2 = #"more";
return result;
}
And call it like this:
TwoStrings twoStrs = myfunc();
NSLog(#"str1 = %#, str2 = %#", twoStrs.str1, twoStrs.str2);
You need to be careful with memory management when returning pointers even if they are wrapped inside a struct. In Objective-C the convention is that functions return autoreleased objects (unless the method name starts with create/new/alloc/copy).
You have a few options:
NSArray: Just return an array. Pretty simple.
Pointers: Pass in two pointers, and write to them instead of returning anything. Make sure to check for NULL!
Structure: Create a struct that has two fields, one for each thing you want to return, and return one of that struct.
Object: Same a structure, but create a full NSObject subclass.
NSDictionary: Similar to NSArray, but removes the need to use magic ordering of the values.
As you can only return one value/object, maybe wrap them up in an array:
-(NSArray*) arrayFromMyFunc
{
NSString *myString = #"MYDATA";
NSString *myString2 = #"MYDATA2";
return [NSArray arrayWithObjects:myString,myString2,nil];
}
You can then use it like this:
NSArray *arr = [self arrayFromMyFunc];
NSString *value1 = [arr objectAtIndex:0];
NSString *value2 = [arr objectAtIndex:1];
You could pass results back by reference, but this is easy to get wrong (syntactically, semantically, and from memory management point of view).
Edit One more thing: Make sure that you really need two return values. If they are quite independent, two separate function are often the better choice - better reusabilty and mentainable. Just in case you are making this as a matter of premature optimization. :-)
You can only directly return one value from a function. But there is a way of doing it.
-(void) myfuncWithVal1:(NSString**)val1 andVal2:(NSString**)val2
{
*val1 = #"MYDATA";
*val2 = #"MYDATA2";
}
Then to call it outside the method you'd use:
NSString* a;
NSString* b;
[self myfuncWithVal1:&a andVal2:&b];
void myfunc(NSString **string1, NSString **string2)
{
*string1 = #"MYDATA";
*string2 = #"MYDATA2";
}
...
NSString *value1, *value2;
myfunc(&value1, &value2);
Remember that you need to pass a pointer to a pointer when working with strings and other objects.
Wrap the two strings in an NSArray:
- (NSArray*)myFunc
{
NSString *myString = #"MYDATA";
NSString *myString2 = #"MYDATA2";
return [NSArray arrayWithObjects:myString, myString2, nil];
}
NSArray *theArray = [self myFunc]
NSString *value1 = [theArray objectAtIndex:0];
NSString *value2 = [theArray] objectAtIndex:1];
I see everyone has mentioned an NSArray but I'd go with an NSDictionary so the values don't have to be added in order or even at all. This means it is able to handle a situation where you only want to return the second string.
- (NSDictionary*)myFunction {
NSString *myString1 = #"string1";
NSString *myString2 = #"string2";
return [NSDictionary dictionaryWithObjectsAndKeys: myString1, #"key1", myString2, #"key2", nil];
}
NSDictionary *myDictionary = [self myFunction]
NSString *string1 = [myDictionary objectForKey:#"key1"];
NSString *string2 = [myDictionary objectForKey:#"key2"];
Related
I'm trying to extract the weather information from here using Xpath on the iPhone. As of now it parses all the data but I'm stuck on how to extract the content and display it in a table.
This is what I have so far:
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:[ #"http://aviationweather.gov/adds/metars/?station_ids=1234&std_trans=translated&chk_metars=on&hoursStr=most+recent+only&submitmet=Submit"stringByReplacingOccurrencesOfString:#"1234" withString:self.title]]];
TFHpple * doc = [[TFHpple alloc] initWithHTMLData:data];
NSArray * elements = [doc searchWithXPathQuery:#"//table[1]//tr"];
NSLog(#"%#", elements);
TFHppleElement * element = [elements objectAtIndex:0];
[element content]; // Tag's innerHTML
[element tagName]; // "a"
[element attributes]; // NSDictionary of href, class, id, etc.
[element objectForKey:#"href"]; // Easy access to single attribute
If anybody needs to see what its outputting so far, let me know.
Thanks,
Andrew
I had the same issue I got to the point your at and didn't no where to go but I end up implementing this code. Hope it helps there is still little bits need to make it work correctly but do to the nature of the app I have developed this is all I can give you. its not much more its just the actual implementation into your code that you need really.
#import "XPathQuery.h"
NSMutableArray *weatherArray = [[NSMutableArray arrayWithArray:0]retain]; // Initilize the NSMutableArray can also be done with just an NSArray but you will have to change the populateArray method.
NSString *xPathLookupQuery = #"//table[1]//tr"; // Path in xml
nodes = PerformXMLXPathQuery(data, xPathLookupQuery); // Pass the data in that you need to search through
[self populateArray:weatherArray fromNodes:nodes]; // To populate multiple values into array.
session = [[self fetchContent:nodes] retain]; // To populate a single value and returns value.
- (void)populateArray:(NSMutableArray *)array fromNodes:(NSArray *)nodes
{
for (NSDictionary *node in nodes) {
for (id key in node) {
if ([key isEqualToString:#"nodeContent"]) {
[array addObject:[node objectForKey:key]];
}
}
}
}
You only need either the above code or below code unless you want both.
- (NSString *)fetchContent:(NSArray *)nodes
{
NSString *result = #"";
for (NSDictionary *node in nodes) {
for (id key in node) {
if([key isEqualToString:#"nodeContent"]) {
result = [node objectForKey:key];
}
}
}
return result;
}
I am new to Objective-C. I have written a function that returns two values. Now I would like to print it into two separate labels, how I can do it?
-(NSString *)abc:(NSInteger)weeks year:(NSInteger)year{
............
return ca , da ;
}
and when I call this function like
resultLabel1.text = [self abc year:year]; //output show the value of da
now I want to show the value of ca into resultLabel1.text and da into resultLabel2.text
is it possible?
You can only return a single value from any method in C and C-derived languages. So you simply need to return a single value that represents both values. You can achieve this by making use of a NSDictionary.
So make it:
-(NSDictionary *)abc:(NSInteger)weeks year:(NSInteger)year{
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
ca, #"object1",
da, #"object2", nil];
return dict;
}
Another way is to return an NSArray:
- (NSArray *)abc:(NSInteger)weeks year:(NSInteger)year {
NSArray *myArray = [NSArray arrayWithObjects:da, ca, nil];
return myArray;
}
And you can then use these values as:
NSArray *myArray = [self abc:2 year:2004];
textLabel.text = (NSString *)[myArray objectAtIndex:0];
textLabel2.text = (NSString *)[myArray objectAtIndex:1];
As Jules points out a method can "return" only a single value. However, you have several options for returning multiple values:
Return a pointer to an object, where the object contains multiple values. The object can be an NSArray, NSDictionary or you own class. Jules answer gave some examples of this.
Pass multiple pointers in your parameters, and the method can store results in the object or variable pointed to. See example here.
Return a struct that has multiple fields. There's an example here.
I'd use a NSDictionary to return multiple values from a method. In the dictionary each value is named and referenced by a key. The keys in this example are "ca" and "da" and the values are both a short string of text.
-(NSDictionary *) abc: (NSInteger) weeks year:(NSInteger) year {
NSString* ca = [NSString stringWithFormat:#"Week is %d", weeks];
NSString* da = [NSString stringWithFormat:#"Year is %d", year];
return [[NSDictionary alloc] initWithObjectsAndKeys:ca, #"ca", da, #"da", nil];
}
Call the method and pick out the returned values with code like this:
NSInteger weekParam = #"52".integerValue;
NSInteger yearParam = #"2011".integerValue;
NSDictionary *result = [self abc:weekParam year:yearParam];
NSLog(#"ca has value: %#", [result objectForKey:#"ca"]);
NSLog(#"da has value: %#", [result objectForKey:#"da"]);
You log should have the following lines added:
ca has value: Week is 52
da has value: Year is 2011
You can "return" multiple objects as parameters in a block:
- (void)method {
[self returnMultipleObjectsWithCompletion:^(NSString *firstString, NSString *secondString) {
NSLog(#"%# %#", firstString, secondString);
}];
}
- (void)returnMultipleObjectsWithCompletion:(void (^)(NSString *firstString, NSString *secondString))completion {
if (completion) {
completion(#"firstReturnString", #"secondReturnString");
}
}
You will have to return an NSArray or NSDictionary with the two values.
i have an array of 5 objects.
i want to assign object which is at index 1, to an NSSTRING.
nsstring *abc = [array objectAtindex:1];
i know this is wrong syntax, this is returning object , something like this.
how can i get value which is at index 1 and assign it to an string?
regards
Erm.. this is the correct syntax :)
Apart the name of the string class:
NSString *abc = [array objectAtIndex:1];
mind that this won't create a copy of the string, if you need to copy it use
NSString *abc = [NSString stringWithString:[array objectAtIndex:1]];
As Eiko notes you can directly copy the string object if you need to:
NSString *abc = [[array objectAtIndex:1] copy];
Arrays are zero based in Objective-C land. So...
NSArray *array = [NSArray arrayWithObjects:#"one", #"two", nil];
NSString *abc = [array objectAtIndex:1];
Would return the second object in the array. Zero would return the first.
I'm trying to include the elements of an array in the NSString that's returned by the -description method in my class. No clue how to do this in Objective-C...in Java there's string concatenation or StringBuilder, what's the equivalent in Obj-C?
TIA..
Just use NSArray's componentsJoinedByString: method with whatever you want between them as the argument.
NSString *elementsSquishedTogether = [myArray componentsJoinedByString:#""];
NSString *connectedByACommaAndSpace = [myArray componentsJoinedByString:#", "];
If you have a C array, you can turn it into an NSArray with NSArray *converted = [NSArray arrayWithObjects:yourCArray count:yourArrayCount].
The title of your thread talks about C arrays, so here's a modification of jsumners' answer that will deal wiith C arrays.
myArray is assumed to be an ivar declared thusly:
int* myArray;
storage for myArray is assumed to be malloc'd at some point and the size of it is in an ivar declared:
int myArraySize;
The code for description goes something like
- (NSString *)description
{
NSMutableString *returnString = [[[NSMutableString alloc] init] autorelease];
for (int i = 0 ; i < myArraySize ; i++)
{
if (i > 0)
{
[returnString appendString: #", "];
}
[returnString appendFormat: #"%d", myArray[i]];
}
return [NSString stringWithFormat: #"[%#]", returnString];
}
There are variations. The above version formats the string with bracket delimiters and commas between elements. Also, it returns an NSString instead of an NSMutableString which is not a big deal, but I feel that if you say you are returning an immutable object, you probably should.
The following could should "build" a string representation of your array. Notice that it is using the -description method of the objects in the array. If you want something different you will have to make the necessary change.
- (NSString *)description: (id) myArr {
NSMutableString *returnString = [[[NSMutableString alloc] init] autorelease];
for (int i = 0, j = [myaArr count]; i < j; i++) {
[returnString appendString: [[myArr objectAtIndex: i] description]];
}
return [NSString stringWithString: returnString];
}
Edit:
As JeremyP said, I answered this using Objective-C arrays. I guess I just forgot the question when I started writing my code. I'm going to leave my answer as an alternative way to do it, though. I've also fixed the return string type from a mutable string to an immutable string (as it should be).
I'm getting this warning "Format not a string literal and no format arguments? Any ideas?
-(BOOL)isFirstPointReached{
NSString *firstPoint = [NSString stringWithFormat:[pointsToFillArray objectAtIndex:0]];
NSString *lastPoint = [NSString stringWithFormat:[pointsToFillArray lastObject]];
if([firstPoint isEqualToString:lastPoint]){
return YES;
}
else{
return NO;
}
}
A few points...
The pointsToFillArray is an array of objects and the compiler does not know if it contains NSStrings or any other type of object. To get rid of the error you would cast it to (NSString*)
Secondly, the stringWithFormat is normally used to create a string from a few different pieces of data and does not need to be used in this case
Thirdly, you could just create pointers to the objects within the array and then do your check
The following should work for you:
NSString *firstPoint = (NSString*)[pointsToFillArray objectAtIndex:0];
NSString *lastPoint = (NSString*)[pointsToFillArray lastObject];
if ([firstPoint isEqualToString:lastPoint]) {
return YES;
}