iOS Declaring object inside a function

xArtx

macrumors 6502a
Original poster
Mar 30, 2012
764
1
Hi Guys,
Here's the best way I could think of to get the local time, and UTC time
into C char arrays timechar, and utimechar:
Code:
    // get local time
    NSDate *today = [NSDate date];
    NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
    [dateFormat setDateFormat:@"MM/dd/yyyy HH:mm:ss"];
    datestring = [dateFormat stringFromDate:today];    
    const char *c = [datestring UTF8String];    
    strncpy(timechar, c, 20);
    char done;
    char dtwo;
    done = timechar[0]; // swap date to Australian format
    dtwo = timechar[1];
    timechar[0] = timechar[3];
    timechar[1] = timechar[4];
    timechar[3] = done;
    timechar[4] = dtwo;
    
    // get utc time
    NSDateFormatter* dfutc = [[NSDateFormatter alloc] init];
    [dfutc setTimeZone:[NSTimeZone timeZoneWithName:@"UTC"]];
    [dfutc setDateFormat:@"MM/dd/yyyy HH:mm:ss"];
    datestring = [dfutc stringFromDate:today];
    const char *d = [datestring UTF8String];
    strncpy(utimechar, d, 20);
    done = utimechar[0]; // swap date to Australian format
    dtwo = utimechar[1];
    utimechar[0] = utimechar[3];
    utimechar[1] = utimechar[4];
    utimechar[3] = done;
    utimechar[4] = dtwo;
Swapping the month and day manually was pretty silly when I could
probably just change the formatter, but there are some really wild
solutions on the net that are supposed to achieve the same thing.

My question is if there is any overhead to do this in a function that is called often.
By "this", I mean allocating the formatters inside the function,
also with regard to other objects, but this one specifically uses the word "allocate".

or is it better to:
Code:
// declare object
NSDateFormatter* dfutc;

// do this somewhere once in the program
dfutc = [[NSDateFormatter alloc] init];

// then continue to use the object inside the function
Cheers, Art.
 
Last edited:

protonail

macrumors newbie
Jun 2, 2013
2
0
I don't recommend to do premature optimizations. Did you check code with profiler and found performance problem in this piece of code? I think the answer is no, so use clear and predictable solutions in this case.
 

ArtOfWarfare

macrumors G3
Nov 26, 2007
8,574
4,005
Do it once. I wouldn't consider it premature optimization because the code should be roughly the same length and equally readable and shouldn't be any more difficult to code. It becomes premature optimization when you have to write a lot of obscure code to get your performance boost.
 

xArtx

macrumors 6502a
Original poster
Mar 30, 2012
764
1
It's just a question for Obj-C programming in general.
With C, it would generally be bad to access global variables in functions,
especially if the variable isn't needed outside of the function.

With NSobjects, I don't know if the same applies.

Performance analyser shows what I'd expect for a vector GPS,
big crunch every second when it has to make calcs and draw a screen.
 

PhoneyDeveloper

macrumors 68040
Sep 2, 2008
3,114
93
This is one typical way to do this using lazy allocation. You could store the date formatter as an ivar if that makes more sense or as a file scope global if you prefer that.

Code:
-(NSDateFormatter*)dateFormatter
{
     static NSDateFormatter* formatter = nil;
     if (! formatter)
     {
          formatter = [[NSDateFormatter alloc] init];
         [formatter setDateFormat:@"MM/dd/yyyy HH:mm:ss"];
     }
     return formatter;
}
The date formatter has to access quite a lot of info related to locales to do its thing so it is considered somewhat heavyweight to create one.
 

Duncan C

macrumors 6502a
Jan 21, 2008
853
0
Northern Virginia
Do it once. I wouldn't consider it premature optimization because the code should be roughly the same length and equally readable and shouldn't be any more difficult to code. It becomes premature optimization when you have to write a lot of obscure code to get your performance boost.

I agree. Memory allocation is a fairly expensive operation.

Lazy loading is a good way to do this. You could create a method

Code:
-(NSDateFormatter *)theDateFormatter;
{
  if (_theDateFormatter = nil)
  {
    _theDateFormatter = [[NSDateFormatter alloc] init];
    //configure the date formatter as needed.
  }
  return _theDateFormatter;
}
Then, any time in your code that you need to refer to your date formatter, use "[self theDateFormatter]".

If you're writing C functions, not methods, then you might need to create a Utilities class and make your theDateFormatter method be a Utilities class method that saves it's date formatter to a private static variable.

The overhead of a method call is dwarfed by the overhead of memory allocation. In fact, the runtime caches method selector lookup and short-circuits method calls into C function calls, so repeated method calls are nearly as fast as function calls.
 

chown33

Moderator
Staff member
Aug 9, 2009
8,486
4,495
Restivus
Lazy loading is a good way to do this.
If there is any possibility of the function or method being called from multiple threads, then the lazy instantiation of the singleton object should be made thread-safe. If it's not, Bad Things may result.

Example of thread-safe (and unsafe) code:
http://cocoasamurai.blogspot.com/2011/04/singletons-your-doing-them-wrong.html

Google search terms: cocoa singleton


To the OP:
Fix the format string so it doesn't require the silly and obtuse shuffling of characters after conversion. There is no reason to keep such horrible code while also worrying about speed. Yes, you'll have to learn what the formatting characters in the format string do, rather than blindly adding copy-pasta with after-the-fact "fixes".
 

xArtx

macrumors 6502a
Original poster
Mar 30, 2012
764
1
Thanks for the replies.
I thin I can work with the example given,
and I've seen some sample code that does the same thing...
I think it's actually OpenEars (flite) lib that does it.

To the OP:
Fix the format string so it doesn't require the silly and obtuse shuffling of characters after conversion. There is no reason to keep such horrible code while also worrying about speed. Yes, you'll have to learn what the formatting characters in the format string do, rather than blindly adding copy-pasta with after-the-fact "fixes".
I kinda did say that.
This was the first thing I got working.
Prior to that I was reading the timezone difference, and applying a difference
to the value for hours input to some algorithms. Now I can input UTC.

Looking a bit harder at my copy-pasta fix, I should have used one less variable:
Code:
   	char done;
	done = timechar[0]; // swap date to Australian format
	timechar[0] = timechar[3];
	timechar[3] = done;
	done = timechar[1];
	timechar[1] = timechar[4];
	timechar[4] = done;
That's a much more worthy hack job!
 

ArtOfWarfare

macrumors G3
Nov 26, 2007
8,574
4,005
Thanks for the replies.
I thin I can work with the example given,
and I've seen some sample code that does the same thing...
I think it's actually OpenEars (flite) lib that does it.



I kinda did say that.
This was the first thing I got working.
Prior to that I was reading the timezone difference, and applying a difference
to the value for hours input to some algorithms. Now I can input UTC.

Looking a bit harder at my copy-pasta fix, I should have used one less variable:
Code:
   	char done;
	done = timechar[0]; // swap date to Australian format
	timechar[0] = timechar[3];
	timechar[3] = done;
	done = timechar[1];
	timechar[1] = timechar[4];
	timechar[4] = done;
That's a much more worthy hack job!
... If that makes sense, comment it. I have no idea what you're doing or why you're doing it, and I doubt you will either after setting the file down for a few months then looking at it again if you don't comment it.
 

xArtx

macrumors 6502a
Original poster
Mar 30, 2012
764
1
... If that makes sense, comment it. I have no idea what you're doing or why you're doing it, and I doubt you will either after setting the file down for a few months then looking at it again if you don't comment it.
It is commented: //swap date to Australian format.
In Australia, we write today's date: 03/06/13.
All I'm doing is swapping the two chars in the result string,
where I should have just changed the date formatter.

It's no biggie. I'll eventually have to do it based on timezone.
It's small time compared to something like converting Kilometers to Miles for other countries.
 

Duncan C

macrumors 6502a
Jan 21, 2008
853
0
Northern Virginia
It is commented: //swap date to Australian format.
In Australia, we write today's date: 03/06/13.
All I'm doing is swapping the two chars in the result string,
where I should have just changed the date formatter.

It's no biggie. I'll eventually have to do it based on timezone.
It's small time compared to something like converting Kilometers to Miles for other countries.
Formatting dates for the local conventions of the user is exactly what date formatters are for.

Whenever possible, you should ask for dates to be formatted in the most general way possible (e.g. short date format) and then let the date formatter generate the string for you using the user's current locale. Date formatters know about the date conventions in a huge number of different languages and countries, and will take care of it for you, without any special code on your part. Here in the US, we'll get our silly mm/dd/yy format. In Oz, and in much of Europe, you'll get dd/mm/yy. If you want 3 letter month codes, those will be converted to the correct language format.

Using a date formatter and then byte-swapping the strings that come out of it is a bad idea, because in other countries the output date format may be different, causing your code to corrupt the date.
 

chown33

Moderator
Staff member
Aug 9, 2009
8,486
4,495
Restivus
It is commented: //swap date to Australian format.
In Australia, we write today's date: 03/06/13.
People outside Australia may not know what "Australian format" means. I sure didn't, and had to read and comprehend the byte shuffling in order to know what it meant.

If you had commented "swap to dd/MM/yyyy format", it would have been clearer. However, it would be even more puzzling as to why you didn't just use that as the format string in the first place.

Obtuse code should be fixed, not simply commented, unless there's a good reason for the obtuseness to remain. I see no such reason here.
 

xArtx

macrumors 6502a
Original poster
Mar 30, 2012
764
1
Date formatters know about the date conventions in a huge number of different languages and countries, and will take care of it for you, without any special code on your part.
I didn't know it would know to change the format, thx.

So I was able to declare the objects globally,
and reduce what's in the C function to this:
Code:
  today = [NSDate date];

  // get local time
  datestring = [dateFormat stringFromDate:today];    
  const char *c = [datestring UTF8String];    
  strncpy(timechar, c, 20);
    
  // get utc time
  datestring = [dfutc stringFromDate:today];
  const char *d = [datestring UTF8String];
  strncpy(utimechar, d, 20);
I did the allocation in an "if" that is only runs once, and contains
code to to other initialisation as well:
Code:
if (trig == 0) {
    dateFormat = [[NSDateFormatter alloc] init];
    [dateFormat setDateFormat:@"dd/MM/yyyy HH:mm:ss"];   
    dfutc = [[NSDateFormatter alloc] init];
    [dfutc setTimeZone:[NSTimeZone timeZoneWithName:@"UTC"]];
    [dfutc setDateFormat:@"dd/MM/yyyy HH:mm:ss"]; 

// do other initialisation stuff for example,
pidivtwo = PI / 2.0; pitimestwo = PI * 2.0;

// lock this code for future passes
trig = 1;
}
Thing is, the format needs to be what I expect, in order to input it
into a bunch of calculations. I wouldn't be able to format it to local
conventions until it comes time to display it.

Anyway, it works...
 

xArtx

macrumors 6502a
Original poster
Mar 30, 2012
764
1
Why not pull the components out of the NSDate as needed for the calculations? Have you heard of NSDateComponents?
Sorry, I made a mistake there...

I'm getting UTC and Local time into two separate strings.

UTC time is used for the calculations (along with TZ offset if needed),
and local time is used for display.
So I could mess up the local time at will without consequence.

I guess this is resolved, though I still want to load the month and day chars into
a four byte array and bitwise rotate the array 16 times to swap the dates.
 

xArtx

macrumors 6502a
Original poster
Mar 30, 2012
764
1
Have you heard of NSDateComponents?
Obviously not!
Code:
    int myear = 2000, uyear = 2000; // will expire 2099
    int mmonth = 0, umonth = 0;
    int mday = 0, uday = 0;
    int mhour = 0, uhour = 0;
    int mmin = 0;
    int umin = 0;
    int msec = 0;
   // local time components
    myear = myear + ((timechar[8] - 0x30)*10);
    myear = myear + (timechar[9] - 0x30);
    mmonth = mmonth + ((timechar[3] - 0x30)*10);
    mmonth = mmonth + (timechar[4] - 0x30);        
    mday = mday + ((timechar[0] - 0x30)*10);
    mday = mday + (timechar[1] - 0x30);        
    mhour = mhour + ((timechar[11] - 0x30)*10);
    mhour = mhour + (timechar[12] - 0x30);
    mmin = mmin + ((timechar[14] - 0x30)*10);
    mmin = mmin + (timechar[15] - 0x30);
    msec = msec + ((timechar[17] - 0x30)*10);
    msec = msec + (timechar[18] - 0x30);
    // UTC time components
    uyear = uyear + ((utimechar[8] - 0x30)*10);
    uyear = uyear + (utimechar[9] - 0x30);
    umonth = umonth + ((utimechar[3] - 0x30)*10);
    umonth = umonth + (utimechar[4] - 0x30);
    uday = uday + ((utimechar[0] - 0x30)*10);
    uday = uday + (utimechar[1] - 0x30);
    uhour = uhour + ((utimechar[11] - 0x30)*10);
    uhour = uhour + (utimechar[12] - 0x30);
    umin = umin + ((utimechar[14] - 0x30)*10);
    umin = umin + (utimechar[15] - 0x30);
but I have no use for this code anymore.
 

Duncan C

macrumors 6502a
Jan 21, 2008
853
0
Northern Virginia
Obviously not!
Code:
    int myear = 2000, uyear = 2000; // will expire 2099
    int mmonth = 0, umonth = 0;
    int mday = 0, uday = 0;
    int mhour = 0, uhour = 0;
    int mmin = 0;
    int umin = 0;
    int msec = 0;
   // local time components
    myear = myear + ((timechar[8] - 0x30)*10);
    myear = myear + (timechar[9] - 0x30);
    mmonth = mmonth + ((timechar[3] - 0x30)*10);
    mmonth = mmonth + (timechar[4] - 0x30);        
    mday = mday + ((timechar[0] - 0x30)*10);
    mday = mday + (timechar[1] - 0x30);        
    mhour = mhour + ((timechar[11] - 0x30)*10);
    mhour = mhour + (timechar[12] - 0x30);
    mmin = mmin + ((timechar[14] - 0x30)*10);
    mmin = mmin + (timechar[15] - 0x30);
    msec = msec + ((timechar[17] - 0x30)*10);
    msec = msec + (timechar[18] - 0x30);
    // UTC time components
    uyear = uyear + ((utimechar[8] - 0x30)*10);
    uyear = uyear + (utimechar[9] - 0x30);
    umonth = umonth + ((utimechar[3] - 0x30)*10);
    umonth = umonth + (utimechar[4] - 0x30);
    uday = uday + ((utimechar[0] - 0x30)*10);
    uday = uday + (utimechar[1] - 0x30);
    uhour = uhour + ((utimechar[11] - 0x30)*10);
    uhour = uhour + (utimechar[12] - 0x30);
    umin = umin + ((utimechar[14] - 0x30)*10);
    umin = umin + (utimechar[15] - 0x30);
but I have no use for this code anymore.
Oh man. NSCalendar, NSDate, and NSDateComponents have all kinds of handy methods for doing date/time calculations. Do a search in the Xcode docs under "Performing Calendar Calculations" and read the article that comes up. Also read the whole introduction to the NSCalendar class.

Methods like components:fromDate:, components:fromDate:toDate:, and dateByAddingComponents:toDate:eek:ptions: are very powerful and very useful.

As you say, you can chuck all that nasty code above.
 

xArtx

macrumors 6502a
Original poster
Mar 30, 2012
764
1
Oh man. NSCalendar, NSDate, and NSDateComponents have all kinds of handy methods for doing date/time calculations. Do a search in the Xcode docs under "Performing Calendar Calculations" and read the article that comes up. Also read the whole introduction to the NSCalendar class.

Methods like components:fromDate:, components:fromDate:toDate:, and dateByAddingComponents:toDate:eek:ptions: are very powerful and very useful.

As you say, you can chuck all that nasty code above.
Whoah, Hmm. Unless it can look at say, something like,
what hour is it in UTC timezone without calculating every other component,
wouldn't calculating only the components you need always be faster?

So in English, if I only wanted to know the Time Of Day in some country,
and I have their timezone offset, couldn't you always calculate the result
time faster because you didn't reference a calendar to look at other information?

For a particular thing I'm doing, I want to display the Time 00:00 in any
timezone, but the time only. It doesn't even have to know if it is the day
before, or after any other reference timezone.

Admittedly, I haven't RTM, but I will.
 
Last edited:

ArtOfWarfare

macrumors G3
Nov 26, 2007
8,574
4,005
Whoah, Hmm. Unless it can look at say, something like,
what hour is it in UTC timezone without calculating every other component,
wouldn't calculating only the components you need always be faster?

So in English, if I only wanted to know the Time Of Day in some country,
and I have their timezone offset, couldn't you always calculate the result
time faster because you didn't reference a calendar to look at other information?
You sound like you're contemplating premature optimization. Don't optimize code until you know it's slow.
 
Last edited:

xArtx

macrumors 6502a
Original poster
Mar 30, 2012
764
1
You sound like you're contemplating premature optimization. Don't optimize code until you know it's slow.
The learning curve for me is a factor. I already know how to do what I'm already doing.
It's not as appealing to learn if I don't think the results will be better than
what I'm already doing (basically) in a particular project.

Don't get me wrong, I've already seen some nice examples,
and in this case it's something I'm going to have to learn anyway.
It's not like a future platform is going to arrive that doesn't have it's
own clock and calendar, so it doesn't seem any less portable to use one.
 

Duncan C

macrumors 6502a
Jan 21, 2008
853
0
Northern Virginia
Whoah, Hmm. Unless it can look at say, something like,
what hour is it in UTC timezone without calculating every other component,
wouldn't calculating only the components you need always be faster?

So in English, if I only wanted to know the Time Of Day in some country,
and I have their timezone offset, couldn't you always calculate the result
time faster because you didn't reference a calendar to look at other information?

For a particular thing I'm doing, I want to display the Time 00:00 in any
timezone, but the time only. It doesn't even have to know if it is the day
before, or after any other reference timezone.

Admittedly, I haven't RTM, but I will.
Processing speed is not usually a consideration when writing this type of code. Unless you are processing tens of thousands of dates you would need sensitive measurements to detect the difference in performance.

Maintainability and ease of localization is much, much more important. I find NSCalendar, NSDate, and NSDateComponents very easy to work with, and the logic is flawless. Your code that calculates month numbers quite likely has edge case problems. Date calculations are a royal pain to get perfect (and test to verify that they are perfect.)
 

xArtx

macrumors 6502a
Original poster
Mar 30, 2012
764
1
Processing speed is not usually a consideration when writing this type of code. Unless you are processing tens of thousands of dates you would need sensitive measurements to detect the difference in performance.

Maintainability and ease of localization is much, much more important. I find NSCalendar, NSDate, and NSDateComponents very easy to work with, and the logic is flawless. Your code that calculates month numbers quite likely has edge case problems. Date calculations are a royal pain to get perfect (and test to verify that they are perfect.)
I don't disagree (generally), and it probably does sound anal or lazy of me,
but I do want to process an unusually high number of timezones. I want to recreate this:
http://www.youtube.com/watch?v=g0kr7hbN744
on the iOS platform.

It's only the fancy display that requires all the checking, otherwise you could
just check the time at the start and finish point on the map.
As a bi more of an "adult", and with the conveniences this platform offers,
I would be checking inside timezone polygons this time.

It is just an excersise for me, but one concrete practical example is to stop
people cheating in games by changing their time zone in settings.
This can determine your timezone without the need for looking at the clock,
as long as the user agrees to Location Services (which could be a requirement).
 

ArtOfWarfare

macrumors G3
Nov 26, 2007
8,574
4,005
I don't disagree (generally), and it probably does sound anal or lazy of me,
but I do want to process an unusually high number of timezones. I want to recreate this:
http://www.youtube.com/watch?v=g0kr7hbN744
on the iOS platform.

It's only the fancy display that requires all the checking, otherwise you could
just check the time at the start and finish point on the map.
As a bi more of an "adult", and with the conveniences this platform offers,
I would be checking inside timezone polygons this time.

It is just an excersise for me, but one concrete practical example is to stop
people cheating in games by changing their time zone in settings.
This can determine your timezone without the need for looking at the clock,
as long as the user agrees to Location Services (which could be a requirement).
So use NSTimeZones with customized offsets, if you want to support additional time zones.