Uzziniet iOS paraugpraksi, izveidojot vienkāršu recepšu lietotni

Avots: ChefStep

Satura rādītājs

  • Darba sākšana
  • Xcode un Swift versija
  • Minimālā atbalstāmā iOS versija
  • Xcode projekta organizēšana
  • Receptes lietotnes struktūra
  • Koda konvencijas
  • Dokumentācija
  • Kodu sadaļu marķēšana
  • Avota kontrole
  • Atkarības
  • Iekļūšana projektā
  • API
  • Palaišanas ekrāns
  • Lietotnes ikona
  • Apgaismojuma kods ar SwiftLint
  • Tipa drošs resurss
  • Parādiet man kodu
  • Modeļa izstrāde
  • Labāka navigācija, izmantojot FlowController
  • Automātiskais izkārtojums
  • Arhitektūra
  • Masīvs skata kontrolieris
  • Piekļuves kontrole
  • Slinks īpašības
  • Kodu fragmenti
  • Tīklošana
  • Kā pārbaudīt tīkla kodu
  • Kešatmiņas ieviešana bezsaistes atbalstam
  • Kā pārbaudīt kešatmiņu
  • Attālo attēlu ielāde
  • Attēla ielādi padarot ērtāku UIImageView
  • Vispārējs datu avots UITableView un UICollectionView
  • Kontrolieris un skats
  • Darbs ar bērniem ar skatu kontrolieri
  • Sastāvs un atkarības injekcija
  • Lietotņu transporta drošība
  • Pielāgots ritināms skats
  • Meklēšanas funkcionalitātes pievienošana
  • Prezentācijas konteksta izpratne
  • Atteikšanās no meklēšanas darbībām
  • Pārbaudes noņemšana ar apgrieztām cerībām
  • Lietotāja saskarnes pārbaude ar UITest
  • Galvenā vītnes aizsargs
  • Izrāžu un jautājumu mērīšana
  • Prototipēšana ar rotaļu laukumu
  • Kurp doties tālāk no šejienes

Es sāku iOS izstrādi, kad tika paziņots par iOS 7. Un es, strādājot, esmu mazliet iemācījies kolēģu un iOS kopienas padomus.

Šajā rakstā es vēlētos dalīties daudzās labajās praksēs, parādot vienkāršas receptes lietotnes piemēru. Pirmkods ir vietnē GitHub Recipes.

Lietotne ir tradicionāla galveno detalizēto lietojumprogramma, kurā parādīts recepšu saraksts kopā ar detalizētu informāciju.

Ir tūkstošiem problēmu risināšanas paņēmienu, un veids, kā problēmu risināt, ir atkarīgs arī no personīgās gaumes. Cerams, ka visā šajā rakstā jūs uzzināsit kaut ko noderīgu - es daudz uzzināju, kad darbojos šajā projektā.

Es esmu pievienojis saites uz dažiem atslēgvārdiem, kur es jutu, ka turpmāka lasīšana būtu noderīga. Tāpēc noteikti pārbaudiet tos. Visas atsauksmes ir laipni gaidītas.

Tātad, sāksim ...

Šeit ir izveidots augsta līmeņa pārskats.

Darba sākšana

Pieņemsim lēmumu par rīka un projekta iestatījumiem, kurus mēs izmantojam.

Xcode un Swift versija

WWDC 2018 Apple iepazīstināja ar Xcode 10 ar Swift 4.2. Rakstīšanas laikā Xcode 10 joprojām ir beta 5. Tāpēc pieturēsimies pie stabilajiem Xcode 9 un Swift 4.1. Xcode 4.2 ir dažas lieliskas iespējas - jūs varat spēlēt ar to caur šo lielisko Playground. Tas neievieš milzīgas izmaiņas no Swift 4.1, tāpēc tuvākajā nākotnē mēs varam viegli atjaunināt mūsu lietotni, ja tāda būs nepieciešama.

Mērķa iestatījumu vietā projekta iestatījumā vajadzētu iestatīt Swift versiju. Tas nozīmē, ka visiem projekta mērķiem ir viena un tā pati Swift versija (4.1).

Minimālā atbalstāmā iOS versija

Sākot ar 2018. gada vasaru, iOS 12 ir publiskajā beta 5 versijā, un mēs nevaram atlasīt mērķauditoriju iOS 12 bez Xcode 10. Šajā amatā mēs izmantojam Xcode 9 un bāzes SDK ir iOS 11. Atkarībā no prasības un lietotāju bāzes, dažas lietotnes ir jāatbalsta vecās iOS versijas. Lai arī iOS lietotāji mēdz pieņemt jaunas iOS versijas ātrāk nekā tie, kuri izmanto operētājsistēmu Android, ir dažas, kuras paliek vecās. Saskaņā ar Ābolu ieteikumiem mums ir jāatbalsta divas jaunākās versijas, kas ir iOS 10 un iOS 11. Kā App Store novērtēja 2018. gada 31. maijā, tikai 5% lietotāju izmanto iOS 9 un vecāku versiju.

Mērķauditorijas atlase pēc jaunām iOS versijām nozīmē, ka mēs varam izmantot jauno SDK priekšrocības, kuras Apple inženieri uzlabo katru gadu. Apple izstrādātāju vietnei ir uzlabots izmaiņu žurnāla skats. Tagad ir vieglāk redzēt, kas ir pievienots vai pārveidots.

Ideālā gadījumā, lai noteiktu, kad atteikties no veco iOS versiju atbalsta, mums ir nepieciešama analīze par to, kā lietotāji izmanto mūsu lietotni.

Xcode projekta organizēšana

Veidojot jauno projektu, atlasiet gan “Iekļaut vienības testus”, gan “Iekļaut lietotāja saskarnes testus”, jo tā bija ieteicama pārbaude savlaicīgi. Jaunākās izmaiņas XCTest ietvarā, it īpaši UI testos, padara testēšanu vieglu un ir diezgan stabilas.

Pirms jaunu failu pievienošanas projektam paņemiet pārtraukumu un padomājiet par savas lietotnes struktūru. Kā mēs vēlamies organizēt failus? Mums ir dažas iespējas. Mēs varam organizēt failus pēc pazīmēm / moduļiem vai lomām / veidiem. Katram no tiem ir savi plusi un mīnusi, un par tiem es diskutēšu tālāk.

Pēc lomas / veida:

  • Plusi: mazāk tiek domāts par to, kur ievietot failus. Skriptus vai filtrus ir arī vieglāk lietot.
  • Mīnusi: ir grūti savstarpēji saistīt, vai mēs vēlamies atrast vairākus failus, kas saistīti ar to pašu funkciju. Būtu vajadzīgs arī laiks failu reorganizēšanai, ja mēs nākotnē vēlamies tos padarīt par atkārtoti lietojamiem komponentiem.

Pēc funkcijas / moduļa

  • Plusi: Tas padara visu modulāru un mudina uz kompozīciju.
  • Mīnusi: Ja tiek komplektēti daudzi dažādu veidu faili, tas var kļūt nekārtīgs.

Paliek modulāri

Personīgi es cenšos pēc iespējas vairāk sakārtot savu kodu pēc funkcijām / komponentiem. Tas ļauj vieglāk noteikt saistīto labojamo kodu un nākotnē vieglāk pievienot jaunas funkcijas. Tas atbild uz jautājumu “Ko šī lietotne dara?”, Nevis “Kas ir šis fails?”. Šeit ir labs raksts par to.

Labs īkšķa noteikums ir saglabāt konsekvenci neatkarīgi no tā, kuru struktūru izvēlaties.

Receptes lietotnes struktūra

Tālāk ir sniegta lietotņu struktūra, kuru izmanto mūsu recepšu lietotne:

Avots

Satur avota koda failus, kas sadalīti komponentos:

  • Funkcijas: galvenās lietotnes funkcijas
  • Sākums: sākuma ekrāns, kurā parādīts recepšu saraksts un atvērta meklēšana
  • Saraksts: parāda recepšu sarakstu, ieskaitot receptes atkārtotu ielādi un tukša skata parādīšanu, ja recepte neeksistē
  • Meklēšana: veic meklēšanu un atcelšanu
  • Detail: parāda detalizētu informāciju

Bibliotēka

Satur mūsu lietojumprogrammas galvenās sastāvdaļas:

  • Plūsma: satur FlowController, lai pārvaldītu plūsmas
  • Adapteris: vispārējs UICollectionView datu avots
  • Pagarinājums: ērti paplašinājumi parastām darbībām
  • Modelis: Lietotnes modelis, parsēts no JSON

Resurss

Satur plist, resursus un Storyboard failus.

Koda konvencijas

Es piekrītu lielākajai daļai stila ceļvežu, kas ietilpst raywenderlich / swift-style-guide un github / swift-style-guide. Tie ir vienkārši un saprātīgi izmantojami Swift projektā. Iepazīstieties arī ar oficiālajām API dizaina vadlīnijām, kuras izstrādājusi Apple Swift komanda, kā uzrakstīt labāku Swift kodu.

Neatkarīgi no tā, kuru stila ceļvedi izvēlaties ievērot, jūsu vissvarīgākajam mērķim jābūt koda skaidrībai.

Atkāpe un tabulas vietas karš ir jutīga tēma, taču tas atkal ir atkarīgs no gaumes. Android projektos izmantoju četru atstarpes atkāpi un iOS un React - divas atstarpes. Šajā lietotnē Receptes es sekoju konsekventai un viegli pamatotai atkāpei, par kuru esmu rakstījis šeit un šeit.

Dokumentācija

Labam kodam vajadzētu sevi skaidri izskaidrot, tāpēc jums nav jāraksta komentāri. Ja koda daļu ir grūti saprast, ieteicams pauzēt un reaģēt uz dažām metodēm ar aprakstošiem nosaukumiem, lai tā kodoldaļa būtu saprotamāka. Tomēr uzskatu, ka dokumentēšanas klases un metodes ir noderīgas arī jūsu kolēģiem un nākamajiem pašiem. Saskaņā ar Swift API projektēšanas vadlīnijām,

Uzrakstiet komentāru par katru deklarāciju. Ieskats, kas iegūts, rakstot dokumentāciju, var nopietni ietekmēt jūsu dizainu, tāpēc neatlieciet to nost.

Komentāru veidni // Xcode ir ļoti viegli ģenerēt, izmantojot Cmd + Alt +/. Ja plānojat pārveidot savu kodu tā, lai nākotnē to varētu koplietot ar citiem, tādi rīki kā jazzy var ģenerēt dokumentāciju, lai citi cilvēki varētu sekot līdzi.

Kodu sadaļu marķēšana

Marka izmantošana var būt noderīga, lai atdalītu koda sadaļas. Tas arī labi sagrupē funkcijas navigācijas joslā. Varat arī izmantot paplašinājumu grupas, saistītās īpašības un metodes.

Vienkāršam UIViewController mēs varam definēt šādus marķējumus:

// MARK: - Init
// MARK: - Skatīt dzīves ciklu
// MARK: - iestatīšana
// MARK: - darbība
// MARK: - dati

Avota kontrole

Git šobrīd ir populāra avotu kontroles sistēma. Mēs varam izmantot veidni .gitignore failu no gitignore.io/api/swift. Pārbaudot atkarības failus (CocoaPods un Carthage), ir gan plusi, gan mīnusi. Tas ir atkarīgs no jūsu projekta, bet man ir tendence neuztikt atkarības (node_modules, Carthage, Pods) avota kontrolē, lai nepārblīvētu koda bāzi. Tas arī atvieglo Pull pieprasījumu pārskatīšanu.

Neatkarīgi no tā, vai jūs reģistrējaties Pods direktorijā, Podfile un Podfile.lock vienmēr jāuztur versijas kontrolē.

Es izmantoju gan iTerm2, lai izpildītu komandas, gan avota koku, lai skatītu zarus un inscenējumu.

Atkarības

Es esmu izmantojis trešo pušu ietvarus, kā arī daudz veidojis un sniedzis ieguldījumu atvērtā koda darbībā. Ietvara izmantošana dod jums stimulu jau pašā sākumā, bet tas nākotnē var arī jūs daudz ierobežot. Var būt dažas triviālas izmaiņas, kuras ir ļoti grūti novērst. Tas pats notiek, lietojot SDK. Mana izvēle ir izvēlēties aktīvās atvērtā pirmkoda struktūras. Rūpīgi izlasiet avota kodu un pārbaudiet ietvarus un konsultējieties ar komandu, ja plānojat tos izmantot. Nedaudz papildu piesardzības tas nekaitē.

Šajā lietotnē es cenšos izmantot pēc iespējas mazāk atkarību. Pietiek tikai, lai parādītu, kā pārvaldīt atkarības. Daži pieredzējuši izstrādātāji var dot priekšroku Carthage - atkarības pārvaldniekam, jo ​​tas dod jums pilnīgu kontroli. Šeit es izvēlos CocoaPods, jo to ir viegli lietot, un līdz šim tas ir lieliski darbojies.

Projekta saknē ir fails ar nosaukumu .swift-version 4.1, lai CocoaPods pastāstītu, ka šis projekts izmanto Swift 4.1. Tas izskatās vienkārši, bet man vajadzēja diezgan daudz laika, lai izdomātu.

Iekļūšana projektā

Izgatavosim dažus palaišanas attēlus un ikonas, lai projekts būtu jauks.

API

Vienkāršs veids, kā iemācīties iOS tīklošanu, ir, izmantojot publiskos bezmaksas API pakalpojumus. Šeit es izmantoju food2fork. Reģistrēties kontam var vietnē http://food2fork.com/about/api. Šajā publiskajā api krātuvē ir arī daudz citu lielisku API.

Ir vērts glabāt savus akreditācijas datus drošā vietā. Paroļu ģenerēšanai un glabāšanai izmantoju 1Password.

Pirms sākam kodēšanu, spēlēsimies ar API, lai redzētu, kāda veida pieprasījumi ir nepieciešami, un atbildes, kuras viņi sūta. Es izmantoju Insomnia rīku, lai pārbaudītu un analizētu API atbildes. Tas ir atvērts avots, bezmaksas un lieliski darbojas.

Palaišanas ekrāns

Pirmais iespaids ir svarīgs, tāpat kā Launch Screen. Ieteicamais veids ir LaunchScreen.storyboard izmantošana statiskā Launch attēla vietā.

Lai pievienotu palaišanas attēlu aktīvu katalogam, atveriet LaunchScreen.storyboard, pievienojiet UIImageView un piespraudiet to UIView malām. Mums nevajadzētu attēlu piespraust drošajai zonai, jo mēs vēlamies, lai attēls būtu pilnekrāna režīmā. Noņemiet arī atzīmes no automātiskā izkārtojuma ierobežojumiem. Iestatiet UIImageView saturuMode kā Aspect Fill, lai tas stiepjas ar pareizo malu attiecību.

Konfigurējiet izkārtojumu LaunchScreen.

Lietotnes ikona

Laba prakse ir nodrošināt visas nepieciešamās lietotņu ikonas katrai jūsu atbalstītajai ierīcei, kā arī tādām vietām kā Notification, Settings un Springboard. Pārliecinieties, vai katram attēlam nav caurspīdīgu pikseļu, pretējā gadījumā tas iegūst melnu fonu. Šis padoms ir no Cilvēka saskarnes vadlīnijām - lietotnes ikonas.

Saglabājiet fonu vienkāršu un izvairieties no caurspīdīguma. Pārliecinieties, vai jūsu ikona ir necaurspīdīga un nepārblīvē fonu. Piešķiriet tam vienkāršu fonu, lai tas nepārspētu citas tuvumā esošās lietotņu ikonas. Visa ikona nav jāaizpilda ar saturu.

Mums ir jāizstrādā kvadrātveida attēli, kuru izmērs ir lielāks par 1024 x 1024, lai katrs varētu samazināt attēlus līdz mazākiem. To var izdarīt ar roku, rakstīt skriptu vai izmantot šo mazo lietotni IconGenerator, kuru izveidoju.

Lietotne IconGenerator var ģenerēt iOS ikonas iPhone, iPad, macOS un watchOS lietotnēs. Rezultāts ir AppIcon.appiconset, kuru mēs varam ievilkt tieši aktīvu katalogā. Aktīvu katalogs ir veids, kā iet uz moderniem Xcode projektiem.

Apgaismojuma kods ar SwiftLint

Neatkarīgi no tā, kuru platformu mēs attīstām, ir labi, ja ir uzraksts, lai ieviestu konsekventas konvencijas. Vispopulārākais rīks Swift projektiem ir SwiftLint, kuru ir izveidojuši satriecošie Realm cilvēki.

Lai to instalētu, pievienojiet podfile “SwiftLint”, “~> 0,25”. Laba prakse ir arī norādīt atkarību versiju, lai pod instalēšana nejauši netiktu atjaunināta uz galveno versiju, kas varētu sabojāt jūsu lietotni. Pēc tam pievienojiet .swiftlint.yml ar vēlamo konfigurāciju. Parauga konfigurāciju var atrast šeit.

Visbeidzot pievienojiet jaunu Run Script Phrase, lai pēc apkopošanas izpildītu swintlint.

Tipa drošs resurss

Es izmantoju R.swift, lai droši pārvaldītu resursus. Tas var ģenerēt klases, kas ir drošas tipam, lai piekļūtu fontam, lokalizējamām virknēm un krāsām. Ikreiz, kad mainām resursu failu nosaukumus, netiešas avārijas vietā tiek iegūtas kompilācijas kļūdas. Tas neļauj mums secināt par resursiem, kas tiek aktīvi izmantoti.

imageView.image = R.image.notFound ()

Parādiet man kodu

Iedziļināsimies kodā, sākot ar modeli, plūsmas kontrolieriem un servisa klasēm.

Modeļa izstrāde

Tas var likties garlaicīgi, taču klienti ir tikai jaukāks veids, kā pārstāvēt API reakciju. Modelis, iespējams, ir visvienkāršākā lieta, un mēs to ļoti daudz izmantojam lietotnē. Tam ir tik svarīga loma, taču var būt dažas acīmredzamas kļūdas saistībā ar nepareizi izveidotiem modeļiem un pieņēmumi par modeļa parsēšanu, kas jāņem vērā.

Mums vajadzētu pārbaudīt katru lietotnes modeli. Ideālā gadījumā mums ir nepieciešama automātiska modeļu pārbaude no API atbildēm gadījumā, ja modelis ir mainījies no aizmugures.

Sākot no Swift 4.0, mēs varam pielāgot savu modeli Codable, lai varētu viegli veikt sērijas izveidošanu uz un no JSON. Mūsu modelim jābūt nemainīgam:

struct Recipe: Covable {
  ļaujiet izdevējam: String
  ļaujiet URL: URL
  let sourceUrl: stīga
  let id: stīga
  let nosaukums: Stīga
  let imageUrl: stīga
  ļaujiet socialRank: Double
  ļaujiet publisherUrl: URL
enum CodingKeys: stīgas, CodingKey {
    lietu izdevējs
    lietas url = "f2f_url"
    case sourceUrl = "source_url"
    case id = "receptes_id"
    lietas nosaukums
    case imageUrl = "image_url"
    case socialRank = "social_rank"
    case publisherUrl = "publisher_url"
  }
}

Mēs varam izmantot dažus testa ietvarus, ja jums patīk izdomāta sintakse vai RSpec stils. Dažās trešo pušu pārbaudes shēmās var būt problēmas. Es uzskatu, ka XCTest ir pietiekami labs.

importēt XCTest
@testable importa receptes
klases RecipesTests: XCTestCase {
  func testParsing () iemet {
    let json: [stīga: jebkura] = [
      "izdevējs": "Divi zirņi un viņu pāksts",
      "f2f_url": "http://food2fork.com/view/975e33",
      "nosaukums": "Cepumi bez šokolādes zemesriekstu sviesta cepeškrāsnī",
      "source_url": "http://www.twopeasandtheirpod.com/no-bake-chocolate-peanut-butter-pretzel-cookies/",
      "receptes_id": "975e33",
      "image_url": "http://static.food2fork.com/NoBakeChocolatePeanutButterPretzelCookies44147.jpg",
      "social_rank": 99.99999999999974,
      "publisher_url": "http://www.twopeasandtheirpod.com"
    ]
ļaujiet datiem = izmēģiniet JSONSerialization.data (withJSONObject: json, options: [])
    let decoder = JSONDecoder ()
    ļaujiet receptei = izmēģiniet decoder.decode (Recipe. Self, no: data)
XCTAssertEqual (recepte.title "Cepumi bez šokolādes zemesriekstu sviesta cepeškrāsnī")
    XCTAssertEqual (recepte.id, "975e33")
    XCTAssertEqual (recepte.url, URL (virkne: "http://food2fork.com/view/975e33")!)
  }
}

Labāka navigācija, izmantojot FlowController

Iepriekš projektos kā maršrutēšanas motoru izmantoju kompasu, taču laika gaitā esmu atklājis, ka arī vienkārša maršrutēšanas koda rakstīšana darbojas.

FlowController tiek izmantots, lai pārvaldītu daudzus ar UIViewController saistītos komponentus kopējai funkcijai. Jūs varat izlasīt FlowController un Coordinator par citiem lietošanas gadījumiem un iegūt labāku izpratni.

Ir AppFlowController, kas pārvalda rootViewController mainīšanu. Pagaidām tas sāk RecipeFlowController.

logs = UIWindow (rāmis: UIScreen.main.bounds)
logs? .rootViewController = appFlowController
logs? .makeKeyAndVisible ()
appFlowController.start ()

RecipeFlowController pārvalda (patiesībā tas ir) UINavigationController, kas apstrādā HomeViewController, RecipesDetailViewController, SafariViewController.

pēdējā klase RecipeFlowController: UINavigationController {
  /// Sāciet plūsmu
  func start () {
    let service = RecipesService (tīklošana: NetworkService ())
    ļaujiet kontrolierim = HomeViewController (recipesService: service)
    viewControllers = [kontrolieris]
    kontrolieris. atlasiet = {[vāja sevis] recepte
      sevi? .startDetail (recepte: recepte)
    }
  }
privāts func startDetail (recepte: recepte) {}
  privāts func startWeb (URL: URL) {}
}

UIViewController var izmantot deleģējumu vai slēgšanu, lai paziņotu FlowController par izmaiņām vai nākamajiem plūsmas ekrāniem. Delegātam var būt nepieciešams pārbaudīt, vai ir divi vienas klases gadījumi. Šeit mēs izmantojam aizvēršanu vienkāršībai.

Automātiskais izkārtojums

Automātiskais izkārtojums pastāv jau kopš iOS 5, katru gadu tas kļūst labāks. Lai gan dažiem cilvēkiem joprojām ir problēmas ar to, galvenokārt tāpēc, ka tiek sajaukti ierobežojumi un veiktspēja, taču personīgi es uzskatu, ka automātiskais izkārtojums ir pietiekami labs.

Cik vien iespējams, es cenšos izmantot automātisko izkārtojumu, lai izveidotu adaptīvu lietotāja saskarni. Mēs varam izmantot tādas bibliotēkas kā Anchors, lai veiktu deklaratīvu un ātru automātisko izkārtojumu. Tomēr šajā lietotnē mēs izmantosim tikai NSLayoutAnchor, jo tas ir izveidots no iOS 9. Tālāk esošo kodu iedvesmojis ierobežojums. Atcerieties, ka automātiskais izkārtojums visvienkāršākajā formā ietver translatesAutoresizingMaskIntoConstraints pārslēgšanu un isActive ierobežojumu aktivizēšanu.

paplašinājums NSLayoutConstraint {
  statiskās funkcijas aktivizēšana (_ ierobežojumi: [NSLayoutConstraint]) {
    constraints.forEach {
      (USD 0.firsItem as? UIView)? TranslatesAutoresizingMaskIntoConstraints = false
      $ 0.isActive = true
    }
  }
}

GitHub faktiski ir pieejami arī daudzi citi izkārtojumu motori. Lai iegūtu priekšstatu par to, kurš no tiem būtu piemērots lietošanai, apskatiet LayoutFrameworkBenchmark.

Arhitektūra

Arhitektūra, iespējams, ir visvairāk apspriesta un apspriesta tēma. Esmu arhitektu izpētes cienītājs. Šeit varat apskatīt vairāk ziņas un ietvarus par dažādām arhitektūrām.

Manuprāt, visas arhitektūras un modeļi nosaka katra objekta lomas un to, kā tās savienot. Atcerieties šos arhitektūras izvēles pamatprincipus:

  • iekapsulē to, kas mainās
  • dod priekšroku kompozīcijai pār mantojumu
  • programmu saskarnei, nevis ieviešanai

Pēc spēles ar daudzām dažādām arhitektūrām, ar Rx un bez tā, es uzzināju, ka vienkāršs MVC ir pietiekami labs. Šajā vienkāršajā projektā ir tikai UIViewController ar loģiku, kas iekausta palīgu apkalpošanas klasēs,

Masīvs skata kontrolieris

Jūs, iespējams, esat dzirdējuši cilvēkus jokodamies par to, cik masīvs ir UIViewController, taču patiesībā nav masīva skata kontroliera. Mēs vienkārši rakstām sliktu kodu. Tomēr ir veidi, kā to samazināt.

Lietotnē Receptes, kuru izmantoju,

  • Pakalpojums injekcijas veikšanai skata kontrollerī viena uzdevuma veikšanai
  • Vispārējs skats, lai skatu pārvietotu un kontrolētu deklarāciju uz slāni Skats
  • Bērnu skata kontrolieris, lai komponētu bērnu skatu kontrolierus, lai izveidotu vairāk funkciju

Šeit ir ļoti labs raksts ar 8 padomiem, kā notievēt lielos kontrolierus.

Piekļuves kontrole

SWIFT dokumentācijā minēts, ka “piekļuves kontrole ierobežo piekļuvi jūsu koda daļām no koda citos avota failos un moduļos. Šī funkcija ļauj jums paslēpt sava koda ieviešanas datus un norādīt vēlamo saskarni, caur kuru šim kodam var piekļūt un to izmantot. ”

Pēc noklusējuma visam vajadzētu būt privātam un galīgam. Tas arī palīdz kompilatoram. Ieraugot publisku īpašumu, mums tas jāmeklē visā projektā, pirms mēs ar to kaut ko turpinām. Ja īpašums tiek izmantots tikai klases ietvaros, padarot to privātu, tas nozīmē, ka mums nav jārūpējas, ja tas sabojājas citur.

Ja iespējams, reklamējiet īpašības kā galīgas.

beigu klase HomeViewController: UIViewController {}

Paziņojiet īpašumus par privātiem vai vismaz privātiem (iestatītiem).

pēdējā klase RecipeDetailView: UIView {
  privāts let scrollableView = ScrollableView ()
  privāts (noteikts) slinks var imageView: UIImageView = self.makeImageView ()
}

Slinks īpašības

Īpašumiem, kuriem var piekļūt vēlāk, mēs tos varam pasludināt par slinkiem un ātri izmantojamiem slēgšanas darbiem.

pēdējā klase RecipeCell: UICollectionViewCell {
  privāts (noteikts) slinks var konteinera skats: UIView = {
    let view = UIView ()
    view.clipsToBounds = patiess
    view.layer.cornerRadius = 5
    view.backgroundColor = Color.main.withAlphaComponent (0.4)
atgriešanās skats
  } ()
}

Mēs varam izmantot arī funkcijas make, ja mēs plānojam to pašu funkciju atkārtoti izmantot vairākiem īpašumiem.

pēdējā klase RecipeDetailView: UIView {
  privāts (noteikts) slinks var imageView: UIImageView = self.makeImageView ()
privāta funkcija makeImageView () -> UIImageView {
    let imageView = UIImageView ()
    imageView.contentMode = .scaleAspectFill
    imageView.clipsToBounds = patiess
    atgriezt attēluView
  }
}

Tas atbilst arī Strive for Fluent Usage ieteikumiem.

Rūpnīcas metožu nosaukumus sāciet ar “make”, piemēram, x.makeIterator ().

Kodu fragmenti

Daži koda sintakse ir grūti atcerēties. Apsveriet iespēju izmantot koda fragmentus, lai automātiski ģenerētu kodu. To atbalsta Xcode, un šo tehnoloģiju demonstrēšanas laikā Apple inženieri dod priekšroku.

ja #pieejams (iOS 11, *) {
  viewController.navigationItem.searchController = searchController
  viewController.navigationItem.hidesSearchBarWhenScrolling = false
} cits {
  viewController.navigationItem.titleView = searchController.searchBar
}

Es izdarīju repo ar dažiem noderīgiem Swift fragmentiem, kurus daudziem patīk izmantot.

Tīklošana

Tīklošana Swift ir sava veida atrisināta problēma. Ir sarežģīti un kļūdaini uzdevumi, piemēram, HTTP atbilžu parsēšana, pieprasījuma rindu apstrāde, parametru vaicājumu apstrāde. Esmu redzējis kļūdas par PATCH pieprasījumiem, mazo burtu HTTP metodēm ... Mēs varam izmantot tikai Alamofire. Šeit nav jātērē laiks.

Šai lietotnei, jo tā ir vienkārša un lai izvairītos no nevajadzīgām atkarībām. Mēs varam tieši izmantot URLSession. Resursā parasti ir URL, ceļš, parametri un HTTP metode.

struct Resurss {
  ļaujiet URL: URL
  let ceļš: stīgu?
  ļaujiet httpMethod: String
  ļaujiet parametriem: [virkne: stīga]
}

Vienkāršs tīkla pakalpojums var tikai parsēt Resursu uz URLRequest un liek URLSession izpildīt

pēdējā klase NetworkService: tīklošana {
  @ discardableResult func fetch (resurss: Resurss, pabeigšana: @escaping (Data?) -> Void) -> URLSessionTask? {
    aizsargs ļauj pieprasīt = makeRequest (resurss: resurss) else {
      pabeigšana (nulle)
      atgriešanās nulle
    }
let task = session.dataTask (ar: pieprasījums, pabeigšanas pārvaldnieks: {dati, _, kļūda
      sargs ļaujiet datiem = dati, kļūda == vēl nav {
        pabeigšana (nulle)
        atgriezties
      }
pabeigšana (dati)
    })
task.resume ()
    atgriešanās uzdevums
  }
}

Izmantojiet atkarības injekciju. Ļaut zvanītājam norādīt URLSessionConfiguration. Šeit mēs izmantojam noklusējuma parametru Swift, lai nodrošinātu visizplatītāko opciju.

init (konfigurācija: URLSessionConfiguration = URLSessionConfiguration.default) {
  self.session = URLSession (konfigurācija: konfigurācija)
}

Es izmantoju arī URLQueryItem, kas bija no iOS 8. Tas padara parsēšanas parametrus vienumu vaicāšanai jauku un mazāk garlaicīgu.

Kā pārbaudīt tīkla kodu

Mēs varam izmantot URLProtocol un URLCache, lai pievienotu spraugu tīkla atbildēm, vai arī mēs varam izmantot ietvarus, piemēram, Mockingjay, kas swizzles URLSessionConfiguration.

Es pats labprātāk izmantoju protokolu testa veikšanai. Izmantojot protokolu, tests var radīt izspēles pieprasījumu, lai sniegtu nepilnīgu atbildi.

protokolu tīklošana {
  @ discardableResult func fetch (resurss: Resurss, pabeigšana: @escaping (Data?) -> Void) -> URLSessionTask?
}
pēdējā klase MockNetworkService: tīklošana {
  let dati: Dati
  init (faila nosaukums: virkne) {
    let saišķis = Pakete (priekš: MockNetworkService.self)
    ļaujiet url = saišķis.url (forResource: fileName, withExtension: "json")!
    self.data = mēģiniet! Dati (satursOr: URL)
  }
func fetch (resurss: Resurss, pabeigšana: @escaping (Dati?) -> Nederīgs) -> URLSessionTask? {
    pabeigšana (dati)
    atgriešanās nulle
  }
}

Kešatmiņas ieviešana bezsaistes atbalstam

Es mēdzu dot ieguldījumu un izmantot bibliotēku ar nosaukumu Cache. Mums no labas kešatmiņas bibliotēkas ir nepieciešama atmiņa un diska kešatmiņa, ātra piekļuve atmiņai, noturība - disks. Kad mēs saglabājam, mēs saglabājam gan atmiņā, gan diskā. Ielādējot, ja atmiņas kešatmiņa neizdodas, mēs ielādējamies no diska, pēc tam vēlreiz atjauninot atmiņu. Ir daudz sarežģītu tēmu par kešatmiņu, piemēram, iztīrīšana, derīguma termiņš, piekļuves biežums. Lasiet par viņiem šeit.

Šajā vienkāršajā lietotnē pietiek ar pašmāju kešatmiņas apkalpošanas klasi un labu veidu, kā uzzināt, kā darbojas kešatmiņa. Viss, kas atrodas programmā Swift, var tikt pārveidots par datiem, tāpēc mēs varam tikai saglabāt datus kešatmiņā. Swift 4 Covable var serializēt objektu uz Data.

Zemāk esošais kods parāda, kā lietot FileManager diska kešatmiņai.

/// Saglabājiet un ielādējiet datus atmiņā un diska kešatmiņā
pēdējā klase CacheService {
/// Lai iegūtu vai ielādētu datus atmiņā
  privātā atmiņa = NSCache  ()
/// Ceļa URL, kurā ir kešatmiņā saglabāti faili (mp3 un attēlu faili)
  private let diskPath: URL
/// Faila vai direktorija pārbaudei ir norādīts ceļš
  privāts let fileManager: FileManager
/// Pārliecinieties, ka visas operācijas tiek veiktas sērijveidā
  private let serialQueue = DispatchQueue (apzīmējums: "Receptes")
init (fileManager: FileManager = FileManager.default) {
    self.fileManager = failu pārvaldnieks
    darīt {
      let documentDirectory = izmēģināt failuManager.url (
        priekš: .documentDirectory,
        iekš: .userDomainMask,
        piemērotsPar: nulle,
        radīt: patiess
      )
      diskPath = documentDirectory.apppingPathComponent ("Receptes")
      izmēģiniet createDirectoryIfNeeded ()
    } noķert {
      fatāla kļūda()
    }
  }
func save (dati: Dati, atslēga: Stīga, pabeigšana: (() -> Void)? = nulle) {
    let atslēga = MD5 (atslēga)
serialQueue.async {
      self.memory.setObject (dati kā NSData, forKey: atslēga kā NSString)
      darīt {
        izmēģiniet data.write (uz: self.filePath (atslēga: atslēga))
        pabeigšana? ()
      } noķert {
        drukāt (kļūda)
      }
    }
  }
}

Lai izvairītos no nepareizi veidotiem un ļoti gariem failu nosaukumiem, mēs tos varam sajaukt. Es izmantoju MD5 no SwiftHash, kas vienkāršu lietojumu dod mirušajam taustiņam = MD5 (atslēga).

Kā pārbaudīt kešatmiņu

Tā kā kešatmiņas operācijas es plānoju būt asinhronas, mums jāizmanto testa gaidas. Atcerieties pirms katra testa atiestatīt stāvokli, lai iepriekšējais testa stāvoklis netraucētu pašreizējam testam. Gaidījums XCTestCase padara asinhrona koda pārbaudi vieglāku nekā jebkad agrāk.

klases CacheServiceTests: XCTestCase {
  let service = CacheService ()
ignorēt func setUp () {
    super.setUp ()
pamēģināt? service.clear ()
  }
func testClear () {
    ļaujiet gaidīt = pašsaprotamība (apraksts: #funkcija)
    let string = "Sveika pasaule"
    ļaujiet datiem = string.data (izmantojot: .utf8)!
service.save (dati: dati, atslēga: "atslēga", aizpildīšana: {
      pamēģināt? self.service.clear ()
      self.service.load (atslēga: "atslēga", aizpildīšana: {
        XCTAssertNil (0 USD)
        gaidīšana.pilda ()
      })
    })
gaidīt (par: [gaidīšana], noildze: 1)
  }
}

Attālo attēlu ielāde

Es arī piedalos Imaginary, tāpēc es mazliet zinu, kā tas darbojas. Attālajiem attēliem mums tas ir jālejuplādē un kešatmiņā, un kešatmiņas atslēga parasti ir attālinātā attēla URL.

Izmantojot mūsu recepšu lietotni, izveidosim vienkāršu ImageService, pamatojoties uz mūsu NetworkService un CacheService. Būtībā attēls ir tikai tīkla resurss, kuru mēs lejupielādējam un saglabājam kešatmiņā. Mēs dodam priekšroku kompozīcijai, tāpēc ImageService iekļausim NetworkService un CacheService.

/// Pārbaudiet vietējo kešatmiņu un atnest attālo attēlu
pēdējā klase ImageService {
private let networkService: tīklošana
  privātā cacheService: CacheService
  privāts var uzdevums: URLSessionTask?
init (networkService: Networking, cacheService: CacheService) {
    self.networkService = networkService
    self.cacheService = cacheService
  }
}

Mums parasti ir UICollectionViewand UITableView šūnas ar UIImageView. Un, tā kā šūnas tiek izmantotas atkārtoti, pirms jauna pieprasījuma sastādīšanas mums ir jāatceļ visi esošie pieprasījuma uzdevumi.

func fetch (URL: URL, aizpildīšana: @escaping (UIImage?) -> Void) {
  // Atcelt esošo uzdevumu, ja tāds ir
  uzdevums? .atcelt ()
// Mēģiniet ielādēt no kešatmiņas
  cacheService.load (atslēga: url.absoluteString, pabeigšana: {[vājš sevis] cachedData in
    ja dati = cachedData, let image = UIImage (dati: dati) {
      DispatchQueue.main.async {
        pabeigšana (attēls)
      }
    } cits {
      // Mēģiniet pieprasīt no tīkla
      ļaujiet resursam = Resurss (URL: URL)
      self? .task = self? .networkService.fetch (resurss: resurss, pabeigšana: {networkData in
        ja let data = networkData, let image = UIImage (dati: dati) {
          // Saglabāt kešatmiņā
          self? .cacheService.save (dati: dati, atslēga: url.absoluteString)
          DispatchQueue.main.async {
            pabeigšana (attēls)
          }
        } cits {
          print ("Kļūda, ielādējot attēlu vietnē \ (URL)")
        }
      })
sevi? .uzdevums? .resume ()
    }
  })
}

Attēla ielādi padarot ērtāku UIImageView

Pievienosim UIImageView paplašinājumu, lai no URL iestatītu attālo attēlu. Es izmantoju saistīto objektu, lai saglabātu šo ImageService un atceltu vecos pieprasījumus. Mēs labi izmantojam saistīto objektu, lai pievienotu ImageService UIImageView. Punkts ir atcelt pašreizējo pieprasījumu, kad pieprasījums tiek atkārtoti aktivizēts. Tas ir parocīgi, ja attēlu skati tiek atveidoti ritināšanas sarakstā.

paplašinājums UIImageView {
  func setImage (URL: URL, vietturis: UIImage? = nulle) {
    ja imageService == nulle {
      imageService = ImageService (networkService: NetworkService (), cacheService: CacheService ())
    }
self.image = vietturis
    lejupielādēt. (vietrādis URL, pabeigšana: {[vājš sevis] attēls iekš
      sevis? .attēls = attēls
    })
  }
privāts var imageService: ImageService? {
    gūt {
      atgriezt objc_getAssociatedObject (self, & AssociateKey.imageService) kā? ImageService
    }
    iestatīt {
      objc_setAssociatedObject (
        sevi,
        & AssociateKey.imageService,
        newValue,
        objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC
      )
    }
  }
}

Vispārējs datu avots UITableView un UICollectionView

Mēs izmantojam UITableView un UICollectionView gandrīz katrā lietotnē un gandrīz vienu un to pašu veicam atkārtoti.

  • parādiet atsvaidzināšanas kontroli iekraušanas laikā
  • datu ielādes saraksts
  • parādīt kļūdu neveiksmes gadījumā.

Ap UITableView un UICollection ir daudz aptinumu. Katrs no tiem pievieno vēl vienu abstrakcijas slāni, kas dod mums lielāku jaudu, bet vienlaikus piemēro ierobežojumus.

Šajā lietotnē es izmantoju adapteri, lai iegūtu vispārīgu datu avotu, lai veiktu tipa drošu kolekciju. Jo galu galā viss, kas mums nepieciešams, ir kartēt no modeļa uz šūnām.

Balstoties uz šo ideju, es izmantoju arī augšupējo posmu. UITableView un UICollectionView ir grūti apņemt, jo reižu tas ir specifisks lietotnei, tāpēc pietiek ar plānu aptinumu, piemēram, Adapter.

pēdējās klases adapteris : NSObject,
UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
  var vienības: [T] = []
  var konfigurēt: ((T, šūna) -> Void)?
  var izvēlēties: ((T) -> Void)?
  var cellHeight: CGFloat = 60
}

Kontrolieris un skats

Es ieskicēju Storyboard daudzu ierobežojumu un daudzu problēmu dēļ. Tā vietā es izmantoju kodu, lai izveidotu skatus un definētu ierobežojumus. Tas nav tik grūti ievērot. Lielākā daļa UIViewController katlu kodu ir domāti skatu izveidošanai un izkārtojuma konfigurēšanai. Pārcelsim tos uz skatu. Jūs varat lasīt vairāk par to šeit.

/// Izmanto, lai atdalītu kontrolieri no skata
klases BaseController : UIViewController {
  ļaujiet saknei = T ()
ignorēt func loadView () {
    skats = sakne
  }
}
pēdējā klase RecipeDetailViewController: BaseController  {}

Darbs ar bērniem ar skatu kontrolieri

Skats kontroliera konteiners ir jaudīga koncepcija. Katram skatu kontrolierim ir atšķirīgas problēmas, un to var izveidot kopā, lai izveidotu uzlabotas funkcijas. Es esmu izmantojis RecipeListViewController, lai pārvaldītu UICollectionView un parādītu recepšu sarakstu.

pēdējā klase RecipeListViewController: UIViewController {
  privāta (komplekta) var kolekcijaView: UICollectionView!
  let adapter = Adapteris  ()
  private let emptyView = EmptyView (teksts: "Nav atrasta neviena recepte!")
}

Ir HomeViewController, kas iegulst šo RecipeListViewController

/// Parādiet recepšu sarakstu
beigu klase HomeViewController: UIViewController {
/// Kad recepte tiek atlasīta
  var izvēlēties: ((Recipe) -> Void)?
privāts var refreshControl = UIRefreshControl ()
  privāti ļauj receptēmService: RecipesService
  privāti ļaujiet meklētKomponents: Meklētkomponents
  privāti ļaujiet recepteListViewController = RecipeListViewController ()
}

Sastāvs un atkarības injekcija

Es cenšos veidot komponentus un sastādīt kodu, kad vien varu. Mēs redzam, ka ImageService izmanto NetworkService un CacheService, bet RecipeDetailViewController izmanto Recipe and RecipesService

Ideālā gadījumā objektiem pašiem nevajadzētu radīt atkarības. Atkarības jāizveido ārpusē un jāpāriet no saknes. Mūsu lietotnē sakne ir AppDelegate un AppFlowController, tāpēc atkarībām jāsākas no šejienes.

Lietotņu transporta drošība

Kopš operētājsistēmas iOS 9 visām lietotnēm ir jāpieņem lietotņu transporta drošība

Lietotņu transporta drošība (ATS) ievieš labāko praksi drošos savienojumos starp lietotni un tās aizmuguri. ATS novērš nejaušu atklāšanu, nodrošina drošu noklusējuma uzvedību un ir viegli lietojams; tas pēc noklusējuma ir ieslēgts arī operētājsistēmās iOS 9 un OS X v10.11. Jums vajadzētu pieņemt ATS pēc iespējas ātrāk, neatkarīgi no tā, vai veidojat jaunu lietotni vai atjaunināt esošo.

Mūsu lietotnē daži attēli tiek iegūti, izmantojot HTTP savienojumu. Mums tas ir jāizslēdz no drošības noteikumiem, bet tikai šim domēnam.

 NSAppTransportSecurity 

   NSExceptionDomains 
  
     food2fork.com 
    
       NSIncludesSubdomains 
      
       NSExceptionAllowsInsecureHTTPLoads 
      
    
  

Pielāgots ritināms skats

Detaļu ekrānā mēs varam izmantot UITableView un UICollectionView ar dažādiem šūnu tipiem. Šeit skatam jābūt statiskam. Mēs varam sakraut, izmantojot UIStackView. Lai iegūtu lielāku elastību, mēs vienkārši varam izmantot UIScrollView.

/// Vertikāli izkārtots skats, izmantojot automātisko izkārtojumu UIScrollView
pēdējā klase ScrollableView: UIView {
  privāts let scrollView = UIScrollView ()
  privāts let contentView = UIView ()
ignorēt init (kadrs: CGRect) {
    super.init (rāmis: rāmis)
scrollView.showsHorizontalScrollIndicator = nepatiess
    scrollView.alwaysBounceHorizontal = false
    addSubview (ritināšanas skats)
scrollView.addSubview (contentView)
NSLayoutConstraint.activate ([
      scrollView.topAnchor.constraint (vienāds ar To: topAnchor),
      scrollView.bottomAnchor.constraint (vienāds ar To: bottomAnchor),
      scrollView.leftAnchor.constraint (vienāds ar To: leftAnchor),
      scrollView.rightAnchor.constraint (vienāds ar To: rightAnchor),
contentView.topAnchor.constraint (vienāds ar To: scrollView.topAnchor),
      contentView.bottomAnchor.constraint (vienāds ar To: scrollView.bottomAnchor),
      contentView.leftAnchor.constraint (vienāds ar To: leftAnchor),
      contentView.rightAnchor.constraint (vienāds ar To: rightAnchor)
    ])
  }
}

Mēs piestiprinām UIScrollView līdz malām. Mēs piespraužam ContentView kreiso un labo enkuru sev, vienlaikus piestiprinot ContentView augšējo un apakšējo enkuru UIScrollView.

Skatījumiem, kas atrodas satura skatījumā, ir augšējie un apakšējie ierobežojumi, tāpēc, paplašinoties, tie paplašina arī saturuView. UIScrollView izmanto automātiskā izkārtojuma informāciju no šī satura skatījuma, lai noteiktu tās satura lielumu. Šeit ir parādīts, kā ScrollableView tiek izmantots RecipeDetailView.

scrollableView.setup (pāri: [
  ScrollableView.Pair (skats: imageView, ievietots: UIEdgeInsets (augšā: 8, pa kreisi: 0, apakšā: 0, pa labi: 0)),
  ScrollableView.Pair (skats: ingredientHeaderView, ievietots: UIEdgeInsets (augšā: 8, pa kreisi: 0, apakšā: 0, pa labi: 0)),
  ScrollableView.Pair (skats: ingredientLabel, iesprausts: UIEdgeInsets (augšā: 4, pa kreisi: 8, apakšā: 0, pa labi: 0)),
  ScrollableView.Pair (skats: infoHeaderView, ievietots: UIEdgeInsets (augšā: 4, pa kreisi: 0, apakšā: 0, pa labi: 0)),
  ScrollableView.Pair (skats: norādīšanas poga, iesprausts: UIEdgeInsets (augšā: 8, pa kreisi: 20, apakšā: 0, pa labi: 20)),
  ScrollableView.Pair (skats: oriģināla poga, iesprausts: UIEdgeInsets (augšā: 8, pa kreisi: 20, apakšā: 0, pa labi: 20)),
  ScrollableView.Pair (skats: infoView, ievietots: UIEdgeInsets (augšā: 16, pa kreisi: 0, apakšā: 20, pa labi: 0))
])

Meklēšanas funkcionalitātes pievienošana

Sākot no iOS 8, mēs varam izmantot UISearchController, lai iegūtu meklēšanas noklusējuma pieredzi ar meklēšanas joslu un rezultātu kontrolieri. Meklēšanas funkcijās iekapsulēsim SearchComponent, lai to varētu pievienot.

beigu klase SearchComponent: NSObject, UISearchResultsUpdating, UISearchBarDelegate {
  ļaujiet recipesService: RecipesService
  ļaujiet searchController: UISearchController
  let recepListViewController = RecipeListViewController ()
}

Sākot ar iOS 11, UINavigationItem ir īpašums ar nosaukumu searchController, kas atvieglo meklēšanas joslas parādīšanu navigācijas joslā.

func add (to viewController: UIViewController) {
  ja #pieejams (iOS 11, *) {
    viewController.navigationItem.searchController = searchController
    viewController.navigationItem.hidesSearchBarWhenScrolling = false
  } cits {
    viewController.navigationItem.titleView = searchController.searchBar
  }
viewController.definesPresentationContext = true
}

Šajā lietotnē mums šobrīd ir jāatspējo hidesNavigationBarDuringPresentation, jo tas ir diezgan buggy. Cerams, ka tas tiks atrisināts turpmākajos iOS atjauninājumos.

Prezentācijas konteksta izpratne

Prezentācijas konteksta izpratne ir būtiska skatu kontroliera prezentācijai. Meklēšanā mēs izmantojam meklētājuResultsController.

self.searchController = UISSearchController (searchResultsController: recipesListViewController)

Avota skata kontrollerī (skata kontrolleris, kurā mēs pievienojam meklēšanas joslu) ir jāizmanto definesPresentationContext. Bez tā mēs meklēšanasResultsController tiek parādīts pa visu ekrānu !!!

Ja skata kontroliera attēlošanai izmanto stilu currentContext vai overCurrentContext, šis īpašums kontrolē to, kuru skata kontroliera hierarhijā esošo skata kontrolieri faktiski satur jaunais saturs. Kad notiek uz kontekstu balstīta prezentācija, UIKit sākas ar pašreizējo skatu kontrolieri un iziet skatu kontroliera hierarhiju. Ja tas atrod skatu kontrolieri, kura šī īpašuma vērtība ir patiesa, tas lūdz šim skatu kontrolierim uzrādīt jauno skata kontrolieri. Ja neviens skatu kontrolieris nenosaka prezentācijas kontekstu, UIKit lūdz loga saknes skata kontrolieri rīkoties ar prezentāciju.
Šī īpašuma noklusējuma vērtība ir nepatiesa. Daži sistēmas nodrošinātie skatu kontrolieri, piemēram, UINavigationController, maina noklusējuma vērtību uz true.

Atteikšanās no meklēšanas darbībām

Mums nevajadzētu izpildīt meklēšanas pieprasījumus par katru taustiņu sitienu, kuru lietotājs ievada meklēšanas joslā. Tāpēc ir nepieciešama kaut kāda veida droseļvārsta darbība. Mēs varam izmantot DispatchWorkItem, lai iekapsulētu darbību un nosūtītu to rindā. Vēlāk mēs to varam atcelt.

beigu klases debitants {
  privātā atļauja: TimeInterval
  privāts var workItem: DispatchWorkItem?
init (kavēšanās: TimeInterval) {
    self.delay = kavēšanās
  }
/// Pēc nelielas kavēšanās iedarbiniet darbību
  func grafiks (darbība: @escaping () -> Void) {
    workItem? .cancel ()
    workItem = DispatchWorkItem (bloks: darbība)
    DispatchQueue.main.asyncAfter (termiņš: .now () + kavēšanās, izpildiet: workItem!)
  }
}

Pārbaudes noņemšana ar apgrieztām cerībām

Lai pārbaudītu Debouncer, mēs varam izmantot XCTest cerības apgrieztā režīmā. Plašāk par to lasiet sadaļā Asinhronā Swift koda testēšana.

Lai pārbaudītu, vai testēšanas laikā nerodas situācija, izveidojiet cerības, kas tiek izpildītas, kad rodas neparedzēta situācija, un iestatiet tās invertēto īpašumu patiesam. Jūsu tests nekavējoties neizdosies, ja tiks izpildīta apgrieztā cerība.
klases DebouncerTests: XCTestCase {
  func testDebouncing () {
    let cancelExpectation = self.expectation (apraksts: "Atcelt")
    cancelExpectation.isInverted = taisnība
let completeExpectation = self.expectation (apraksts: "pabeigts")
    let debouncer = debouncer (kavēšanās: 0,3)
debouncer.schedule {
      AtceltExpectation.fulfill ()
    }
debouncer.schedule {
      completeExpectation.fulfill ()
    }
pagaidiet (par: [AtceltExpectation, completeExpectation], noildze: 1)
  }
}

Lietotāja saskarnes pārbaude ar UITest

Dažreiz maza reakcija var radīt lielu efektu. Pēc izslēgtas pogas pēc tam var tikt izveidoti nelietojami ekrāni. UITest palīdz nodrošināt lietotnes integritāti un funkcionālos aspektus. Pārbaudei jābūt deklaratīvai. Mēs varam izmantot robota modeli.

klases receptesUITests: XCTestCase {
  var lietotne: XCUIApieteikums!
  ignorēt func setUp () {
    super.setUp ()
    turpinātAfterFailure = nepatiesi
    lietotne = XCUIApieteikums ()
  }
  func testScrolling () {
    app.launch ()
    ļaujiet collectionView = app.collectionViews.element (piesaistītsBy: 0)
    collectionView.swipeUp ()
    collectionView.swipeUp ()
  }
  func testGoToDetail () {
    app.launch ()
    ļaujiet collectionView = app.collectionViews.element (piesaistītsBy: 0)
    let firstCell = collectionView.cells.element (robežains: 0)
    firstCell.tap ()
  }
}

Šeit ir daži no maniem rakstiem par testēšanu.

  • UITests palaišana ar Facebook pieteikšanos iOS
  • Pārbaude ātri, izmantojot modeli “Ņemot vērā, kad tad”

Galvenā vītnes aizsargs

Piekļuve lietotāja saskarnei no fona rindas var izraisīt iespējamās problēmas. Agrāk man vajadzēja izmantot MainThreadGuard, tagad, kad Xcode 9 ir galvenā pavediena pārbaudītājs, es to vienkārši ieslēdzu Xcode.

Galvenais pavedienu pārbaudītājs ir savrups rīks Swift un C valodām, kas fona pavedienā nosaka AppKit, UIKit un citu API nederīgu izmantošanu. UI atjaunināšana pavedienos, kas nav galvenie pavedieni, ir izplatīta kļūda, kas var izraisīt nepareizu lietotāja interfeisa atjaunināšanu, vizuālus defektus, datu bojājumus un avārijas.

Izrāžu un jautājumu mērīšana

Mēs varam izmantot instrumentus, lai rūpīgi profilētu lietotni. Ātrai mērīšanai mēs varam doties uz cilni Debug Navigator un skatīt CPU, atmiņas un tīkla izmantošanu. Iepazīstieties ar šo atdzist rakstu, lai uzzinātu vairāk par instrumentiem.

Prototipēšana ar rotaļu laukumu

Rotaļu laukums ir ieteicams veids, kā izveidot un veidot lietotnes. WWDC 2018 Apple iepazīstināja ar Create ML, kas atbalsta Playground, lai apmācītu modeli. Iepazīstieties ar šo atdzist rakstu, lai uzzinātu vairāk par rotaļu laukuma attīstību Swift.

Kurp doties tālāk no šejienes

Paldies, ka esat tik tālu nokļuvuši. Es ceru, ka esat iemācījies kaut ko noderīgu. Labākais veids, kā kaut ko iemācīties, ir vienkārši to izdarīt. Ja jūs atkal un atkal rakstāt vienu un to pašu kodu, izveidojiet to kā sastāvdaļu. Ja problēma sagādā grūtības, rakstiet par to. Dalieties pieredzē ar visu pasauli, jūs daudz uzzināsit.

Es iesaku izlasīt rakstu Labākās vietas, kur apgūt iOS attīstību, lai uzzinātu vairāk par iOS attīstību.

Ja jums ir kādi jautājumi, komentāri vai atsauksmes, neaizmirstiet tos pievienot komentāros. Un, ja šis raksts jums šķita noderīgs, neaizmirstiet aplaudēt.

Ja jums patīk šī ziņa, apsveriet iespēju apmeklēt citus manus rakstus un lietotnes