Geolocation API - Is there a way to make random locations each time? - ios

I currently have a map app that is supposed to give random locations on each press - however I am often met with 'ZERO_RESULTS'
The method part
int randomIndex = arc4random() % [arr_OfCountryCode count];
NSString *urlString = [NSString stringWithFormat:#"https://maps.googleapis.com/maps/api/geocode/json?address=%#&sensor=false,+CA&key=MY_GOOGLE_KEY",[arr_OfCountryCode objectAtIndex:randomIndex]];
The array of CountryCodes are;
arr_OfCountryCode = #[#"AF",#"AL",#"DZ",#"AS",#"AD",#"AO",#"AI",#"AQ",#"AG",#"AR",#"AM",#"AW",#"AC",#"AU",#"AT",#"AZ",#"BS",#"BH",#"BD",#"BB",#"BY",#"BE",#"BZ",#"BJ",#"BM",#"BT",#"BO",#"BA",#"BW",#"BV",#"BR",#"IO",#"VG",#"BN",#"BG",#"BF",#"BI",#"KH",#"CM",#"CA",#"IC",#",CV",#"BQ",#"KY",#"CF",#"EA",#"TD",#"CL",#"CN",#"CX",#"CP",#"CC",#"CO",#"KM",#"CD",#"CG",#"CK",#"CR",#"HR",#"CU",#"CW",#"CY",#"CZ",#"CI",#"DK",#"DG",#"DJ",#"DM",#"DO",#"EC",#"EG",#"SV",#"GQ",#"ER",#"EE",#"ET",#"FK",#"FO",#"FJ",#"FI",#"FR",#"FG",#"PF",#"TF",#"GA",#"GM",#"GE",#"DE",#"GH",#"GI",#"GR",#"GL",#"GD",#"GP",#"GU",#"GT",#"GG",#"GN",#"GW",#"GY",#"HT",#"HM",#"HN",#"HK",#"HU",#"IS",#"IN",#"ID",#"IR",#"IQ",#"IE",#"IM",#"IL",#"IT",#"JM",#"JP",#"JE",#"JO",#"KZ",#"KE",#"KI",#"XK",#"KW",#"KG",#"LA",#"LV",#"LB",#"LS",#"LR",#"LY",#"LI",#"LT",#"LU",#"MO",#"MK",#"MG",#"MW",#"MY",#"MV",#"ML",#"MT",#"MH",#"MQ",#"MR",#"MU",#"YT",#"MX",#"FM",#"MD",#"MC",#"MN",#"ME",#"MS",#"MA",#"MZ",#"MM",#"NA",#"NR",#"NP",#"NL",#"NC",#"NZ",#"NI",#"NE",#"NG",#"NU",#"NF",#"KP",#"MP",#"NO",#"OM",#"PK",#"PW",#"PS",#"PA",#"PG",#"PY",#"PE",#"PH",#"PN",#"PL",#"PT",#"PR",#"QA",#"RO",#"RU",#"RW",#"RE",#"WS",#"SM",#"SA",#"SN",#"RS",#"SC",#"SL",#"SG",#"SX",#"SK",#"SI",#"SB",#"SO",#"ZA",#"GS",#"KR",#"SS",#"ES",#"LK",#"BL",#"SH",#"KN",#"LC",#"MF",#"PM",#"VC",#"SD",#"SR",#"SJ",#"SZ",#"SE",#"CH",#"SY",#"ST",#"TW",#"TJ",#"TZ",#"TH",#"TL",#"TG",#"TK",#"TO",#"TT",#"TA",#"TN",#"TR",#"TM",#"TC",#"TV",#"UM",#"VI",#"UG",#"UA",#"AE",#"GB",#"US",#"UY",#"UZ",#"VU",#"VA",#"VE",#"VN",#"WF",#"EH",#"YE",#"ZM",#"ZW",#"AX"];
Ideally all I really want is to come up with a random location in any country each time, I did think this would work, but it comes up ZERO_RESULTS more times than it works...

Related

Save a large number of objects in coredata

I try to save many objects in coredata, but get this crash:
Communications error: <OS_xpc_error: <error: 0x19b354af0> { count = 1, contents =
"XPCErrorDescription" => <string: 0x19b354e50> { length = 22, contents = "Connection interrupted" }
}>
Message from debugger: Terminated due to memory issue
I use MagicalRecord:
[MagicalRecord saveInBackgroundWithBlock:^(NSManagedObjectContext *localContext){
for (int i = 0; i < json.count; i++) {
[Product parseWithData:((NSMutableArray *)json)[i]];
}
}];
Product.m
+ (void)parseWithData:(NSDictionary *)dictionary {
NSString *xml_id = [dictionary[#"XML_ID"] isKindOfClass:[NSString class]] ? dictionary[#"XML_ID"] : #"";
Product *product = [Product getProductWithXML_id:xml_id];
if (!product)
product = [Product MR_createEntity];
product.xml_id = xml_id;
product.code = [dictionary[#"Code"] isKindOfClass:[NSString class]] ? dictionary[#"Code"] : #"";
...
}
Can you suggest me, how can i save it?
When i save my objects in loop to core data - memory grow very fast
It seems to be a memory issue.
Try surrounding the inner part of your for loop with
autoreleasepool {
...
}
You need to paginate the way you get the data and/or save it.
By paginate, i mean :
download the first 1000 (for example, it depends on the content really)
When its done, save the 1000 you just go
When that is done, get the next 1000, save it again, and so on.
You need to know the number you're trying to get and use the (if I remember correctly ) SetLimit: on the parse method, and SetSkip. The skip skips the X first elements, and the limit is the max number of items that will be downloaded.
That way, you skip 0 with limit 1000, then recall the method with skip += limit, and you'll get the second 1000 chunk, and so on. The last chunk will obviously be smaller than 1000.
Doing this will drastically increase the time taken, but that could be done seamlessly in the background ; but it will be spread over much enough to need less memory.
Do it, and see if it makes a big difference. If not, you could always reduce to 500 instead of 1000, or completely change your architecture ; maybe you don't even need ALL the items right now !

NSDecimalNumber for finances

I'm building an app that deals with money and I've been using floating point arithmetic up until now, but I've learned that it's better to use NSDecimalNumber.
I want to make sure that I've understood it correctly, so here goes:
Imagine some worker, earning 20.57$/hour. This information is provided by the user. I did it like this before:
#property (nonatomic) float hourlyRate;
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
numberFormatter.numberStyle = NSNumberFormatterDecimalStyle;
NSNumber *hourlyRate = [numberFormatter numberFromString:self.rateTextField.text];
settingsObject.hourlyRate = [hourlyRate floatValue];
But I've now changed it to:
#property (nonatomic) NSDecimalNumber *hourlyRate;
settingsObject.hourlyRate = (NSDecimalNumber *)[NSDecimalNumber decimalNumberWithString:self.rateTextField.text locale:[NSLocale currentLocale]];
Is this the correct way to read NSDecimalNumbers from string?
Say this person enters a workplace at 10:01. I save that information like so:
[[NSUserDefaults standardUserDefaults] setObject:[NSDate date] forKey:#"start"];
Once the person is finished, the start time is read from NSUserDefaults like so:
NSDate *start = [[NSUserDefaults standardUserDefaults] objectForKey:#"start"];
The duration is calculated like so:
NSTimeInterval interval = [[NSDate date] timeIntervalSinceDate:start] / 3600;
NSDecimalNumber *earned = [settingsObject.hourlyRate decimalNumberByMultiplyingBy:[[NSDecimalNumber alloc] initWithFloat:interval]];
is this the correct and most efficient way, while keeping precision?
Thanks!
Is this the correct way to read NSDecimalNumbers from string?
Yes. However, you shouldn't need to cast the result. So it should just look like this:
settingsObject.hourlyRate = [NSDecimalNumber decimalNumberWithString:self.rateTextField.text locale:[NSLocale currentLocale]];
And the NSLocale part isn't necessary, unless you're using a non-current locale:
settingsObject.hourlyRate = [NSDecimalNumber decimalNumberWithString:self.rateTextField.text];
I don't think this function likes nil values, so you would want to make sure that rateTextField has a non-nil value first:
if ([self.rateTextField hasText]) {
settingsObject.hourlyRate = [NSDecimalNumber decimalNumberWithString:self.rateTextField.text];
}
else {
settingsObject.hourlyRate = [NSDecimalNumber zero];
}
is this the correct and most efficient way, while keeping precision?
Yes, your conversion of the interval to an NSDecimal number and then the multiplication looks good to me.
First you need an answer for this question:
How accurate do you want to be - or do you need to be?
Will your app generate invoices, or will it serve as the basis for invoices? If yes, you may have to stay away from floating point numbers. You may also have to think about how duration is actually used in calculations. There may be regulations for certain business areas or professions, which define how to measure / invoice time.
Not really accurate:
If you do not need to be really accurate, I would continue using floating numbers until you hit obstacles.
Accurate:
1. Money:
Store money as integers as cents.
2. Time:
Determine time slots and store them as integers (maybe minutes).
3. Calculations:
Calculate using integers. Never use floats.
Details:
When you have an input like 25.07 (I used a different number than your 20.57 to explain cents rendering) store it as 2507. Do your calculations in cents. For displaying convert to $ or $/hrs. For example:
int amount = 2507;
int amountDollars = amount / 100;
int amountCents = amount % 100;
NSString *output = [NSString stringWithFormat:#"%d.%02d $/hrs", amountDollars, amountCents];
NSLog(#"output = %#", output);
// prints:
// output = 25.07 $/hrs
For time chose a suitable base unit (minute / second / five minutes / ten minutes / half an hour?) and store that as an integer.
Lets assume you invoice in units of 10 minutes. You probably then bill the next 10 minutes, when they are begun. So if 11 minutes are in the record, you have to calculate 20 minutes. Similar issues exist for minutes - assume these values:
Actual Time | "Integer Time"
10:09:59 | 10:09
10:10:01 | 10:10
Difference:
00:00:02 | 00:01
If you just use actual time using floating points the first difference amounts to almost nothing - the second amounts to one minute. If your times are shown in the report as 10:09 and 10:10, people will wonder, why in the first case the amount is almost nothing.
Doing financial and time calculations is hard if you need to be really accurate. So it boils down to this: First find out, how accurate you need to be. (Note that "accurate" may have weird meanings and implications when entering the realm of regulations, laws etc.)

Arabic characters (effective power bug) crash my swift iOS app. how do I properly sanitize inputs to avoid this and related problems?

the text that caused the crash is the following:
the error occurred at the following line:
let size = CGSize(width: 250, height: DBL_MAX)
let font = UIFont.systemFontOfSize(16.0)
let attributes = [
NSFontAttributeName:font ,
NSParagraphStyleAttributeName: paraStyle
]
var rect = text.boundingRectWithSize(size, options:.UsesLineFragmentOrigin, attributes: attributes, context: nil)
where text variable contains the inputted string
parastyle is declared as follows:
let paraStyle = NSMutableParagraphStyle()
paraStyle.lineBreakMode = NSLineBreakMode.ByWordWrapping
My initial idea is that the system font can't handle these characters and I need to do an NSCharacterSet, but I'm not sure how to either just ban characters that'll crash my app or make it so i can handle this input (ideal). I don't want to ban emojis/emoticons either.
Thanks!
Not an answer but some information and that possibly provids a way code way to avoid it.
Updated to information from The Register:
The problem isn’t with the Arabic characters themselves, but in how the unicode representing them is processed by CoreText, which is a library of software routines to help apps display text on screens.
The bug causes CoreText to access memory that is invalid, which forces the operating system to kill off the currently running program: which could be your text message app, your terminal, or in the case of the notification screen, a core part of the OS.
From Reddit but this may not be completely correct:
It only works when the message has to be abbreviated with ‘…’. This is usually on the lock screen and main menu of Messages.app.
The words effective and power can be anything as long as they’re on two different lines, which forces the Arabic text farther down the message where some of the letters will be replaced with ‘…’
The crash happens when the first dot replaces part of one of the Arabic characters (they require more than one byte to store) Normally there are safety checks to make sure half characters aren’t stored, but this replacement bypasses those checks for whatever reason.
My solution is the next category:
static NSString *const CRASH_STRING = #"\u0963h \u0963 \u0963";
#implementation NSString (CONEffectivePower)
- (BOOL)isDangerousStringForCurrentOS
{
if (IS_IOS_7_OR_LESS || IS_IOS_8_4_OR_HIGHER) {
return NO;
}
return [self containsEffectivePowerText];
}
- (BOOL)containsEffectivePowerText
{
return [self containsString:CRASH_STRING];
}
#end
Filter all characters to have same directionality. Unfortunately, I'm only aware of such API in Java.
Don't even try. This is a bug in the operating system that will be fixed. It's not your problem. If you try to fix it, you are just wasting your time. And you are very likely to introduce bugs - when you say you "sanitise" input that means you cannot handle some perfectly fine input.
The company I work at develops a multiplatform group video chat.
In Crashlytics report we started noticing that some users are "effectively" trolling iOS users using this famous unicode sequence.
We can't just sit and wait for Apple to fix this bug.
So, I've worked on this problem, this is the shortest crashing sequence I got:
// unichar representation
unichar crashChars[8] = {1585, 1611, 32, 2403, 32, 2403, 32, 2403};
// string representation
NSString *crashString = #"\u0631\u064b \u0963 \u0963 \u0963"
So, I decided to filter out all text messages that contains two U+0963 'ॣ' symbols with one symbol between them (hope you are able to decipher this phrase)
My code from NSString+Extensions category.
static const unichar kDangerousSymbol = 2403;
- (BOOL)isDangerousUnicode {
NSUInteger distance = 0;
NSUInteger charactersFound = 0;
for (NSUInteger i = 0; i < self.length; i++) {
unichar character = [self characterAtIndex:i];
if (charactersFound) {
distance++;
}
if (distance > 2) {
charactersFound = 0;
}
if (kDangerousSymbol == character) {
charactersFound++;
}
if (charactersFound > 1 && distance > 0) {
return YES;
}
}
return NO;
}
Lousy Specta test:
SpecBegin(NSStringExtensions)
describe(#"NSString+Extensions", ^{
//....
it(#"should detect dangerous Unicode sequences", ^{
expect([#"\u0963 \u0963" isDangerousUnicode]).to.beTruthy();
expect([#"\u0631\u064b \u0963 \u0963 \u0963" isDangerousUnicode]).to.beTruthy();
expect([#"\u0631\u064b \u0963 \u0963 \u0963" isDangerousUnicode]).to.beFalsy();
});
//....
});
SpecEnd
I'm not sure if it's OK to "discriminate" messages with too many "devanagari vowel sign vocalic ll".
I'm open to corrections, suggestions, criticism :).
I would love to see a better solution to this problem.

Iterating through an NSDictionary and timing events in IOS

I'm new to IOS / Objective C and am trying to figure out the best way to create a collection, iterate over it, and time events.
I have a series of lines of a song and I want an individual line of a song to appear on the screen as the music is playing at the right point in the song. So I've started by doing the following: I put the individual lines into a Dictionary and the millisecond value of when the line should appear.
NSDictionary *bualadhBos = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:2875], #"Muid uilig ag bualadh bos, ",
[NSNumber numberWithInt:3407], #"Muid uilig ag tógáil cos, ",
[NSNumber numberWithInt:3889], #"Muid ag déanamh fead ghlaice, ",
[NSNumber numberWithInt:4401], #"Muid uilig ag geaibíneacht. ",
[NSNumber numberWithInt:4900], #"Buail do ghlúine 1, 2, 3, ",
[NSNumber numberWithInt:5383], #"Buail do bholg mór buí, ",
[NSNumber numberWithInt:5910], #"Léim suas, ansin suigh síos, ",
[NSNumber numberWithInt:6435], #"Seasaigh suas go hard arís. ",
[NSNumber numberWithInt:6942], #"Sín amach do dhá lamh, ",
[NSNumber numberWithInt:7430], #"Anois lig ort go bhfuil tú ' snámh. ",
[NSNumber numberWithInt:7934], #"Amharc ar dheis, ansin ar chlé, ",
[NSNumber numberWithInt:8436], #"Tóg do shúile go dtí an spéir. ",
[NSNumber numberWithInt:8940], #"Tiontaigh thart is thart arís, ",
[NSNumber numberWithInt:9436], #"Cuir síos do dhá lámh le do thaobh, ",
[NSNumber numberWithInt:9942], #"Lámha suas is lúb do ghlúin, ",
[NSNumber numberWithInt:10456], #"Suigí síos anois go ciúin. ", nil
];
then I wanted to iterate over the Dictionary, create a Timer that would call a method that is responsible for changing the text in the textLayer
for (id key in bualadhBos ) {
NSTimer *timer;
timer = [[NSTimer scheduledTimerWithTimeInterval:bualadhBos[key] target:self selector:#selector(changeText) userInfo:nil repeats:NO]];
}
-(void)changeText {
// change the text of the textLayer
textLayer.string = #"Some New Text";
}
But as I started to debug this and inspect how it might work, I noticed in the debugger that the order which the items appear in the Dictionary have all been shuffled around. I'm also concerned (I don't know enough about this) that I'm creating multiple timers and that there might be a more efficient approach to solving this problem.
Any direction would be greatly appreciated.
Dictionaries are sorted by definition in the way that is most suitable for hash algorithm so you should never rely on their order.
In your case it would be better to build a binary tree and have a single NSTimer that fires once a second, performs binary tree search and returns the closest string for provided time offset.
If you use AVFoundation or AVPlayer for playback. Then to synchronize subtitles with media playback, you could use something like addPeriodicTimeObserverForInterval to fire timer once a second and perform search in your binary tree and update UI.
In pseudo code:
[player addPeriodicTimeObserverForInterval:CMTimeMake(1, 1) queue:NULL usingBlock:^(CMTime time) {
// get playback time
NSTimeInterval seconds = CMTimeGetSeconds(time);
// search b-tree
NSString* subtitle = MyBtreeFindSubtitleForTimeInterval(seconds);
// update UI
myTextLabel.text = subtitle;
}];
I noticed in the debugger that the order which the items appear in the Dictionary have all been shuffled around.
Dictionaries are not ordered collections. Don't rely on the order of the elements being the same as the order that you added the elements. Don't rely on the order of the elements at all, in any respect.
If you want to access the elements of a dictionary in a certain order, create an array containing the keys in the order you prefer. Then iterate over the array and use each key to access the corresponding value in the array. In your case, you could get the array of keys, sort it into ascending order, and use that. Or, you could create an array of dictionaries with keys like "time" and "lyric", one for each line.
All that said, given your current code it's hard to see why you care need to access the elements in a particular order. If you're creating all the timers at once, as you're currently doing, things should work fine until the number of timers becomes a problem. I'm not sure where that point is, but I'm sure it's much greater than 20.
I'm creating multiple timers and that there might be a more efficient approach to solving this problem
Sure. You're creating one timer for each line all at once, so that many timers run concurrently. You could instead just create the first timer and have it's action create another timer when it fires, and so on for each line. To avoid timer drift, use the system time to calculate the appropriate delay to the time when the next line should be displayed.

Picking the nearest 3 dates out of a list

I am working on a TV-guide app, and am trying to get the nearest 3 dates from an NSArray with NSDictionary's. So far so good, but I have been trying to figure out how I can do this the best way using as little memory as possible and with as little code (hence decreasing the likelihood of bugs or crashes). The array is already sorted.
I have a dictionary with all the channels shows for one day. The dictionary withholds an NSDate (called date).
Lets say a channel has 8 shows and the time is now 11:45. show #3 started at 11:00 and ends at 12:00, show #4 starts at 12:00 and ends at 13:00, show #5 at 13:00 to 14:00 ect.
How could I fetch show #3 (which started in the past!), #4 and #5 the fastest (memory wise) and easiest from my array of dictionaries?
Currently I am doing a for loop fetching each dictionary, and then comparing the dictionaries date with the current date. And thats where I am stuck. Or maybe I just have a brain-fag.
My current code (after a while of testing different things):
- (NSArray*)getCommingProgramsFromDict:(NSArray*)programs amountOfShows:(int)shows
{
int fetched = 0;
NSMutableArray *resultArray = [[NSMutableArray alloc] init];
NSDate *latestDate = [NSDate date];
for (NSDictionary *program in programs)
{
NSDate *startDate = [program objectForKey:#"date"];
NSLog(#"Program: %#", program);
switch ([latestDate compare:startDate]) {
case NSOrderedAscending:
NSLog(#"latestDate is older, meaning the show starts in the future from latestDate");
// do something
break;
case NSOrderedSame:
NSLog(#"latestDate is the same as startDate");
// do something
break;
case NSOrderedDescending:
NSLog(#"latestDate is more recent, meaning show starts in the past");
// do something
break;
}
// Now what?
}
return resultArray;
}
I am writing it for iOS 5, using ARC.
After your EDIT and explanation, here is another answer, hopefully fitting your question better.
The idea is to find the index of the show that is next (startDate after now). Once you have it, it will be easy to get the show at the previous index (on air) and the 2 shows after it.
NSUInteger indexOfNextShow = [arrayOfShows indexOfObjectPassingTest:^BOOL(id program, NSUInteger idx, BOOL *stop) {
NSDate* startDate = [program objectForKey:#"date"];
return ([startDate timeIntervalSinceNow] > 0); // startDate after now, so we are after the on-air show
}];
At that stage, indexOfNextShow contains the index of the show in your NSArray that will air after the current show. Thus what you want according to your question is objects at index indexOfNextShow-1 (show on air), indexOfNextShow (next show) and indexOfNextShow+1 (show after the next).
// in practice you should check the range validity before doing this
NSIndexSet* indexes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(indexOfNextShow-1,3)];
NSArray* onAirShowAnd2Next = [arrayOfShows objectsAtIndexes:indexes];
Obviously in practice you should add some verifications (like indexOfNextShow being >0 before trying to access object at index indexOfNextShow-1 and indexOfNextShow+1 not being past the total number of shows in your array).
The advantage of this is that since your array of shows is sorted by startDate already, indexOfObjectPassingTest: returns the first object passing the test, and stop iterating as soon as it has found the right object. So this is both concise, easy-to-read code and relatively efficient.
.
I'm not sure I understood your model structure, you have an NSArray of shows, each show being a NSDictionary holding the NSDate of the show along with other info, right?
One idea then is to sort this NSArray of show according to the distance between the start time of the show and now.
NSArray* shows = ... // your arraw of NSDictionaries representing each show
NSArray* sortedShows = [shows sortedArrayUsingComparator:^(id show1, id show2) {
NSTimeInterval ti1 = fabs([[show1 objectForKey:#"startDate"] timeIntervalSinceNow]);
NSTimeInterval ti2 = fabs([[show2 objectForKey:#"startDate"] timeIntervalSinceNow]);
return (NSComparisonResult)(ti1-ti2);
}];
Then of course it is easy at that point to only take the 3 first shows of the sortedShows array.
If I've misunderstood your model structure, please edit your question to specify it, but I'm sure you can adapt my code to fit your model then
The question asks for the "fastest (memory wise)". Are you looking for the fastest or the most memory/footprint conscious? With algorithms there is often a space vs. time tradeoff so as you make it faster, you typically do it by adding indexes and other lookup data structures which increase the memory footprint.
For this problem the straight forward implementation would be to iterate through each channel and each item comparing each against the top 3 held in memory. But that could be slow.
With additional storage, you could have an additional array which indexes into time slots (one per 15 minutes granularity good enough?) and then daisy chain shows off of those time slots. Given the current time, you could index straight into the current times slot and then look up the next set of shows. The array would have pointers to the same objects that the dictionaries are pointing to. That's an additional data structure to optimize one specific pattern of access but it does it at a cost - more memory.
That would increase your foot print but would be very fast since it's just an array index offset.
Finally, you could store all your shows in a sqlite database or CoreData and solve your problem with one query. Let the sql engine do the hard work. that wold also keep your memory foot print reasonable.
Hope that sparks some ideas.
EDIT:
A crude example showing how you can construct a look table - an array with slots for every 15 minutes. It's instant to jump to the current time slot since it's just an array offset. Then you walk the absolute number of walks - the next three and you're out. So, it's an array offset with 3 iterations.
Most of the code is building date - the lookup table, finding the time slot and the loop is trivial.
NSInteger slotFromTime(NSDate *date)
{
NSLog(#"date: %#", date);
NSDateComponents *dateComponents = [[NSCalendar currentCalendar] components:(NSHourCalendarUnit | NSMinuteCalendarUnit) fromDate:date];
NSInteger hour = [dateComponents hour];
NSInteger minute = [dateComponents minute];
NSInteger slot = (hour * 60 + minute)/15;
NSLog(#"slot: %d", (int)slot);
return slot;
}
int main (int argc, const char * argv[])
{
// An array of arrays - the outer array is an index of 15 min time slots.
NSArray *slots[96];
NSDate *currentTime = [NSDate date];
NSInteger currentSlot = slotFromTime(currentTime);
// populate with shows into the next few slots for demo purpose
NSInteger index = currentSlot;
NSArray *shows1 = [NSArray arrayWithObjects:#"Seinfeld", #"Tonight Show", nil];
slots[++index] = shows1;
NSArray *shows2 = [NSArray arrayWithObjects:#"Friends", #"Jurassic Park", nil];
slots[++index] = shows2;
// find next three -jump directly to the current slot and only iterate till we find three.
// we don't have to iterate over the full data set of shows
NSMutableArray *nextShow = [[NSMutableArray alloc] init];
for (NSInteger currIndex = currentSlot; currIndex < 96; currIndex++)
{
NSArray *shows = slots[currIndex];
if (shows)
{
for (NSString *show in shows)
{
NSLog(#"found show: %#", show);
[nextShow addObject:show];
if ([nextShow count] == 3)
break;
}
}
if ([nextShow count] == 3)
break;
}
return 0;
}
This outputs:
2011-10-01 17:48:10.526 Craplet[946:707] date: 2011-10-01 21:48:10 +0000
2011-10-01 17:48:10.527 Craplet[946:707] slot: 71
2011-10-01 17:48:14.335 Craplet[946:707] found show: Seinfeld
2011-10-01 17:48:14.336 Craplet[946:707] found show: Tonight Show
2011-10-01 17:48:21.335 Craplet[946:707] found show: Friends

Resources