Programim dhe zhvillim, javascript, python, php, html

Përdorimi i ReactiveCocoa për të gjurmuar përditësimet e UI me një objekt në distancë

Unë jam duke krijuar një aplikacion iOS që ju lejon të kontrolloni në distancë muzikën në një aplikacion që luan në desktopin tuaj.

Një nga problemet më të vështira është aftësia për të përditësuar pozicionin e "gjurmuesit" (i cili tregon pozicionin kohor dhe kohëzgjatjen e këngës që luhet aktualisht). Këtu ka disa burime të dhënash:

  • Në nisje, telekomanda dërgon një kërkesë rrjeti për të marrë pozicionin fillestar dhe kohëzgjatjen e këngës që luhet aktualisht.
  • Kur përdoruesi rregullon pozicionin e gjurmuesit duke përdorur telekomandën, ai dërgon një kërkesë rrjeti te aplikacioni i muzikës për të ndryshuar pozicionin e këngës.
  • Nëse përdoruesi përdor aplikacionin në desktop për të ndryshuar pozicionin e gjurmuesit, aplikacioni dërgon një kërkesë rrjeti në telekomandë me pozicionin e ri të gjurmuesit.
  • Nëse kënga po luhet aktualisht, pozicioni i gjurmuesit përditësohet çdo 0,5 sekonda ose më shumë.

Për momentin, gjurmuesi është një UISlider i cili mbështetet nga një model "Player". Sa herë që përdoruesi ndryshon pozicionin në rrëshqitës, ai përditëson modelin dhe dërgon një kërkesë rrjeti, si kjo:

Në NowPlayingViewController.m

[[slider rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(UISlider *x) {
    [playerModel seekToPosition:x.value];
}];

[RACObserve(playerModel, position) subscribeNext:^(id x) {
    slider.value = player.position;
}];

Në PlayerModel.m:

@property (nonatomic) NSTimeInterval position;

- (void)seekToPosition:(NSTimeInterval)position
{
    self.position = position;
    [self.client newRequestWithMethod:@"seekTo" params:@[positionArg] callback:NULL];
}

- (void)receivedPlayerUpdate:(NSDictionary *)json
{
    self.position = [json objectForKey:@"position"]
}

Problemi është kur një përdorues "përplas" me rrëshqitësin dhe vendos në radhë një numër kërkesash rrjeti të cilat të gjitha kthehen në kohë të ndryshme. Përdoruesi mund të ketë lëvizur përsëri rrëshqitësin kur të merret një përgjigje, duke e zhvendosur rrëshqitësin përsëri në një vlerë të mëparshme.

Pyetja ime: Si ta përdor saktë ReactiveCocoa në këtë shembull, duke u siguruar që përditësimet nga rrjeti të trajtohen, por vetëm nëse përdoruesi nuk e ka lëvizur rrëshqitësin që atëherë?


Përgjigjet:


1

lidhjen tuaj të GitHub në lidhje me këtë ju thoni se doni t'i konsideroni përditësimet e telekomandës si kanonike . Kjo është mirë, sepse (siç sugjeroi Josh Abernathy atje), RAC ose jo, ju duhet të zgjidhni një nga dy burimet për të marrë përparësi (ose keni nevojë për stampa kohore, por më pas ju duhet një orë referimi...).

Duke pasur parasysh kodin tuaj dhe shpërfilljen e RAC, zgjidhja është thjesht vendosja e një flamuri në seekToPosition: dhe çrregullimi i tij duke përdorur një kohëmatës. Kontrolloni flamurin në recievedPlayerUpdate:, duke injoruar përditësimin nëse është caktuar.

Nga rruga, ju duhet të përdorni makro RAC() për të lidhur vlerën e rrëshqitësit tuaj, në vend të subscribeNext: që keni:

RAC(slider, value) = RACObserve(playerModel, position);

Megjithatë, ju mund të ndërtoni patjetër një zinxhir sinjali për të bërë atë që dëshironi. Ju keni katër sinjale që duhet t'i kombinoni.

Për artikullin e fundit, përditësimin periodik, mund të përdorni interval:onScheduler::

[[RACSignal interval:kPositionFetchSeconds
         onScheduler:[RACScheduler scheduler]] map:^(id _){
                          return /* Request position over network */;
}];

map: thjesht injoron datën që prodhon sinjali interval:... dhe merr pozicionin. Meqenëse kërkesat dhe mesazhet tuaja nga desktopi kanë prioritet të barabartë, merge: ata së bashku:

[RACSignal merge:@[desktopPositionSignal, timedRequestSignal]];

Megjithatë, vendosët se nuk dëshironi që asnjëri prej këtyre sinjaleve të kalojë nëse përdoruesi ka prekur rrëshqitësin. Kjo mund të realizohet në një nga dy mënyrat. Duke përdorur flamurin që sugjerova, mund të filter: ai sinjal i bashkuar:

[mergedSignal filter:^BOOL (id _){ return userFiddlingWithSlider; }];

Më mirë se kaq -- shmangia e gjendjes shtesë -- do të ishte të ndërtoje një operacion nga një kombinim i throttle: dhe sample: që kalon një vlerë nga një sinjal në një interval të caktuar pasi një sinjal tjetër nuk ka dërguar asgjë:

[mergedSignal sample:
          [sliderSignal throttle:kUserFiddlingWithSliderInterval]];

(Dhe, sigurisht, mund të dëshironi të mbytni/kampiononi sinjalin interval:onScheduler: në të njëjtën mënyrë -- përpara bashkimit -- në mënyrë që të shmangni kërkesat e panevojshme të rrjetit.)

Mund t'i bashkoni të gjitha në PlayerModel, duke e lidhur me position. Thjesht do t'ju duhet t'i jepni PlayerModel rac_signalForControlEvents: të rrëshqitësit dhe më pas të bashkoni vlerën e rrëshqitësit. Meqenëse po përdorni të njëjtin sinjal në shumë vende në një zinxhir, besoj se dëshironi ta "multicast" atë.

Së fundi, përdorni startWith: për të marrë të parën tuaj artikulli më sipër, pozicioni fillestar nga aplikacioni i desktopit, në transmetim.

RAC(self, position) = 
    [[RACSignal merge:@[sampledSignal,
                        [sliderSignal map:^id(UISlider * slider){
                                                    return [slider value];
                        }]]
] startWith:/* Request position over network */];

Vendimin për të ndarë çdo sinjal në variablin e vet ose për t'i bashkuar të gjitha së bashku në stilin Lisp, do t'jua lë juve.

Rastësisht, e kam parë të dobishme të nxjerr zinxhirët e sinjalit kur punojmë për probleme si kjo. Unë bëra një diagram të shpejtë për skenarin tuaj. Ndihmon me të menduarit e sinjaleve si entitete më vete, në krahasim me shqetësimin për vlerat që ato mbartin.

03.01.2014
Materiale të reja

Masterclass Coroutines: Kapitulli-3: Anulimi i korutinave dhe trajtimi i përjashtimeve.
Mirë se vini në udhëzuesin gjithëpërfshirës mbi Kotlin Coroutines! Në këtë seri artikujsh, unë do t'ju çoj në një udhëtim magjepsës, duke filluar nga bazat dhe gradualisht duke u thelluar në..

Faketojeni derisa ta arrini me të dhënat false
A e gjeni ndonjëherë veten duke ndërtuar një aplikacion të ri dhe keni nevojë për të dhëna testimi që duken dhe duken më realiste ose një grup i madh të dhënash për performancën e ngarkesës...

Si të përdorni kërkesën API në Python
Kërkesë API në GitHub për të marrë depot e përdoruesve duke përdorur Python. Në këtë artikull, unë shpjegoj procesin hap pas hapi për të trajtuar një kërkesë API për të marrë të dhëna nga..

Një udhëzues hap pas hapi për të zotëruar React
Në këtë artikull, do të mësoni se si të krijoni aplikacionin React, do të mësoni se si funksionon React dhe konceptet thelbësore që duhet të dini për të ndërtuar aplikacione React. Learning..

AI dhe Psikologjia — Pjesa 2
Në pjesën 2 të serisë sonë të AI dhe Psikologji ne diskutojmë se si makineritë mbledhin dhe përpunojnë të dhëna për të mësuar emocione dhe ndjenja të ndryshme në mendjen e njeriut, duke ndihmuar..

Esencialet e punës ditore të kodit tim VS
Shtesat e mia të preferuara - Git Graph 💹 Kjo shtesë është vërtet e mahnitshme, e përdor përpara se të filloj të punoj për të kontrolluar dy herë ndryshimet dhe degët më të fundit, mund të..

Pse Python? Zbulimi i fuqisë së gjithanshme të një gjiganti programues
Në peizazhin gjithnjë në zhvillim të gjuhëve të programimit, Python është shfaqur si një forcë dominuese. Rritja e tij meteorike nuk është rastësi. Joshja e Python qëndron në thjeshtësinë,..