objc.io

înainte de iOS 7, dezvoltatorii erau destul de limitați în ceea ce puteau face atunci când aplicațiile lor au părăsit prim-planul. În afară de VOIP și caracteristici bazate pe locație, singura modalitate de a executa cod în fundal a fost de a utiliza sarcini de fundal, limitată la rularea pentru câteva minute. Dacă doriți să descărcați un videoclip mare pentru vizualizare offline sau să faceți o copie de rezervă a fotografiilor unui utilizator pe serverul dvs., puteți finaliza doar o parte din lucrare.

iOS 7 adaugă două API-uri noi pentru actualizarea interfeței UI și a conținutului aplicației în fundal. Primul, background Fetch, vă permite să preluați conținut nou din rețea la intervale regulate. A doua, notificări la distanță, este o caracteristică nouă care utilizează notificările Push pentru a notifica o aplicație atunci când a avut loc un eveniment. Ambele mecanisme noi vă ajută să mențineți actualizată interfața aplicației și puteți programa lucrul la noul serviciu de transfer de fundal, care vă permite să efectuați transferuri de rețea în afara procesului (descărcări și încărcări).

background Fetch și notificările de la distanță sunt simple cârlige de Delegare a aplicațiilor cu 30 de secunde de timp de ceas de perete pentru a efectua lucrări înainte ca aplicația dvs. să fie suspendată. Nu sunt destinate lucrului intensiv al procesorului sau sarcinilor de lungă durată, ci sunt pentru a face coadă la solicitări de rețea de lungă durată, cum ar fi o descărcare mare de filme sau efectuarea de actualizări rapide de conținut.

din perspectiva unui utilizator, singura schimbare evidentă a multitasking-ului este noul App switcher, care afișează un instantaneu al interfeței de utilizare a fiecărei aplicații așa cum a fost atunci când a părăsit prim-planul. Dar există un motiv pentru afișarea instantaneelor – acum Puteți actualiza instantaneul aplicației după ce finalizați lucrările de fundal, afișând o previzualizare a conținutului nou. Aplicațiile de rețele sociale, știri sau vreme pot afișa acum cel mai recent conținut fără ca utilizatorul să fie nevoit să deschidă aplicația. Vom vedea cum să actualizăm instantaneul mai târziu.

background Fetch

background Fetch este un fel de mecanism inteligent de votare care funcționează cel mai bine pentru aplicațiile care au actualizări frecvente de conținut, cum ar fi rețelele sociale, știrile sau aplicațiile meteo. Sistemul trezește aplicația pe baza comportamentului unui utilizator și își propune să declanșeze preluări de fundal înainte ca utilizatorul să lanseze aplicația. De exemplu, dacă utilizatorul folosește întotdeauna o aplicație la 1 p.m., sistemul învață și se adaptează, efectuând preluări înainte de perioadele de utilizare. Preluările de fundal sunt combinate între aplicații de către radioul dispozitivului pentru a reduce utilizarea bateriei și, dacă raportați că datele noi nu au fost disponibile în timpul unei preluări, iOS se poate adapta, folosind aceste informații pentru a evita preluările în momente liniștite.

primul pas în activarea preluării fundalului este să specificați că veți utiliza caracteristica din tasta UIBackgroundModes din lista de informații. Cel mai simplu mod de a face acest lucru este să utilizați fila capabilități noi din editorul de proiecte Xcode 5, care include o secțiune moduri de fundal pentru configurarea ușoară a opțiunilor multitasking.

alternativ, puteți edita cheia manual:

<key>UIBackgroundModes</key><array> <string>fetch</string></array>

apoi, spuneți iOS cât de des doriți să preluați:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ ; return YES;}

intervalul implicit de preluare nu este niciodată, deci va trebui să setați un interval de timp sau aplicația nu va fi apelată niciodată în fundal. Valoarea UIApplicationBackgroundFetchIntervalMinimum solicită sistemului să gestioneze când aplicația dvs. este trezită, cât mai des posibil, dar ar trebui să specificați propriul interval de timp dacă acest lucru nu este necesar. De exemplu, o aplicație meteo poate actualiza condițiile doar pe oră. iOS va aștepta cel puțin intervalul de timp specificat între preluările de fundal.

dacă aplicația dvs. permite unui utilizator să se deconecteze și știți că nu vor exista date noi, poate doriți să setați minimumBackgroundFetchInterval înapoi la UIApplicationBackgroundFetchIntervalNever pentru a fi un bun cetățean și pentru a economisi resurse.

ultimul pas este să implementați următoarea metodă în delegatul aplicației:

- (void) application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{ NSURLSessionConfiguration *sessionConfiguration = ; NSURLSession *session = ; NSURL *url = initWithString:@"http://yourserver.com/data.json"]; NSURLSessionDataTask *task = ; // Start the task ;}

aici puteți efectua lucrări atunci când sunteți trezit de sistem. Rețineți că aveți doar 30 de secunde pentru a determina dacă este disponibil conținut nou, pentru a procesa conținutul nou și pentru a vă actualiza interfața de utilizare. Acesta ar trebui să fie suficient timp pentru a prelua date din rețea și pentru a prelua câteva miniaturi pentru interfața dvs. de utilizare, dar nu mult mai mult. Când solicitările dvs. de rețea sunt complete și interfața dvs. de utilizare a fost actualizată, ar trebui să apelați handler-ul de finalizare.

handler finalizarea servește două scopuri. În primul rând, sistemul măsoară puterea utilizată de procesul dvs. și înregistrează dacă au fost disponibile date noi pe baza argumentului UIBackgroundFetchResult pe care l-ați transmis. În al doilea rând, atunci când apelați handler finalizare, un instantaneu de UI este luată și app switcher este actualizat. Utilizatorul va vedea noul conținut atunci când el sau ea este de comutare aplicații. Acest comportament snapshotting handler de finalizare este comun tuturor manipulatorilor de finalizare din noile API-uri multitasking.

într-o aplicație din lumea reală, ar trebui să transmiteți completionHandler sub-componentelor aplicației dvs. și să o apelați atunci când ați procesat date și ați actualizat interfața de utilizare.

în acest moment, s-ar putea să vă întrebați cum iOS poate instantaneu UI-ul aplicației dvs. atunci când rulează în fundal și cum funcționează ciclul de viață al aplicației cu preluarea fundalului. Dacă aplicația dvs. este suspendată în prezent, Sistemul o va trezi înainte de a apela application: performFetchWithCompletionHandler:. Dacă aplicația dvs. nu rulează, sistemul o va lansa, apelând metodele obișnuite de Delegare, inclusiv application: didFinishLaunchingWithOptions:. Vă puteți gândi la ea ca aplicația care rulează exact în același mod ca și în cazul în care utilizatorul a lansat-o de la Springboard, cu excepția UI este invizibil, prestate offscreen.

în majoritatea cazurilor, veți efectua aceeași lucrare atunci când aplicația se lansează în fundal ca și în prim-plan, dar puteți detecta lansările de fundal uitându-vă la proprietatea applicationState a UIApplication:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ NSLog(@"Launched in background %d", UIApplicationStateBackground == application.applicationState); return YES;}

testarea Background Fetch

există două moduri în care puteți simula un background fetch. Cea mai ușoară metodă este de a rula aplicația de la Xcode și faceți clic pe simula fundal Fetch sub meniul de depanare Xcode în timp ce aplicația se execută.

alternativ, puteți utiliza o schemă pentru a modifica modul în care Xcode rulează aplicația. Sub elementul de meniu Xcode produs, alegeți schemă și apoi gestionați scheme. De aici, editați sau adăugați o nouă schemă și bifați caseta de selectare lansare datorită unui eveniment de preluare în fundal, așa cum se arată mai jos.

notificări la distanță

notificările la distanță vă permit să notificați aplicația atunci când apar evenimente importante. Este posibil să aveți mesaje instantanee noi de livrat, alerte de știri de ultimă oră de trimis sau cel mai recent episod al emisiunii TV preferate a utilizatorului dvs. gata pentru descărcare pentru vizualizare offline. Notificările de la distanță sunt excelente pentru conținut sporadic, dar imediat important, unde întârzierea dintre preluările de fundal ar putea să nu fie acceptabilă. Notificările de la distanță pot fi, de asemenea, mult mai eficiente decât preluarea de fundal, deoarece aplicația dvs. se lansează numai atunci când este necesar.

o notificare de la distanță este într-adevăr doar o notificare Push normală cu setul de pavilion content-available. Puteți trimite o apăsare cu un mesaj de alertă care informează utilizatorul că s-a întâmplat ceva, în timp ce actualizați interfața de utilizare în fundal. Dar notificările de la distanță pot fi, de asemenea, silențioase, fără mesaj de alertă sau sunet, utilizate doar pentru a actualiza interfața aplicației sau pentru a declanșa munca de fundal. Puteți posta apoi o notificare locală când ați terminat de descărcat sau procesat noul conținut.

notificările push silențioase sunt limitate la rată, așa că nu vă fie teamă să trimiteți cât mai multe cereri. iOS și serverele APN vor controla cât de des sunt livrate și nu veți avea probleme pentru trimiterea prea multor. Dacă notificările push sunt accelerate, acestea ar putea fi amânate până la data viitoare când dispozitivul trimite un pachet keep-alive sau primește o altă notificare.

trimiterea notificărilor la distanță

pentru a trimite o notificare la distanță, setați steagul conținut disponibil într-o sarcină utilă de notificare push. Steagul disponibil pentru conținut este aceeași cheie utilizată pentru a notifica aplicațiile chioșcului de ziare, astfel încât majoritatea scripturilor push și Bibliotecilor acceptă deja notificări de la distanță. Când trimiteți o notificare la distanță, este posibil să doriți să includeți și unele date în sarcina utilă de notificare, astfel încât aplicația dvs. să poată face referire la eveniment. Acest lucru ar putea salva câteva cereri de rețea și de a crește capacitatea de reacție a aplicației.

vă recomandăm să utilizați utilitarul Houston Nomad CLI pentru a trimite mesaje push în timpul dezvoltării, dar puteți utiliza biblioteca sau scriptul preferat.

puteți instala Houston, ca parte a nomad – cli Ruby gem:

gem install nomad-cli

și apoi trimiteți o notificare cu utilitarul apn inclus în Nomad

# Send a Push Notification to your Deviceapn push <device token> -c /path/to/key-cert.pem -n -d content-id=42

aici steagul -n specifică faptul că cheia disponibilă pentru conținut ar trebui inclusă și -d ne permite să adăugăm propriile chei de date la sarcina utilă.

sarcina utilă de notificare rezultată arată astfel:

{ "aps" : { "content-available" : 1 }, "content-id" : 42}

iOS 7 adaugă o nouă metodă de Delegare a aplicației, care se numește atunci când se primește o notificare push cu cheia disponibilă pentru conținut:

- (void) application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{ NSLog(@"Remote Notification userInfo is %@", userInfo); NSNumber *contentID = userInfo; // Do something with the content ID completionHandler(UIBackgroundFetchResultNewData);}

din nou, aplicația este lansată în fundal și are 30 de secunde pentru a prelua conținut nou și a actualiza interfața de utilizare, înainte de a apela handler-ul de finalizare. Am putea efectua o solicitare rapidă de rețea așa cum am făcut-o în exemplul de preluare a fundalului, dar să folosim noul serviciu puternic de transfer de fundal pentru a solicita o sarcină mare de descărcare și a vedea cum putem actualiza interfața noastră de utilizare atunci când se finalizează.

NSURLSession și serviciul de transfer de fundal

în timp ce NSURLSession este o nouă clasă în iOS 7, se referă, de asemenea, la noua tehnologie în rețea fundație. Destinate să înlocuiască NSURLConnection, se păstrează concepte și clase familiare precum NSURL, NSURLRequest și NSURLResponse. Veți lucra cu înlocuitorul NSURLConnection, NSURLSessionTask, pentru a face solicitări de rețea și pentru a gestiona răspunsurile acestora. Există trei tipuri de activități de sesiune – date, descărcare și încărcare – fiecare dintre acestea adaugă zahăr sintactic la NSURLSessionTask, deci ar trebui să îl utilizați pe cel adecvat pentru cazul dvs. de utilizare.

un NSURLSessioncoordonează unul sau mai multe dintre aceste NSURLSessionTask s și se comportă în conformitate cu NSURLSessionConfiguration cu care a fost creat. Puteți crea mai multe NSURLSessions pentru a grupa activități asociate cu aceeași configurație. Pentru a interacționa cu serviciul de transfer de fundal, veți crea o configurație de sesiune utilizând . Sarcinile adăugate la o sesiune de fundal sunt rulate într-un proces extern și continuă chiar dacă aplicația dvs. este suspendată, se blochează sau este ucisă.

NSURLSessionConfiguration vă permite să setați anteturile HTTP implicite, să configurați politicile cache, să restricționați utilizarea rețelei celulare și multe altele. O opțiune este steagul discretionary, care permite sistemului să programeze sarcini pentru performanțe optime. Ceea ce înseamnă acest lucru este că transferurile dvs. vor trece doar prin Wifi atunci când dispozitivul are suficientă putere. Dacă bateria este descărcată sau este disponibilă doar o conexiune celulară, sarcina dvs. nu se va executa. Steagul discretionary are efect numai dacă obiectul de configurare a sesiunii a fost construit apelând metoda backgroundSessionConfiguration: și dacă transferul de fundal este inițiat în timp ce aplicația dvs. se află în prim-plan. Dacă transferul este inițiat din fundal, transferul va rula întotdeauna în modul discreționar.

acum știm puțin despre NSURLSession și cum funcționează o sesiune de fundal, să revenim la exemplul nostru de notificare la distanță și să adăugăm un cod pentru a solicita o descărcare pe serviciul de transfer de fundal. Când descărcarea se termină, vom notifica utilizatorul că fișierul este disponibil pentru utilizare.

NSURLSessionDownloadTask

În primul rând, să se ocupe de o notificare de la distanță și cere un NSURLSessionDownloadTask pe serviciul de transfer de fundal. În backgroundURLSession, creăm un NURLSession cu o configurație de sesiune de fundal și adăugăm delegatul aplicației noastre ca delegat de sesiune. Documentația recomandă instanțierea mai multor sesiuni cu același identificator, așa că folosim dispatch_once pentru a evita problemele potențiale:

- (NSURLSession *)backgroundURLSession{ static NSURLSession *session = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ NSString *identifier = @"io.objc.backgroundTransferExample"; NSURLSessionConfiguration* sessionConfig = ; session = ]; }); return session;}- (void) application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{ NSLog(@"Received remote notification with userInfo %@", userInfo); NSNumber *contentID = userInfo; NSString *downloadURLString = ]; NSURL* downloadURL = ; NSURLRequest *request = ; NSURLSessionDownloadTask *task = downloadTaskWithRequest:request]; task.taskDescription = ]; ; completionHandler(UIBackgroundFetchResultNewData);}

creăm o sarcină de descărcare folosind metoda clasei NSURLSession și configurăm solicitarea acesteia și oferim o descriere pentru utilizare ulterioară. Trebuie să vă amintiți să apelați pentru a începe efectiv sarcina, deoarece toate sarcinile de sesiune încep în starea suspendată.

acum trebuie să implementăm metodele NSURLSessionDownloadDelegate pentru a primi apeluri înapoi la finalizarea descărcării. De asemenea, poate fi necesar să implementați metode NSURLSessionDelegate sau NSURLSessionTaskDelegate dacă trebuie să gestionați autentificarea sau alte evenimente din ciclul de viață al sesiunii. Ar trebui să consultați ciclul de viață al documentului Apple al unei sesiuni URL cu delegați personalizați, ceea ce explică ciclul de viață complet pentru toate tipurile de activități de sesiune.

niciuna dintre metodele de delegare NSURLSessionDownloadDelegate nu este opțională, deși singura în care trebuie să acționăm în acest exemplu este . Când sarcina termină descărcarea, vi se oferă o adresă URL temporară a fișierului de pe disc. Trebuie să mutați sau să copiați fișierul în spațiul de stocare al aplicației, deoarece acesta va fi eliminat din spațiul de stocare temporar atunci când reveniți din această metodă de delegare.

#Pragma Mark - NSURLSessionDownloadDelegate- (void) URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location{ NSLog(@"downloadTask:%@ didFinishDownloadingToURL:%@", downloadTask.taskDescription, location); // Copy file to your app's storage with NSFileManager // ... // Notify your UI}- (void) URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes{}- (void) URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{}

dacă aplicația dvs. rulează încă în prim-plan atunci când sarcina sesiunii de fundal se termină, codul de mai sus va fi suficient. Cu toate acestea, în majoritatea cazurilor, aplicația dvs. nu va rula sau va fi suspendată în fundal. În aceste cazuri, trebuie să implementați două metode de Delegare a aplicației, astfel încât sistemul să vă poată trezi aplicația. Spre deosebire de apelurile delegate anterioare, delegatul aplicației este apelat de două ori, deoarece delegații de sesiune și de activitate pot primi mai multe mesaje. Metoda delegatului aplicației application: handleEventsForBackgroundURLSession: este apelată înainte ca aceste mesaje delegate NSURLSession să fie trimise și URLSessionDidFinishEventsForBackgroundURLSession este apelată ulterior. În prima metodă, stocați un fundal completionHandler, iar în cea de-a doua îl apelați pentru a vă actualiza interfața de utilizare:

- (void) application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler{ // You must re-establish a reference to the background session, // or NSURLSessionDownloadDelegate and NSURLSessionDelegate methods will not be called // as no delegate is attached to the session. See backgroundURLSession above. NSURLSession *backgroundSession = ; NSLog(@"Rejoining session with identifier %@ %@", identifier, backgroundSession); // Store the completion handler to update your UI after processing session events ;}- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session{ NSLog(@"Background URL session %@ finished events.\n", session); if (session.configuration.identifier) { // Call the handler we stored in -application:handleEventsForBackgroundURLSession: ; }}- (void)addCompletionHandler:(CompletionHandlerType)handler forSession:(NSString *)identifier{ if () { NSLog(@"Error: Got multiple handlers for a single session identifier. This should not happen.\n"); } ;}- (void)callCompletionHandlerForSession: (NSString *)identifier{ CompletionHandlerType handler = ; if (handler) { ; NSLog(@"Calling completion handler for session %@", identifier); handler(); }}

acest proces în două etape este necesar pentru a actualiza interfața de utilizare a aplicației dacă nu sunteți deja în prim-plan atunci când se finalizează transferul de fundal. În plus, dacă aplicația nu rulează deloc când se termină transferul de fundal, iOS o va lansa în fundal, iar metodele anterioare de Delegare a aplicației și sesiunii sunt apelate după application:didFinishLaunchingWithOptions:.

configurare și limitare

am atins pe scurt puterea transferurilor de fundal, dar ar trebui să explorați documentația și să vă uitați la opțiunile NSURLSessionConfiguration care acceptă cel mai bine cazul dvs. de utilizare. De exemplu, NSURLSessionTasks suport timeout resurse prin NSURLSessionConfiguration ‘ s timeoutIntervalForResource proprietate. Puteți utiliza acest lucru pentru a specifica cât timp doriți să permiteți finalizarea unui transfer înainte de a renunța complet. Puteți utiliza acest lucru dacă conținutul dvs. este disponibil doar pentru o perioadă limitată de timp sau dacă eșecul de a descărca sau încărca resursa în timpul datinterval indică faptul că utilizatorul nu are suficientă lățime de bandă Wifi.

În plus față de sarcinile de descărcare, NSURLSession acceptă pe deplin sarcinile de încărcare, astfel încât să puteți încărca un videoclip pe serverul dvs. în fundal și să vă asigurați utilizatorul că nu mai trebuie să lase aplicația în funcțiune, așa cum s-ar fi putut face în iOS 6. O atingere plăcută ar fi să setați proprietatea sessionSendsLaunchEvents a NSURLSessionConfiguration la NO, dacă aplicația dvs. nu are nevoie de lansare în fundal la finalizarea transferului. Utilizarea eficientă a resurselor de sistem menține atât iOS, cât și utilizatorul fericit.

În cele din urmă, există câteva limitări în utilizarea sesiunilor de fundal. Deoarece este necesar un delegat, nu puteți utiliza metodele simple de apel invers bazate pe blocuri pe NSURLSession. Lansarea aplicației în fundal este relativ costisitoare, astfel încât redirecționările HTTP sunt întotdeauna luate. Serviciul de transfer de fundal acceptă numai HTTP și HTTPS și nu puteți utiliza protocoale personalizate. Sistemul optimizează transferurile pe baza resurselor disponibile și nu puteți forța transferul să progreseze în fundal în orice moment.

rețineți, De asemenea, că NSURLSessionDataTasks nu sunt acceptate deloc în sesiunile de fundal și ar trebui să utilizați aceste activități numai pentru solicitări de scurtă durată, mici, nu pentru descărcări sau încărcări.

rezumat

noile API-uri multitasking și de rețea puternice din iOS 7 deschid o gamă întreagă de posibilități atât pentru aplicațiile noi, cât și pentru cele existente. Luați în considerare cazurile de utilizare din aplicația dvs. care pot beneficia de transferuri de rețea în afara procesului și de date noi și profitați la maximum de aceste API-uri fantastice noi. În general, implementați transferuri de fundal ca și cum aplicația dvs. rulează în prim plan, făcând actualizări UI adecvate, iar cea mai mare parte a lucrărilor este deja făcută pentru dvs.

  • utilizați API-ul nou adecvat pentru conținutul aplicației.

  • fiți eficienți și apelați manipulatorii de finalizare cât mai curând posibil.

  • manipulatorii de finalizare actualizează instantaneul UI al aplicației.

Lectură suplimentară

  • WWDC 2013 sesiune „ce este nou cu Multitasking”

  • WWDC 2013 sesiune „ce este nou în Fundația Networking”

  • ghid de programare a sistemului de încărcare URL

Lasă un răspuns

Adresa ta de email nu va fi publicată.