Arbeider med NSOperationQueue Class

Multi-oppgave hindrer apper fra å fryse. I de fleste programmeringsspråk er det vanskelig å oppnå dette, men NSOperationQueue-klassen i iOS gjør det enkelt!

Denne opplæringen vil vise hvordan du bruker NSOperationQueue klasse. Et NSOperationQueue-objekt er en kø som håndterer objekter av NSOperation klassetype. Et NSOperation-objekt, bare formulert, representerer en enkelt oppgave, inkludert både dataene og koden knyttet til oppgaven. NSOperationQueue håndterer og styrer utførelsen av alle NSOperation-objektene (oppgavene) som er lagt til det. Utførelsen skjer med hovedtråden i søknaden. Når et NSOperation-objekt blir lagt til i køen, utføres det umiddelbart, og det forlater ikke køen før den er ferdig. En oppgave kan bli kansellert, men den er ikke fjernet fra køen til den er ferdig. NSOperation-klassen er en abstrakt en, slik at den ikke kan brukes direkte i programmet. I stedet er det to underkategorier, den NSInvocationOperation klasse og NSBlockOperation klasse. Jeg bruker den første i denne opplæringen.


Eksempelprosjektet

Her er målet for denne opplæringen: For hver ekstra tråd ønsker vi at vårt program skal opprette et NSInvocationOperation (NSOperation) -objekt. Vi legger til hvert objekt i NSOperationQueue og så er vi ferdige. Køen tar ansvar for alt og appen fungerer uten frysing. For å demonstrere tydelig bruk av klassene jeg nevnte ovenfor, vil vi lage et (enkelt) prøveprosjekt der, bortsett fra hovedtråden i appen, vil vi ha to flere tråder som går sammen med den. På den første tråden vil en løkke løpe fra 1 til 10.000.000, og hver 100 trinn vil en etikett bli oppdatert med loopens motverdien. På den andre tråden fylles en etiketts bakgrunn med en egendefinert farge. Den prosessen vil finne sted inne i en løkke, og den vil bli utført mer enn en gang. Så vi vil ha noe som en fargrotator. Samtidig vises RGB-verdiene for den tilpassede bakgrunnsfargen sammen med loop-tellerens verdi ved siden av etiketten. Til slutt vil vi bruke tre knapper for å endre visningens bakgrunnsfarge på hovedtråden. Disse oppgavene kunne ikke utføres samtidig uten multi-tasking. Her ser du sluttresultatet:


Trinn 1: Opprett prosjektet

La oss begynne med å lage prosjektet. Åpne Xcode og opprett en ny Enkeltvisningsprogram.

Klikk på Neste og angi et navn på prosjektet. Jeg heter det ThreadingTestApp. Du kan bruke det samme eller andre navn du liker.

Neste. fullfør prosjektopprettelsen.


Trinn 2: Oppsett grensesnittet

Klikk på ViewController.xib fil for å avsløre grensesnittbyggeren. Legg til følgende kontroller for å lage et grensesnitt som det neste bildet:

  1. UINavigationBar
    • Ramme (x, y, W, H): 0, 0, 320, 44
    • Tintcolor: Sort farge
    • Tittel: "Enkel Multi-Threading Demo"
  2. UILabel
    • Ramme (x, y, W, H): 20, 59, 280, 21
    • Tekst: "Counter at Thread # 1"
  3. UILabel
    • Ramme (x, y, W, H): 20, 88, 280, 50
    • Bakgrunnsfarge: Lysegrå farge
    • Tekstfarge: Mørk grå farge
    • Tekst: -
  4. UILabel
    • Ramme (x, y, W, H): 20, 154, 280, 21
    • Tekst: "Tilfeldig farge rotator på tråd # 2"
  5. UILabel
    • Ramme (x, y, W, H): 20, 183, 100, 80
    • Bakgrunnsfarge: Lysegrå farge
    • Tekst: -
  6. UILabel
    • Ramme (x, y, W, H): 128, 183, 150, 80
    • Tekst: -
  7. UILabel
    • Ramme (x, y, W, H): 20, 374, 280, 21
    • Tekst: "Bakgrunnsfarge i hovedgruppen"
  8. UIButton
    • Ramme (x, y, W, H): 20, 403, 73, 37
    • Tittel: "Farge # 1"
  9. UIButton
    • Ramme (x, y, W, H): 124, 403, 73, 37
    • Tittel: "Farge # 2"
  10. UIButton
    • Ramme (x, y, W, H): 228, 403, 73, 37
    • Tittel: "Farge # 3"

For den siste UILabel og de tre UIButtons, sett autostørrelse verdi til Venstre - Bunn for å få grensesnittet til å se fint ut på iPhone 4 / 4S og iPhone 5, akkurat som det neste bildet:


Trinn 3: IBOutlet Properties og IBAction Methods

I dette neste trinnet vil vi opprette IBOutlet-egenskapene og IBAction-metodene som er nødvendige for å gjøre vårt eksempelapp-arbeid. Hvis du vil opprette nye egenskaper og metoder, og koble dem til kontrollene dine mens du er Interface Builder, klikker du på midtknappen på editor-knappen på Xcode-verktøylinjen for å avsløre Assistent Editor:

Ikke alle kontroller trenger en uttakseiendom. Vi vil bare legge til en for UILabels 3, 5 og 6 (i henhold til ordren ble de oppført i trinn 2), oppkalt label1, label2 og label3.

For å sette inn en ny utgangseiendom, Kontroll + Klikk (Høyreklikk) på en etikett> Klikk på Ny referanseutgang> Dra og slipp inn i assistenteditoren. Deretter angir du navnet på den nye eiendommen, akkurat som i følgende bilder:

Sette inn en ny IBOutlet-eiendom


Angi egenskapsnavn for IBOutlet

Gjenta prosessen over tre ganger for å koble de tre UILabels til egenskaper. Inne i din ViewController.h fil du har disse egenskapene deklarert:

 @property (behold, nonatomic) IBOutlet UILabel * label1; @property (behold, nonatomic) IBOutlet UILabel * label2; @property (behold, nonatomic) IBOutlet UILabel * label3;

Legg nå IBAction metoder for de tre UIButtons. Hver enkelt knapp vil endre bakgrunnsfargen på visningen. Slik setter du inn en ny IBAction-metode, Kontroll + Klikk (Høyreklikk) på en UIButton> Klikk på Touch Up Inside> Dra og slipp inn Assistent Editor. Deretter angir du navnet på den nye metoden. Ta en titt på følgende bilder og neste utdrag for metodenavnene:


Sette inn en ny IBAction-metode
Angi IBAction-metodenavnet

Igjen, gjenta prosessen over tre ganger for å koble hver UIButton til en handlingsmetode. De ViewController.h filen skal nå inneholde disse:

 - (IBAction) applyBackgroundColor1; - (IBAction) applyBackgroundColor2; - (IBAction) applyBackgroundColor3;

IBOutlet-egenskapene og IBAction-metodene er nå klare. Vi kan nå begynne koding.


Trinn 4: NSOperationQueue Object og Nødvendige Oppgave-relaterte Metode Deklarasjoner

En av de viktigste oppgavene vi må gjøre er å erklære en NSOperationQueue objekt (vår operasjonskø), som vil bli brukt til å utføre våre oppgaver i sekundære tråder. Åpne ViewController.h fil og legg til følgende innhold rett etter @interface Overskrift (ikke glem de krøllede parentesene):

 @interface ViewController: UIViewController NSOperationQueue * operationQueue; 

Også hver oppgave må ha minst en metode som inneholder koden som vil kjøre samtidig med hovedtråden. Ifølge den innledende beskrivelsen blir den første oppgaven metoden navngitt counterTask og den andre vil bli navngitt colorRotatorTask:

 -(Void) counterTask; - (void) colorRotatorTask;

Det er alt vi trenger. Våre ViewController.h filen skal se slik ut:

 @interface ViewController: UIViewController NSOperationQueue * operationQueue;  @property (behold, nonatomic) IBOutlet UILabel * label1; @property (behold, nonatomic) IBOutlet UILabel * label2; @property (behold, nonatomic) IBOutlet UILabel * label3; - (IBAction) applyBackgroundColor1; - (IBAction) applyBackgroundColor2; - (IBAction) applyBackgroundColor3; - (void) counterTask; - (void) colorRotatorTask; @slutt

La oss gå videre til implementering.


Trinn 5: Implementering

Vi er nesten ferdig. Vi har oppsett vårt grensesnitt, gjort alle nødvendige tilkoblinger, erklært nødvendige IBAction og andre metoder, og etablert vår base. Nå er det på tide å bygge på dem.

Åpne ViewController.m fil og gå til viewDidLoad metode. Den viktigste delen av denne opplæringen skal finne sted her. Vi vil opprette en ny NSOperationQueue eksempel og to NSOperation (NSInvocationOperation) objekter. Disse objektene vil inkapslere koden til de to metodene vi tidligere erklærte og da vil de bli henrettet på egen hånd av NSOperationQueue. Her er koden:

 - (void) viewDidLoad [super viewDidLoad]; // Opprett en ny NSOperationQueue-forekomst. operationQueue = [NSOperationQueue new]; // Opprett et nytt NSOperation-objekt ved hjelp av NSInvocationOperation-underklassen. // Fortell det å kjøre counterTask-metoden. NSInvocationOperation * operation = [[NSInvocationOperation alloc] initWithTarget: selector: @selector (counterTask) objekt: null]; // Legg til operasjonen i køen og la den bli kjørt. [operationQueue addOperation: drift]; [operasjonsutgivelse]; // Den samme historien som ovenfor, bare fortell her for å utføre colorRotatorTask-metoden. operasjon = [[NSInvocationOperation alloc] initWithTarget: selvvalg: @selector (colorRotatorTask) objekt: null]; [operationQueue addOperation: drift]; [operasjonsutgivelse]; 

Hele denne prosessen er veldig enkel. Etter å ha opprettet NSOperationQueue eksempelvis lager vi et NSInvocationOperation-objekt (operasjon). Vi setter sin valgmetode (koden vi vil ha henrettet på en egen tråd), og så legger vi den til køen. Når det kommer inn i køen, begynner det umiddelbart å løpe. Derefter kan operasjonsobjektet frigjøres, siden køen er ansvarlig for å håndtere den fra nå av. I dette tilfellet oppretter vi et annet objekt, og vi bruker det på samme måte for den andre oppgaven (colorRotatorTask).

Vår neste oppgave er å implementere de to valgmåter. La oss begynne med å skrive counterTask metode. Det vil inneholde en til loop som vil løpe for et stort antall iterasjoner og hver 100 trinnene Label1s tekst vil bli oppdatert med den nåværende iterasjonens motverdien (Jeg). Koden er enkel, så her er alt:

 -(void) counterTask // Lag en BIG loop og hver 100 trinn la den oppdatere etiketten1 UILabel med tellerens verdi. for (int i = 0; i<10000000; i++)  if (i % 100 == 0)  // Notice that we use the performSelectorOnMainThread method here instead of setting the label's value directly. // We do that to let the main thread to take care of showing the text on the label // and to avoid display problems due to the loop speed. [label1 performSelectorOnMainThread:@selector(setText:) withObject:[NSString stringWithFormat:@"%d", i] waitUntilDone:YES];   // When the loop gets finished then just display a message. [label1 performSelectorOnMainThread:@selector(setText:) withObject:@"Thread #1 has finished." waitUntilDone:NO]; 

Vær oppmerksom på at det anbefales som den beste praksisen (selv av Apple) å utføre visuelle oppdateringer på grensesnittet ved hjelp av hovedtråden, og ikke ved å gjøre det direkte fra en sekundær tråd. Derfor er bruken av performSelectorOnMainThread Metode er nødvendig i tilfeller som denne.

La oss nå implementere colorRotatorTask metode:

 -(void) colorRotatorTask // Vi trenger en egendefinert farge for å jobbe med. UIColor * customColor; // Kjør en loop med 500 iterasjoner. for (int i = 0; i<500; i++)  // Create three float random numbers with values from 0.0 to 1.0. float redColorValue = (arc4random() % 100) * 1.0 / 100; float greenColorValue = (arc4random() % 100) * 1.0 / 100; float blueColorValue = (arc4random() % 100) * 1.0 / 100; // Create our custom color. Keep the alpha value to 1.0. customColor = [UIColor colorWithRed:redColorValue green:greenColorValue blue:blueColorValue alpha:1.0]; // Change the label2 UILabel's background color. [label2 performSelectorOnMainThread:@selector(setBackgroundColor:) withObject:customColor waitUntilDone:YES]; // Set the r, g, b and iteration number values on label3. [label3 performSelectorOnMainThread:@selector(setText:) withObject:[NSString stringWithFormat:@"Red: %.2f\nGreen: %.2f\nBlue: %.2f\Iteration #: %d", redColorValue, greenColorValue, blueColorValue, i] waitUntilDone:YES]; // Put the thread to sleep for a while to let us see the color rotation easily. [NSThread sleepForTimeInterval:0.4];  // Show a message when the loop is over. [label3 performSelectorOnMainThread:@selector(setText:) withObject:@"Thread #2 has finished." waitUntilDone:NO]; 

Du kan se at vi brukte performSelectorOnMainThread metode her også. Det neste trinnet er [NSThread sleepForTimeInterval: 0.4]; kommando, som brukes til å forårsake en kort forsinkelse (0,4 sekunder) i hver loop-utførelse. Selv om det ikke er nødvendig å bruke denne metoden, er det å foretrekke å bruke det her for å redusere bakgrunnsfarvens endringshastighet på Label2 UILabel (vår fargerotator). I hver krets lager vi også tilfeldige verdier for rød, grønn og blå. Vi angir deretter disse verdiene for å lage en egendefinert farge og angi den som bakgrunnsfarge i Label2 UILabel.

På dette tidspunktet er de to oppgavene som skal utføres samtidig med hovedtrådene klare. La oss implementere de tre (veldig enkelt) IBAction-metodene, og så er vi klare til å gå. Som jeg allerede har nevnt, vil de tre UIButtons endre visningsens bakgrunnsfarge, med det ultimate målet å demonstrere hvordan hovedtråden kan løpe sammen med de to andre oppgavene. Her er de:

 - (IBAction) applyBackgroundColor1 [self.view setBackgroundColor: [UIColor colorWithRed: 255.0 / 255.0 grønn: 204.0 / 255.0 blå: 102.0 / 255.0 alpha: 1.0]];  - (IBAction) applyBackgroundColor2 [self.view setBackgroundColor: [UIColor colorWithRed: 204.0 / 255.0 grønn: 255.0 / 255.0 blå: 102.0 / 255.0 alpha: 1.0]];  - (IBAction) applyBackgroundColor3 [self.view setBackgroundColor: [UIColor whiteColor]]; 

Det er det! Nå kan du kjøre programmet og se hvordan tre forskjellige oppgaver kan finne sted samtidig. Husk at når utførelsen av NSOperation-objekter er over, vil den automatisk forlate køen.


Konklusjon

Mange av dere har kanskje allerede oppdaget at den faktiske koden for å kjøre en multi-tasking-app kun krever noen linjer med kode. Det ser ut til at den største arbeidsbelastningen er å implementere de nødvendige metodene som fungerer med hver oppgave. Likevel, denne metoden er en enkel måte å utvikle multi-threading apps i iOS.