Load Random APi Content - ios

How do I change this function to load content randomly from the API? I want to pass in a random integer and change the end point of the url.
NSString* WebServiceURL =#"http://movie-quotes.herokuapp.com/api/v1/quotes";
to this
http://movie-quotes.herokuapp.com/api/v1/quotes/2
where the number at the end is the quote number
Here is my relevant code:
-(void)LoadQuotesRandom
{
randomQuotes = nil;
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
// Load the JSON string from our web serivce (in a background thread)
NSDictionary * dictionary = [JSONHelper loadJSONDataFromURL:WebServiceURL];
dispatch_async(dispatch_get_main_queue(), ^{
randomQuotes = [NSMutableArray array];
// Iterate through the array of Customer records in the dictionary
for (NSDictionary * oneQuote in dictionary)
{
Quotes* newQuotes =[[Quotes alloc] init];
// Add our new Customer record to our NSMutableArray
newQuotes.Quote = [oneQuote objectForKey:#"content"];
newQuotes.FilmName =[oneQuote objectForKey:#"film"];
[randomQuotes addObject:newQuotes];
}
});
});
}

To restate more simply, I think you want a url string with a random integer suffix.
NSInteger randomInt = arc4random_uniform(SOME_MAX);
NSString *baseUrl = #"http://movie-quotes.herokuapp.com/api/v1/quotes";
NSString *webServiceUrl = [NSString stringWithFormat:#"%#/%ld", baseUrl, randomInt];
You'll need to #define SOME_MAX for the largest quote index one can request.
I suggest you separate this completely for the code that makes the request. Get one piece working that does any request given a string describing the url, and a separate piece that generates these url strings.

Related

how to use dispatch_apply to replace nested for loop of GCD to get maximum concurrent performance

I have a nested for loop. I want to optimise it using GCD concurrency. Tried:
Replace both for loop with gcd_apply.
Replaced only inner for loop with gcd_apply.
I want to get final out put same without change in order.
-(NSMutableArray*)getsportNotificationObjectsByGroup{
NSMutableArray* notificationObjects = [NSMutableArray array];
NSString* defaultNoteValue;
defaultNoteValue = [WADeviceAndAppSettingPopUpManager getDefaultNoteValueBasedOnSystemAlertButtonAction];
for(WACategoryInfo * categoryInfo in self.allSportSCategories){
#autoreleasepool {
NSMutableArray *subArray = [[NSMutableArray alloc] init];;
for (NSDictionary *dictNotificationTags in categoryInfo.notificationTags) {
NSString *tagName, *tagCode;
BOOL isTagDefaultEnabled = NO;
tagName = [dictNotificationTags objectForKeyWithNullCheck:ktagName];
tagCode = [dictNotificationTags objectForKeyWithNullCheck:ktagCode];
isTagDefaultEnabled = [[dictNotificationTags objectForKeyWithNullCheck:kisTagDefaultEnabled] boolValue];
//********value computation*******//
NSString* val = #"";
if ([WAConfigLoader sharedInstance].isCollegeStyleApp) {
val = [WADeviceAndAppSettingPopUpManager getValueForSwitch:dictNotificationTags];
}
//*****value computation*********//
NSDictionary *sportDetail = #{
kname:tagName,
ktype:kswitch,
kid:tagCode,
kvalue : val,
ksportStringId:categoryInfo.sportStringID,
kTitleKey : tagName
};
[subArray addObject:sportDetail];
}
NSMutableDictionary *aNewDict = [[NSMutableDictionary alloc] init];
[aNewDict setObject:subArray forKey:kdata];
[aNewDict setObject:categoryInfo.sportTitle forKey:ksection];
[notificationObjects addObject:aNewDict];
}
}
return notificationObjects;
}
It's not mandatory to use GCD only, my concern is to maximise loop performance.
If you replace the inner loop with dispatch_apply, you have to take concern of these drawbacks:
You have to sync the call to [subArray addObject]
The order in subArray is indetermined
Therefore, I would recomment to only put the outer loop in a dispatch_apply work item, because it's results are added to a dictionary which does not provide any order. Nevertheless, you'd have to sync [notificationObjects addObject] anyway.
Just remember to dispatch_apply into a concurrent queue.

Retrieve YouTube channel videos by channel name

I am looking for two API calls in Youtube Data API V3.
First I want to get the Channel ID by specifying the name of the channel.
Once I have the Channel ID I want to get n number of videos from that channel.
I am looking for the API calls that I have to make.
Also, does anyone know if there's a chance that channel or video IDs may change at some point? If they can change for the same video/channel then I should not hardcode the ID's in my code.
Thanks
For total newbies who want a running example : consider a function that will help understand the entire cycle of fetch,parse,display etc and bring youtube channel's videos to your tableview specifically. im not writing the tableview part here
-(void)initiateRequestToYoutubeApiAndGetChannelInfo
{
NSString * urlYouCanUseAsSample = #"https://www.googleapis.com/youtube/v3/search?key={YOUR_API_KEY_WITHOUT_CURLY_BRACES}&channelId={CHANNEL_ID_YOU_CAN_GET_FROM_ADDRESS_BAR_WITHOUT_CURLY_BRACES}&part=snippet,id&order=date&maxResults=20";
NSURL *url = [[NSURL alloc] initWithString: urlYouCanUseAsSample];
// Create your request
NSURLRequest *request = [NSURLRequest requestWithURL:url];
// Send the request asynchronously remember to reload tableview on global thread
[NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
// Callback, parse the data and check for errors
if (data && !connectionError) {
NSError *jsonError;
NSDictionary *jsonResult = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&jsonError];
if (!jsonError) {
// better put a breakpoint here to see what is the result and how it is brought to you. Channel id name etc info should be there
NSLog(#"%#",jsonResult);
/// separating "items" dictionary and making array
//
id keyValuePairDict = jsonResult;
NSMutableArray * itemList = keyValuePairDict[#"items"];
for (int i = 0; i< itemList.count; i++) {
/// separating VIDEO ID dictionary from items dictionary and string video id
id v_id0 = itemList[i];
NSDictionary * vid_id = v_id0[#"id"];
id v_id = vid_id;
NSString * video_ID = v_id[#"videoId"];
//you can fill your local array for video ids at this point
// [video_IDS addObject:video_ID];
/// separating snippet dictionary from itemlist array
id snippet = itemList[i];
NSDictionary * snip = snippet[#"snippet"];
/// separating TITLE and DESCRIPTION from snippet dictionary
id title = snip;
NSString * title_For_Video = title[#"title"];
NSString * desc_For_Video = title[#"description"];
//you can fill your local array for titles & desc at this point
// [video_titles addObject:title_For_Video];
// [video_description addObject:desc_For_Video];
/// separating thumbnail dictionary from snippet dictionary
id tnail = snip;
NSDictionary * thumbnail_ = tnail[#"thumbnails"];
/// separating highresolution url dictionary from thumbnail dictionary
id highRes = thumbnail_;
NSDictionary * high_res = highRes[#"high"];
/// separating HIGH RES THUMBNAIL IMG URL from high res dictionary
id url_for_tnail = high_res;
NSString * thumbnail_url = url_for_tnail[#"url"];
//you can fill your local array for titles & desc at this point
[video_thumbnail_url addObject:thumbnail_url];
}
// reload your tableview on main thread
//[self.tableView performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:NO];
performSelectorOnMainThread:#selector(reloadInputViews) withObject:nil waitUntilDone:NO];
// you can log all local arrays for convenience
// NSLog(#"%#",video_IDS);
// NSLog(#"%#",video_titles);
// NSLog(#"%#",video_description);
// NSLog(#"%#",video_thumbnail_url);
}
else
{
NSLog(#"an error occurred");
}
}
}];
}
First call is a search.list with setting q as channel name and type="channel".
Second one is calling channels.list with that id and get the playlistId of the uploaded videos list.
Third is the playlistItems.list to list videos under that playlist.

NSDictionary constant looping

SO I have a program which calls the FlickR API, gets the URL's puts them into a dictionary and then assigns them into a table view, using an image view.
NSArray *photos = [self.flickr photosForUser:#"James Kinvig"];
int countAttempts = 0;
[[self.flickr photosForUser:#"James Kinvig"]count];
for (int i = 0; i < [[self.flickr photosForUser:#"James Kinvig"]count]; i++) {
for(NSDictionary *dictionary in photos) {
countAttempts++;
NSString *farmId = [dictionary objectForKey:#"farm"];
NSString *serverId = [dictionary objectForKey:#"server"];
NSString *photoId = [dictionary objectForKey:#"id"];
NSString *secret = [dictionary objectForKey:#"secret"];
self.url= [NSURL URLWithString:[NSString stringWithFormat:#"http://farm%#.staticflickr.com/%#/%#_%#.jpg", farmId, serverId, photoId, secret]];
//NSLog(#"self.url = %#", self.url);
NSLog(#"count = %d", countAttempts);
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^{
NSData *imgData = [NSData dataWithContentsOfURL:self.url];
dispatch_sync(dispatch_get_main_queue(), ^{
UIImage *img = [UIImage imageWithData:imgData];
cell.imageView.image = img;
[cell setNeedsLayout];
});
});
}
}
return cell;
}
This is the method it calls, photosForUser:
- (NSMutableArray *) photosForUser: (NSString *) friendUserName
{
NSString *request = [NSString stringWithFormat: #"https://api.flickr.com/services/rest/?method=flickr.people.findByUsername&username=%#", friendUserName];
NSDictionary *result = [self fetch: request];
NSString *nsid = [result valueForKeyPath: #"user.nsid"];
request = [NSString stringWithFormat: #"https://api.flickr.com/services/rest/?method=flickr.photos.search&per_page=%ld&has_geo=1&user_id=%#&extras=original_format,tags,description,geo,date_upload,owner_name,place_url", (long) self.maximumResults, nsid];
result = [self fetch: request];
return [result valueForKeyPath: #"photos.photo"];
}
Which does a fetch to the flickr API.
What is happening though is that is stuck in an eternal loop. Even with the for statement being less than the count, it still eternal loops. I have NSLog'd the count of the FlickR photos and it = 11.
This may have something to do with it, but whenever I press the button to take me to the table view controller, I get a HUGE lag, close to a minute, and nothing is being calculated (photo-wise) as I've done a count++
Thanks
let me understand this.. By the last line of your first block of code, I conclude that that is the uitableview dataSource method, cellForRowAtIndexPath.. what doesn't really makes sense.. you you have a fetch there, you have A loop inside a loop, that is setting many images (by download them) in one single imageView, and this is happening for all your visible cells at the same time. This will never work!
The solution is:
1 - remove this method from the cellForRow, this is not the place to request the images
2 - create another method that will fetch the content
3 - create a method that will do your loops and store the images on the array so you don't need to do that many times, only one..
4 - reload the tableview after you finish the step 3
5 - use the array of images that is already done to set your images by indexPath.row in your cell..
6 - I recommend you to use a Library for imageCache (i.e https://github.com/rs/SDWebImage)
NSArray *photos = [self.flickr photosForUser:#"James Kinvig"];
for (int i = 0; i < [[self.flickr photosForUser:#"James Kinvig"] count]; i++)
{
for (NSDictionary *dictionary in photos)
{
You have two nested loops iterating over the same collection. This turns what should be an O(n) operation into O(n^2) and explains why your process is taking a very long time.
Since the loop bodies never use i, I would fix it by getting rid of the outer loop:
NSArray *photos = [self.flickr photosForUser:#"James Kinvig"];
for (NSDictionary *dictionary in photos)
{

How do i loop an nsobject once saved to

I am using an NSMutableArray to store items in a list form from a web service. How do I read the data out of my array to display a random quote.
As i am trying to avoid hitting the webservice twice or am i over complicating it?
NSInteger randomInt = arc4random_uniform(3);
NSString *baseUrl = #"http://movie-quotes.herokuapp.com/api/v1/quotes";
NSString *webServiceUrl= [NSString stringWithFormat:#"%#/%ld", baseUrl,(long)randomInt];
randomQuotes = nil;
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
// Load the JSON string from our web serivce (in a background thread)
NSDictionary * dictionary = [JSONHelper loadJSONDataFromURL:webServiceUrl];
dispatch_async(dispatch_get_main_queue(), ^{
randomQuotes = [NSMutableArray array];
// Iterate through the array of quotes records in the dictionary
for (NSDictionary * oneQuote in dictionary)
{
Quotes* newQuotes =[[Quotes alloc] init];
// Add our new Customer record to our NSMutableArray
newQuotes.Quote = [oneQuote objectForKey:#"content"];
newQuotes.FilmName = [oneQuote objectForKey:#"film"];
[randomQuotes addObject:newQuotes];
}
});
});
You can get a random object out of an array like this.
NSUInteger randomIndex = arc4random_uniform(theArray.count);
[theArray objectAtIndex: randomIndex];
As long as you keep the array of quotes around, you won't need to hit the web service again.

Display all JSON data from NSDictionary to UITableview

I am fairly new to iOS development, been at it for 2 years or so. I have developed an app for my Litecoin mining pool that is able to pull data from the API url in JSON format. I am able to get individual variables from JSON, but I want to display all of the data from the "workers" block into a UITableView. Here is an example of the JSON:
{"username":"n00bminer","balance":"0","total_hashrate":"1429","payout_history":"0.71828344","round_shares":"96908","workers":
{
"n00bminer.1":{"hashrate":"998","last_share_timestamp":"1392906308","accepted_shares":"84755","stale_shares":"913"},
"n00bminer.cpu":
{"hashrate":"0","accepted_shares":"7891","stale_shares":"11"},
"n00bminer.2":{"hashrate":"431","last_share_timestamp":"1392906300","accepted_shares":"13285","stale_shares":"118"}
}}
(bolded is the part that I need) Live data: http://www.ielitepool.com/api.php?api_key=9d9be4bd59eb8de59f1cac981099c43e866b0cc07a5555dd922c9efc08ac31a1
I request this using:
NSData* apiData = [NSData dataWithContentsOfURL:
[NSURL URLWithString:[[NSUserDefaults standardUserDefaults] valueForKey:#"api_url"]]
];
NSDictionary* json = nil;
if (apiData) {
json = [NSJSONSerialization
JSONObjectWithData:apiData
options:kNilOptions
error:nil];
}
and get individual variables using:
float total_hashrate = [[json valueForKey:#"total_hashrate"] floatValue];
How can I get all of the workers, as well as their stats in one UITableView. For example, I don't want the worker name to only display, then have it lead to another UITableViewController, but rather the name and then the stats underneath (hashrate, accepted_shares, etc.)
Following code will print worker's information:
[json[#"workers"] enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSDictionary *obj, BOOL *stop) {
NSLog(#"worker = %# : hashrate = %f last_share_timestamp = %f",
key, [obj[#"hashrate"] floatValue], [obj[#"last_share_timestamp"] floatValue] );
}];
If you will have troubles displaying info in table, please create separate question with code sample.

Resources