Beruflich Dokumente
Kultur Dokumente
AFNetworking2.0TutorialRayWenderlich
Update1/18/2014:FullyupdatedforiOS7andAFNetworking2.0
(originalpostbyScottSherwood,updatebyJoshuaGreene).
IniOS7,AppleintroducedNSURLSessionasthenew,preferred
methodofnetworking(asopposedtotheolderNSURLConnection
API).UsingthisrawNSURLSessionAPIisdefinitelyavalidwayto
writeyournetworkingcodeweevenhaveatutorialonthat.
However,theresanalternativetoconsiderusingthepopular
thirdpartynetworkinglibraryAFNetworking.
ThelatestversionofAFNetworking(2.0)isnowbuiltontopof
NSURLSession,soyougetallofthegreatfeaturesprovidedthere.
Butyoualsogetalotofextracoolfeatureslikeserialization,
reachabilitysupport,UIKitintegration(suchasahandycategory
onasynchronouslyloadingimagesinaUIImageView),andmore.
AFNetworkingisincrediblypopularitwonourReadersChoice
2012BestiOSLibraryAward.Itsalsooneofthemostwidelyused,
opensourceprojectswithover10,000stars,2,600forks,and160
contributorsonGithub.
LearnhowtouseAFNetworking:aneasy
tousenetworkAPIforiOS!
InthisAFNetworking2.0tutorial,youwilllearnaboutthemajor
componentsofAFNetworkingbybuildingaWeatherAppthatusesfeedsfromWorldWeatherOnline.Youllstartwith
staticweatherdata,butbytheendofthetutorial,theappwillbefullyconnectedtoliveweatherfeeds.
Todaysforecast:acooldeveloperlearnsallaboutAFNetworkingandgetsinspiredtouseitinhis/herapps.Letsget
busy!
Getting Started
FirstdownloadthestarterprojectforthisAFNetworking2.0tutorialhere.
ThisprojectprovidesabasicUItogetyoustartednoAFNetworkingcodehasbeenaddedyet.
OpenMainStoryboard.storyboard,andyouwillseethreeviewcontrollers:
http://www.raywenderlich.com/59255/afnetworking20tutorial
1/27
6/16/2015
AFNetworking2.0TutorialRayWenderlich
Fromlefttoright,theyare:
Atoplevelnavigationcontroller
Atableviewcontrollerthatwilldisplaytheweather,onerowperday
Acustomviewcontroller(WeatherAnimationViewController)thatwillshowtheweatherforasingledaywhenthe
usertapsonatableviewcell
Buildandruntheproject.YoullseetheUIappear,butnothingworksyet.Thatsbecausetheappneedstogetitsdata
fromthenetwork,butthiscodehasntbeenaddedyet.Thisiswhatyouwillbedoinginthistutorial!
ThefirstthingyouneedtodoisincludetheAFNetworkingframeworkinyourproject.Downloadthelatestversionfrom
GitHubbyclickingontheDownloadZiplink.
Whenyouunzipthefile,youwillseethatitincludesseveralsubfoldersanditems.Ofparticularinterest,itincludesa
subfoldercalledAFNetworkingandanothercalledUIKit+AFNetworkingasshownbelow:
http://www.raywenderlich.com/59255/afnetworking20tutorial
2/27
6/16/2015
AFNetworking2.0TutorialRayWenderlich
DragthesefoldersintoyourXcodeproject.
http://www.raywenderlich.com/59255/afnetworking20tutorial
3/27
6/16/2015
AFNetworking2.0TutorialRayWenderlich
Whenpresentedwithoptionsforaddingthefolders,makesurethatCopyitemsintodestinationgroupsfolder(if
needed)andCreategroupsforanyaddedfoldersarebothchecked.
Tocompletethesetup,opentheprecompiledheaderWeatherPrefix.pchfromtheSupportingFilessectionofthe
project.Addthislineaftertheotherimports:
#import "AFNetworking.h"
AddingAFNetworkingtotheprecompiledheadermeansthattheframeworkwillbeautomaticallyincludedinallthe
projectssourcefiles.
Prettyeasy,eh?Nowyourereadytoweatherthecode!
Operation JSON
AFNetworkingissmartenoughtoloadandprocessstructureddataoverthenetwork,aswellasplainoldHTTPrequests.
Inparticular,itsupportsJSON,XMLandPropertyLists(plists).
YoucoulddownloadsomeJSONandthenrunitthroughaparser(likethebuiltinNSJSONSerialization)yourself,but
whybother?AFNetworkingcandoitall!
http://www.raywenderlich.com/59255/afnetworking20tutorial
4/27
6/16/2015
AFNetworking2.0TutorialRayWenderlich
FirstyouneedthebaseURLofthetestscript.AddthistothetopofWTTableViewController.m,justunderneathallthe
#importlines.
static NSString * const BaseURLString =
@"http://www.raywenderlich.com/demos/weather_sample/";
ThisistheURLtoanincrediblysimplewebservicethatIcreatedforyouforthistutorial.Ifyourecuriouswhatitlooks
like,youcandownloadthesource.
ThewebservicereturnsweatherdatainthreedifferentformatsJSON,XML,andPLIST.Youcantakealookatthedata
itcanreturnbyusingtheseURLS:
http://www.raywenderlich.com/demos/weather_sample/weather.php?format=json
http://www.raywenderlich.com/demos/weather_sample/weather.php?format=xml
http://www.raywenderlich.com/demos/weather_sample/weather.php?format=plist(mightnotshowcorrectlyinyour
browser)
ThefirstdataformatyouwillbeusingisJSON.JSONisaverycommonJavaScriptderivedobjectformat.Itlooks
somethinglikethis:
{
"data": {
"current_condition": [
{
"cloudcover": "16",
"humidity": "59",
"observation_time": "09:09 PM",
}
]
}
}
Note:IfyoudliketolearnmoreaboutJSON,checkoutourWorkingwithJSONTutorial.
WhentheusertapstheJSONbutton,theappwillloadandprocessJSONdatafromtheserver.In
WTTableViewController.m,findthejsonTapped:method(itshouldbeempty)andreplaceitwiththefollowing:
- (IBAction)jsonTapped:(id)sender
{
// 1
http://www.raywenderlich.com/59255/afnetworking20tutorial
5/27
6/16/2015
AFNetworking2.0TutorialRayWenderlich
// 2
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc]
initWithRequest:request];
operation.responseSerializer = [AFJSONResponseSerializer serializer];
// 3
self.weather = (NSDictionary *)responseObject;
self.title = @"JSON Retrieved";
[self.tableView reloadData];
// 4
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Error Retrieving
Weather"
message:[error
localizedDescription]
delegate:nil
cancelButtonTitle:@"Ok"
otherButtonTitles:nil];
[alertView show];
}];
// 5
[operation start];
}
Awesome,thisisyourfirstAFNetworkingcode!Sincethisisallnew,Illexplainitonesectionatatime.
1. YoufirstcreateastringrepresentingthefullurlfromthebaseURLstring.ThisisthenusedtocreateanNSURL
object,whichisusedtomakeanNSURLRequest.
2. AFHTTPRequestOperationisanallinoneclassforhandlingHTTPtransfersacrossthenetwork.Youtellitthatthe
responseshouldbereadasJSONbysettingtheresponseSerializerpropertytothedefaultJSONserializer.
AFNetworkingwillthentakecareofparsingtheJSONforyou.
3. Thesuccessblockrunswhen(surprise!)therequestsucceeds.TheJSONserializerparsesthereceiveddataand
returnsadictionaryintheresponseObjectvariable,whichisstoredintheweatherproperty.
4. Thefailureblockrunsifsomethinggoeswrongsuchasifnetworkingisntavailable.Ifthishappens,yousimply
displayanalertwiththeerrormessage.
5. Youmustexplicitlytelltheoperationtostart(orelsenothingwillhappen).
Asyoucansee,AFNetworkingisextremelysimpletouse.Injustafewlinesofcode,youwereabletocreatea
networkingoperationthatbothdownloadsandparsesitsresponse.
Nowthattheweatherdataisstoredinself.weather,youneedtodisplayit.Findthe
tableView:numberOfRowsInSection:methodandreplaceitwiththefollowing:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if(!self.weather)
http://www.raywenderlich.com/59255/afnetworking20tutorial
6/27
6/16/2015
AFNetworking2.0TutorialRayWenderlich
return 0;
switch (section) {
case 0: {
return 1;
}
case 1: {
NSArray *upcomingWeather = [self.weather upcomingWeather];
return [upcomingWeather count];
}
default:
return 0;
}
}
Thetableviewwillhavetwosections:thefirsttodisplaythecurrentweatherandthesecondtodisplaytheupcoming
weather.
Waitaminute!,youmightbethinking.Whatisthis[self.weatherupcomingWeather]?Ifself.weatherisaplainold
NSDictionary,howdoesitknowwhatupcomingWeatheris?
Tomakeiteasiertodisplaythedata,IaddedacoupleofhelpercategoriesonNSDictionaryinthestarterproject:
NSDictionary+weather
NSDictionary+weather_package
Thesecategoriesaddsomehandymethodsthatmakeitalittleeasiertoaccessthedataelements.Youwanttofocuson
thenetworkingpartandnotonnavigatingNSDictionarykeys,right?
Note:FYI,analternativewaytomakeworkingwithJSONresultsabiteasierthanlookingupkeysindictionariesor
creatingspecialcategorieslikethisistouseathirdpartylibrarylikeJSONModel.
StillinWTTableViewController.m,findthetableView:cellForRowAtIndexPath:methodandreplaceitwiththefollowing
implementation:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath
*)indexPath
{
static NSString *CellIdentifier = @"WeatherCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier
forIndexPath:indexPath];
switch (indexPath.section) {
case 0: {
daysWeather = [self.weather currentCondition];
break;
}
case 1: {
NSArray *upcomingWeather = [self.weather upcomingWeather];
daysWeather = upcomingWeather[indexPath.row];
break;
}
default:
break;
http://www.raywenderlich.com/59255/afnetworking20tutorial
7/27
6/16/2015
AFNetworking2.0TutorialRayWenderlich
// You will add code here later to customize the cell, but it's good for now.
return cell;
}
LikethetableView:numberOfRowsInSection:method,thehandyNSDictionarycategoriesareusedtoeasilyaccessthe
data.Thecurrentdaysweatherisadictionary,andtheupcomingdaysarestoredinanarray.
BuildandrunyourprojecttapontheJSONbuttontogetthenetworkingrequestinmotionandyoushouldseethis:
JSONsuccess!
8/27
6/16/2015
AFNetworking2.0TutorialRayWenderlich
<dict>
<key>data</key>
<dict>
<key>current_condition</key>
<array>
<dict>
<key>cloudcover</key>
<string>16</string>
<key>humidity</key>
<string>59</string>
...
Theaboverepresents:
Adictionarywithasinglekeycalleddatathatcontainsanotherdictionary.
Thatdictionaryhasasinglekeycalledcurrent_conditionthatcontainsanarray.
Thatarraycontainsadictionarywithseveralkeysandvalues,likecloudcover=16andhumidity=59.
Itstimetoloadtheplistversionoftheweatherdata.FindtheplistTapped:methodandreplacetheempty
implementationwiththefollowing:
- (IBAction)plistTapped:(id)sender
{
NSString *string = [NSString stringWithFormat:@"%@weather.php?format=plist",
BaseURLString];
NSURL *url = [NSURL URLWithString:string];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[operation start];
}
NoticethatthiscodeisalmostidenticaltotheJSONversion,exceptforchangingtheresponseSerializertothedefault
AFPropertyListResponseSerializertoletAFNetworkingknowthatyouregoingtobeparsingaplist.
http://www.raywenderlich.com/59255/afnetworking20tutorial
9/27
6/16/2015
AFNetworking2.0TutorialRayWenderlich
Thatsprettyneat:yourappcanaccepteitherJSONorplistformatswithjustatinychangetothecode!
BuildandrunyourprojectandtrytappingonthePLISTbutton.Youshouldseesomethinglikethis:
TheClearbuttoninthetopnavigationbarwillclearthetitleandtableviewdatasoyoucanreseteverythingtomake
suretherequestsaregoingthrough.
Operation XML
WhileAFNetworkinghandlesJSONandplistparsingforyou,workingwithXMLisalittlemorecomplicated.Thistime,its
yourjobtoconstructtheweatherdictionaryfromtheXMLfeed.
Fortunately,iOSprovidessomehelpviatheNSXMLParserclass(whichisaSAXparser,ifyouwanttoreaduponit).
StillinWTTableViewController.m,findthexmlTapped:methodandreplaceitsimplementationwiththefollowing:
- (IBAction)xmlTapped:(id)sender
{
NSString *string = [NSString stringWithFormat:@"%@weather.php?format=xml",
BaseURLString];
NSURL *url = [NSURL URLWithString:string];
http://www.raywenderlich.com/59255/afnetworking20tutorial
10/27
6/16/2015
AFNetworking2.0TutorialRayWenderlich
// Leave these commented for now (you first need to add the delegate methods)
// XMLParser.delegate = self;
// [XMLParser parse];
}];
[operation start];
}
Thisshouldlookprettyfamiliarbynow.Thebiggestchangeisthatinthesuccessblockyoudontgetanice,
preprocessedNSDictionaryobjectpassedtoyou.Instead,responseObjectisaninstanceofNSXMLParser,whichyou
willusetodotheheavyliftinginparsingtheXML.
YoullneedtoimplementasetofdelegatemethodsforNXMLParsertobeabletoparsetheXML.Noticethat
XMLParsersdelegateissettoself,soyouwillneedtoaddNSXMLParsersdelegatemethodsto
WTTableViewControllertohandletheparsing.
First,updateWTTableViewController.handchangetheclassdeclarationatthetopasfollows:
@interface WTTableViewController : UITableViewController<NSXMLParserDelegate>
ThismeanstheclasswillimplementtheNSXMLParserDelegateprotocol.Youwillimplementthesemethodssoon,but
firstyouneedtoaddafewproperties.
AddthefollowingpropertiestoWTTableViewController.mwithintheclassextension,rightafter@interface
WTTableViewController():
@property(nonatomic,
being parsed
@property(nonatomic,
xml response
@property(nonatomic,
@property(nonatomic,
// current section
// completed parsed
ThesepropertieswillcomeinhandywhenyoureparsingtheXML.
http://www.raywenderlich.com/59255/afnetworking20tutorial
11/27
6/16/2015
AFNetworking2.0TutorialRayWenderlich
NowpastethismethodinWTTableViewController.m,rightbefore@end:
- (void)parserDidStartDocument:(NSXMLParser *)parser
{
self.xmlWeather = [NSMutableDictionary dictionary];
}
Theparsercallsthismethodwhenitfirststartsparsing.Whenthishappens,yousetself.xmlWeathertoanew
dictionary,whichwillholdholdtheXMLdata.
Nextpastethismethodrightafterthispreviousone:
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:
(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary
*)attributeDict
{
self.elementName = qName;
if([qName isEqualToString:@"current_condition"] ||
[qName isEqualToString:@"weather"] ||
[qName isEqualToString:@"request"]) {
self.currentDictionary = [NSMutableDictionary dictionary];
}
12/27
6/16/2015
AFNetworking2.0TutorialRayWenderlich
self.currentDictionary = nil;
}
// 3
else if ([qName isEqualToString:@"value"]) {
// Ignore value tags, they only appear in the two conditions below
}
// 4
else if ([qName isEqualToString:@"weatherDesc"] ||
[qName isEqualToString:@"weatherIconUrl"]) {
NSDictionary *dictionary = @{@"value": self.outstring};
NSArray *array = @[dictionary];
self.currentDictionary[qName] = array;
}
// 5
else if (qName) {
self.currentDictionary[qName] = self.outstring;
}
self.elementName = nil;
}
Thismethodiscalledwhenanendelementtagisencountered.Whenthathappens,youcheckforafewspecialtags:
1. Thecurrent_conditionelementindicatesyouhavetheweatherforthecurrentday.Youaddthisdirectlytothe
xmlWeatherdictionary.
2. Theweatherelementmeansyouhavetheweatherforasubsequentday.Whilethereisonlyonecurrentday,
theremaybeseveralsubsequentdays,soyouaddthisweatherinformationtoanarray.
3. Thevaluetagonlyappearsinsideothertags,soitssafetoskipoverit.
4. TheweatherDescandweatherIconUrlelementvaluesneedtobeboxedinsideanarraybeforetheycanbe
stored.Thisway,theywillmatchhowtheJSONandplistversionsofthedataarestructuredexactly.
5. Allotherelementscanbestoredasis.
Nowforthefinaldelegatemethod!Pastethismethodjustafterthepreviousone:
- (void) parserDidEndDocument:(NSXMLParser *)parser
{
self.weather = @{@"data": self.xmlWeather};
self.title = @"XML Retrieved";
[self.tableView reloadData];
}
Theparsercallsthismethodwhenitreachestheendofthedocument.Atthispoint,thexmlWeatherdictionarythat
youvebeenbuildingiscomplete,sothetableviewcanbereloaded.
WrappingxmlWeatherinsideanotherNSDictionarymightseemredundant,butthisensurestheformatmatchesup
exactlywiththeJSONandplistversions.Thisway,allthreedataformatscanbedisplayedwiththesamecode!
http://www.raywenderlich.com/59255/afnetworking20tutorial
13/27
6/16/2015
AFNetworking2.0TutorialRayWenderlich
Nowthatthedelegatemethodsandpropertiesareinplace,returntothexmlTapped:methodanduncommentthelines
ofcodefrombefore:
- (IBAction)xmlTapped:(id)sender
{
...
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id
responseObject) {
http://www.raywenderlich.com/59255/afnetworking20tutorial
14/27
6/16/2015
AFNetworking2.0TutorialRayWenderlich
http://www.raywenderlich.com/59255/afnetworking20tutorial
15/27
6/16/2015
AFNetworking2.0TutorialRayWenderlich
[cell.imageView setImageWithURLRequest:request
placeholderImage:placeholderImage
success:^(NSURLRequest *request, NSHTTPURLResponse
*response, UIImage *image) {
weakCell.imageView.image = image;
[weakCell setNeedsLayout];
} failure:nil];
UIImageView+AFNetworkingmakessetImageWithURLRequest:andseveralotherrelatedmethodsavailabletoyou.
Boththesuccessandfailureblocksareoptional,butifyoudoprovideasuccessblock,youmustexplicitlysettheimage
propertyontheimageview(orelseitwontbeset).Ifyoudontprovideasuccessblock,theimagewillautomaticallybe
setforyou.
Whenthecellisfirstcreated,itsimageviewwilldisplaytheplaceholderimageuntiltherealimagehasfinished
downloading.
Nowbuildandrunyourproject.Taponanyoftheoperationsyouveaddedsofar,andyoushouldseethis:
http://www.raywenderlich.com/59255/afnetworking20tutorial
16/27
6/16/2015
AFNetworking2.0TutorialRayWenderlich
Nice!Asynchronouslyloadingimageshasneverbeeneasier.
A RESTful Class
SofaryouvebeencreatingoneoffnetworkingoperationsusingAFHTTPRequestOperation.
Alternatively,AFHTTPRequestOperationManagerandAFHTTPSessionManageraredesignedtohelpyoueasily
interactwithasingle,webserviceendpoint.
BothoftheseallowyoutosetabaseURLandthenmakeseveralrequeststothesameendpoint.Bothcanalsomonitor
forchangesinconnectivity,encodeparameters,handlemultipartformrequests,enqueuebatchoperations,andhelp
youperformthefullsuiteofRESTfulverbs(GET,POST,PUT,andDELETE).
WhichoneshouldIuse?,youmightask.
IfyouretargetingiOS7andabove,useAFHTTPSessionManager,asinternallyitcreatesanduses
NSURLSessionandrelatedobjects.
IfyouretargetingiOS6andabove,useAFHTTPRequestOperationManager,whichhassimilarfunctionalityto
AFHTTPSessionManager,yetitusesNSURLConnectioninternallyinsteadofNSURLSession(whichisnt
availableiniOS6).Otherwise,theseclassesareverysimilarinfunctionality.
Inyourweatherappproject,youllbeusingAFHTTPSessionManagertoperformbothaGETandPUToperation.
Note:UnclearonwhatallthistalkisaboutREST,GET,andPOST?Checkoutthisexplanationofthesubject
WhatisREST?
UpdatetheclassdeclarationatthetopofWTTableViewController.htothefollowing:
@interface WTTableViewController : UITableViewController<NSXMLParserDelegate,
CLLocationManagerDelegate, UIActionSheetDelegate>
InWTTableViewController.m,findtheclientTapped:methodandreplaceitsimplementationwiththefollowing:
- (IBAction)clientTapped:(id)sender
{
UIActionSheet *actionSheet = [[UIActionSheet alloc]
initWithTitle:@"AFHTTPSessionManager"
delegate:self
cancelButtonTitle:@"Cancel"
destructiveButtonTitle:nil
otherButtonTitles:@"HTTP GET", @"HTTP
POST", nil];
[actionSheet showFromBarButtonItem:sender animated:YES];
}
ThismethodcreatesanddisplaysanactionsheetaskingtheusertochoosebetweenaGETandPOSTrequest.Addthe
followingmethodattheendoftheclassimplementation(rightbefore@end)toimplementtheactionsheetdelegate
method:
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:
(NSInteger)buttonIndex
{
if (buttonIndex == [actionSheet cancelButtonIndex]) {
// User pressed cancel -- abort
return;
http://www.raywenderlich.com/59255/afnetworking20tutorial
17/27
6/16/2015
AFNetworking2.0TutorialRayWenderlich
// 1
NSURL *baseURL = [NSURL URLWithString:BaseURLString];
NSDictionary *parameters = @{@"format": @"json"};
// 2
AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc]
initWithBaseURL:baseURL];
manager.responseSerializer = [AFJSONResponseSerializer serializer];
// 3
if (buttonIndex == 0) {
[manager GET:@"weather.php" parameters:parameters success:^(NSURLSessionDataTask
*task, id responseObject) {
self.weather = responseObject;
self.title = @"HTTP GET";
[self.tableView reloadData];
} failure:^(NSURLSessionDataTask *task, NSError *error) {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Error Retrieving
Weather"
message:[error
localizedDescription]
delegate:nil
cancelButtonTitle:@"Ok"
otherButtonTitles:nil];
[alertView show];
}];
}
// 4
else if (buttonIndex == 1) {
[manager POST:@"weather.php" parameters:parameters success:^(NSURLSessionDataTask
*task, id responseObject) {
self.weather = responseObject;
self.title = @"HTTP POST";
[self.tableView reloadData];
} failure:^(NSURLSessionDataTask *task, NSError *error) {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Error Retrieving
Weather"
message:[error
localizedDescription]
delegate:nil
cancelButtonTitle:@"Ok"
otherButtonTitles:nil];
[alertView show];
}];
}
}
Hereswhatshappeningabove:
1. YoufirstsetupthebaseURLandthedictionaryofparameters.
2. YouthencreateaninstanceofAFHTTPSessionManagerandsetitsresponseSerializertothedefaultJSON
serializer,similartothepreviousJSONexample.
3. IftheuserpressesthebuttonindexforHTTPGET,youcalltheGETmethodonthemanager,passinginthe
parametersandusualpairofsuccessandfailureblocks.
4. YoudothesamewiththePOSTversion.
http://www.raywenderlich.com/59255/afnetworking20tutorial
18/27
6/16/2015
AFNetworking2.0TutorialRayWenderlich
InthisexampleyourerequestingJSONresponses,butyoucaneasilyrequesteitheroftheothertwoformatsas
discussedpreviously.
Buildandrunyourproject,tapontheClientbuttonandthentaponeithertheHTTPGETorHTTPPOSTbuttontoinitiate
theassociatedrequest.Youshouldseethesescreens:
Atthispoint,youknowthebasicsofusingAFHTTPSessionManager,buttheresanevenbetterwaytouseitthatwill
resultincleanercode,whichyoulllearnaboutnext.
19/27
6/16/2015
AFNetworking2.0TutorialRayWenderlich
1. Createasubclassforeachwebservice.Forexample,ifyourewritingasocialnetworkaggregator,youmightwant
onesubclassforTwitter,oneforFacebook,anotherforInstragramandsoon.
2. IneachAFHTTPSessionManagersubclass,createaclassmethodthatreturnsasharedsingletoninstance.This
savesresourcesandeliminatestheneedtoallocateandspinupnewobjects.
YourprojectcurrentlydoesnthaveasubclassofAFHTTPSessionManageritjustcreatesonedirectly.Letsfixthat.
Tobegin,createanewfileinyourprojectoftypeiOS\CocoaTouch\ObjectiveCClass.CallitWeatherHTTPClientand
makeitasubclassofAFHTTPSessionManager.
Youwanttheclasstodothreethings:performHTTPrequests,callbacktoadelegatewhenthenewweatherdatais
available,andusetheusersphysicallocationtogetaccurateweather.
ReplacethecontentsofWeatherHTTPClient.hwiththefollowing:
#import "AFHTTPSessionManager.h"
@protocol WeatherHTTPClientDelegate;
+ (WeatherHTTPClient *)sharedWeatherHTTPClient;
- (instancetype)initWithBaseURL:(NSURL *)url;
- (void)updateWeatherAtLocation:(CLLocation *)location forNumberOfDays:(NSUInteger)number;
@end
return _sharedWeatherHTTPClient;
}
- (instancetype)initWithBaseURL:(NSURL *)url
http://www.raywenderlich.com/59255/afnetworking20tutorial
20/27
6/16/2015
AFNetworking2.0TutorialRayWenderlich
{
self = [super initWithBaseURL:url];
if (self) {
self.responseSerializer = [AFJSONResponseSerializer serializer];
self.requestSerializer = [AFJSONRequestSerializer serializer];
}
return self;
}
ThesharedWeatherHTTPClientmethodusesGrandCentralDispatchtoensurethesharedsingletonobjectisonly
allocatedonce.YouinitializetheobjectwithabaseURLandsetituptorequestandexpectJSONresponsesfromthe
webservice.
Pastethefollowingmethodunderneaththepreviousones:
- (void)updateWeatherAtLocation:(CLLocation *)location forNumberOfDays:(NSUInteger)number
{
NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
parameters[@"num_of_days"] = @(number);
parameters[@"q"] = [NSString
stringWithFormat:@"%f,%f",location.coordinate.latitude,location.coordinate.longitude];
parameters[@"format"] = @"json";
parameters[@"key"] = WorldWeatherOnlineAPIKey;
21/27
6/16/2015
AFNetworking2.0TutorialRayWenderlich
InWTTableViewController.m,addthefollowinglinestothebottomofviewDidLoad::
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
TheselinesinitializetheCoreLocationmanagertodeterminetheuserslocationwhentheviewloads.TheCore
Locationmanagerthenreportsthatlocationviaadelegatecallback.Addthefollowingmethodtotheimplementation:
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray
*)locations
{
// Last object contains the most recent location
CLLocation *newLocation = [locations lastObject];
[self.locationManager stopUpdatingLocation];
22/27
6/16/2015
AFNetworking2.0TutorialRayWenderlich
theWeatherHTTPClientrequest,andyoushouldseesomethinglikethis:
Hereshopingyourupcomingweatherisassunnyasmine!
http://www.raywenderlich.com/59255/afnetworking20tutorial
23/27
6/16/2015
AFNetworking2.0TutorialRayWenderlich
Luckily,AFNetworkingcomeswithaneasywaytoprovidethisfeedback:AFNetworkActivityIndicatorManager.
InWTAppDelegate.m,addthisimportjustbelowtheother:
#import "AFNetworkActivityIndicatorManager.h"
Thenfindtheapplication:didFinishLaunchingWithOptions:methodandreplaceitwiththefollowing:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:
(NSDictionary *)launchOptions
{
[AFNetworkActivityIndicatorManager sharedManager].enabled = YES;
return YES;
}
EnablingthesharedManagerautomaticallydisplaysthenetworkactivityindicatorwheneveranewoperationis
underway.Youwontneedtomanageitseparatelyforeveryrequestyoumake.
Buildandrun,andyoushouldseethelittlenetworkingspinnerinthestatusbarwhenevertheresanetworkrequest:
Nowtheresasignoflifeforyouruserevenwhenyourappiswaitingonaslowwebservice.
Downloading Images
Ifyoutaponatableviewcell,theapptakesyoutoadetailviewoftheweatherandananimationillustratingthe
correspondingweatherconditions.
Thatsnice,butatthemomenttheanimationhasaveryplainbackground.Whatbetterwaytoupdatethebackground
thanoverthenetwork!
HeresthefinalAFNetworkingtrickforthistutorial:AFHTTPRequestOperationcanalsohandleimagerequestsbysetting
itsresponseSerializertoaninstanceofAFImageResponseSerializer.
TherearetwomethodstubsinWeatherAnimationViewController.mtoimplement.FindtheupdateBackgroundImage:
methodandreplaceitwiththefollowing:
- (IBAction)updateBackgroundImage:(id)sender
http://www.raywenderlich.com/59255/afnetworking20tutorial
24/27
6/16/2015
AFNetworking2.0TutorialRayWenderlich
{
NSURL *url = [NSURL URLWithString:@"http://www.raywenderlich.com/wpcontent/uploads/2014/01/sunny-background.png"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
self.backgroundImageView.image = responseObject;
[self saveImage:responseObject withFilename:@"background.png"];
[operation start];
}
Thismethodinitiatesandhandlesdownloadingthenewbackground.Oncompletion,itreturnsthefullimagerequested.
InWeatherAnimationViewController.m,youwillseetwohelpermethods,imageWithFilename:and
saveImage:withFilename:,whichwillletyoustoreandloadanyimageyoudownload.updateBackgroundImage:calls
thesehelpermethodstosavethedownloadedimagestodisk.
FindthedeleteBackgroundImage:methodandreplaceitwiththefollowing:
- (IBAction)deleteBackgroundImage:(id)sender
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
NSString *path = [[paths objectAtIndex:0]
stringByAppendingPathComponent:@"WeatherHTTPClientImages/"];
http://www.raywenderlich.com/59255/afnetworking20tutorial
25/27
6/16/2015
AFNetworking2.0TutorialRayWenderlich
http://www.raywenderlich.com/59255/afnetworking20tutorial
26/27
6/16/2015
AFNetworking2.0TutorialRayWenderlich
JoshuaGreene
JoshuaGreeneisasenioriOSdeveloperatCitrix.Whenhe'snotslingingcode,he
enjoysmartialarts,Netflix,andspendingtimewithhiswonderfulwifeanddaughter.
YoucanreachhimbyemailoronTwitter.
http://www.raywenderlich.com/59255/afnetworking20tutorial
27/27