iOS Method Return Multiple Values NSDictionary - ios

I have a method that I call that calculates the Sunrise, Noon and Sunset for any given day. I pass the method the day date as a Julian.
The method need to return the three numbers or strings: Sunrise, Noon and Sunset.
I am trying to call it as follows:
ClassSolarCalculations *LINK = [[ClassSolarCalculations alloc] init];
NSString dateSunrise= [[NSString alloc] initWithFormat:#"%f", [LINK CalculateSunrise: Julian]];
where the Method reads:
(NSDictionary *) CalculateSunrise: (double) Julian;
NSDictionary *returnTimes = [NSDictionary initWithObjectsAndKeys: SunriseText, #"Sunrise", NoonText, "#Noon", SunsetText, #"Sunset", nil];
return returnTimes;
I can this approach to work to return a single value but would like to return all three in one go rather than fudge the solution by calling variants of the routine three times…

Lots of things should be changed here:
method and variable names should start with lowercase letters and use camel case.
Rename your CalculateSunrise: method since it will return more values. Maybe calculateSunTimes:.
Since your method returns an NSDictionary you handling of the return needs to be different.
Try this:
ClassSolarCalculations *link = [[ClassSolarCalculations alloc] init];
NSDictionary *times = [link calculateSunTimes:julian];
NSString *sunrise = times[#"sunrise"];
NSString *noon = times[#"noon"];
NSString *sunset = times[#"sunset"];
Your method would be something like:
- (NSDictionary *)calculateSunTimes:(double)julian {
// calculate the three values:
return #{ #"sunrise" : sunriseText, #"sunset" : sunsetText, #"noon" : noonText };
}
Notice the use of modern Objective-C syntax.

Related

Why two strings allocated with NSString *str1 = [[NSString alloc]init]; have same address?

NSString *str1 = [[NSString alloc]init];
NSString *str2 = [[NSString alloc]init];
NSLog(#"%p\n%p",str1,str2);
result
str1:0x7fff7b559d00
str2:0x7fff7b559d00
Why str1 and str2 have same memory address?
NSString is immutable, so two empty strings are identical. Therefore, Cocoa can return the same object every time you create it.
The real question, however, how can this be done when alloc returns two different addresses for the two strings?
The answer is that init is allowed to substitute the value of self for anything it wishes, and return a completely different object. For example, NSString's init can be implemented like this:
-(id)init {
static NSString *empty = nil;
if (!empty) {
empty = [[NSString alloc] initWithCharacters:"" length:0];
}
return empty;
}
Note: The real code in Cocoa will almost certainly be different; this is only an illustration to show how the same address could be returned for different allocations.

Getting write request value from NSArray with Core Bluetooth

I have a method here:
- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveWriteRequests:(NSArray *)requests
{
NSLog(#"PERIPHERAL: peripheralManager:%# didReceiveWriteRequests:%#", peripheral, requests);
NSString * result = [[requests valueForKey:#"description"] componentsJoinedByString:#""];
_label.text = result;
}
I receive the write request in an NSArray. Right now I am just converting the full array into a string and outputting the string into a text box. To make sure everything is set up correctly. It indeed is working, but I do not want the full array listed but just the value alone stored in a NSString.
I want this in a string:
Test
Not this:
CBATTRequest: 0x1702240 Central = , Characteristic = , Offset = 0, Value = test
This should be easy to accomplish and I am possibly just brain dead from a long day. How is this supposed to be done?
You need to consider that requests is an array of CBATTRequests, which have a value property containing an NSData object representing the data being written.
If you want one string representing all of the values, you need to iterate over requests and convert each of these NSData values to NSString and concatenate them. If I'm understanding your question correctly, this should be what you're looking for.
- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveWriteRequests:(NSArray *)requests {
NSMutableString *output = [[NSMutableString alloc] init];
for (CBATTRequest *request in requests) {
NSString *stringValue = [[NSString alloc] initWithData:[request value] encoding:NSUTF8StringEncoding];
if (stringValue) {
[output appendString:stringValue];
}
}
_label.text = output.copy;
}
As a note, updating to Xcode 7 would help make this more clear, since the requests parameter of -peripheralManager:didReceiveWriteRequests: has updated to use Objective-C generics, and now has the type NSArray<CBATTRequest *> *.

Passing a _CFNSString into an NSString

I have a loop that identifies elements of a webpage via its HTML and extracts the sections I need. I'm wanting to build an array or (very) long string of the extracted text which can be used later.
The extraction uses TFHpple from GitHub. The problem seems to lie with the extracted text being a _CFNSString, and these don't allow me to transpose them into a NSString or NSMutuableArray.
The code I'm using is:
NSArray *webNodes = [webParser searchWithXPathQuery:tutorialsXpathQueryString];
NSString *extractedText = [[NSString alloc] init];
NSMutableArray *extractedArray = [[NSMutableArray alloc] initWithCapacity:0];
for (TFHppleElement *element in webNodes) {
Extraction *extraction = [[Extraction alloc] init];
[extractedArray addObject:extraction];
extraction.title = [[element firstChild] content];
extractedText = extraction.title;
NSLog(#"\n\nTitle: %#", extractedText);
}
The NSLog at this point shows me extractedText holds I'm after for each loop, breaking the code shows extractedText to be a _CFNSString.
If I try adding
text = [text StringByAppendingString extractedText];
(with 'text' being an NSString initialised before the loop) as the last step of the loop I get a null value. Its the same if I try adding text or extraction.title directly into an array.
I found this question Convert NSCFString to NSString but the conversion seems to be going the other way (NSString to CFNSString). When I added equivalent code I got bridging errors and the code doesn't run.
How can I collect the data within extraction.title to build a string or array that can be used later?
You said you only want a text.
Get it in one line of code for array:
NSArray *extractedArray = [webNodes valueForKeyPath:#"firstChild.content"];
For string:
NSString *extractedText = [webNodes valueForKeyPath:#"firstChild.content"] componentsJoinedByString:#" "];

Objective C Array Count String Issue

Okay I am new to objective C and am trying hard to learn it on my own with out bother the stacked overflow community to much but it is really quite different then what I'm used to (C++).
But I have come across a issue that I for the life of me can't figure out and I'm sure it's going be something stupid. But I am pulling questions and answers from a website that then will display on my iOS application by using this code.
NSString * GetUrl = [NSString stringWithFormat:#"http://www.mywebpage.com/page.php"];
NSString * GetAllHtml = [NSString stringWithContentsOfURL:[NSURL URLWithString:GetUrl] encoding:1 error:nil];
NSString *PullWholeQuestion = [[GetAllHtml componentsSeparatedByString:#"<tr>"] objectAtIndex:1];
NSString *FinishWholeQuestion = [[PullWholeQuestion componentsSeparatedByString:#"</tr>"] objectAtIndex:0];
After I get all of the webpage information I strip down each question and want to make it where it will do a loop process to pull the questions so basically I need to count how many array options there are for the FinishedWholeQuestion variable
I found this snippet online that seemed to work with there example but I cant repeat it
NSArray *stringArray = [NSArray arrayWithObjects:#"1", #"2", nil];
NSLog(#"count = %d", [stringArray count]);
"componentsSeparatedByString" returns an NSArray object, not a single NSString.
An array object can contain zero, one or more NSString objects, depending on the input.
If you change "FinishWholeQuestion" into a NSArray object, you'll likely get a few components (separate by a string).
And now that I'm looking at your code a little more closely, I see you're making an assumption that your array is always valid (and has more than 2 entries, as evidenced by the "objectAtIndex: 1" bit).
You should also change the first character of all your Objective-C variables. Best practices in Objective-C are that the first character of variables should always be lower case.
Like this:
NSString * getUrl = [NSString stringWithFormat:#"http://www.mywebpage.com/page.php"];
NSString * getAllHtml = [NSString stringWithContentsOfURL:[NSURL URLWithString:getUrl] encoding: NSUTF8StringEncoding error:nil];
NSArray * allQuestions = [getAllHtml componentsSeparatedByString:#"<tr>"];
if([allQuestions count] > 1)
{
// assuming there is at least two entries in this array
NSString * pullWholeQuestion = [allQuestions objectAtIndex: 1];
if(pullWholeQuestion)
{
NSString *finishWholeQuestion = [[pullWholeQuestion componentsSeparatedByString:#"</tr>"] objectAtIndex:0];
}
}

How to better initialize strings to avoid dead stores

I found a few questions like this but I couldn't find this particular question. I have a number of strings that are initialized as
NSString *string = [[NSString alloc] init];
which are then assigned a value depending on the results of an if/else block:
if ([anotherThing isEqualToString:#"boogers"]) {
string = [NSString stringWithFormat:#"some characters"];
} else {
string = [NSString stringWithFormat:#"some _other_ characters"];
}
and then string is used later in the method.
How can I accomplish this without leaving a dead store at the alloc/init stage? If I alloc inside the if (or the else), the string is gone by the time I need it several lines down.
You don't have to initialize the string on that first line -- you just need to declare it:
NSString *string = nil;
if ([anotherThing isEqualToString:#"boogers"]) {
string = #"some characters";
} else {
string = #"some _other_ characters";
}
The [NSString stringWithFormat:] will initialize a new NSString object for you, basically what you are doing is declaring a new object each time, just set the pointers for your strings as NSSTring *someString, *someOtherString, *allTheStringsYouNeed; and then use any class method to initialize it even #"Characters"; will work correctly as the compiler do it at runtime for you.

Resources