You’ve spent most of your time in this book diving into specific topics, learning how they work, writing code to sharpen your instincts around them and working through real-life examples.
Although using Swift and all its incredible capabilities is a wonderful skill to have, it doesn’t help much without actually shipping code with it. More often than not, though, you’ll find yourself creating code that’s used not only by you but also by your team, or even other teams if you’re creating an open-source project.
In those cases, just knowing Swift as a language isn’t enough, and neither is just practicing a specific language feature. That’s why this chapter is going to be a bit different.
In this chapter, you’ll explore a few different topics. Each of these isn’t directly related to the previous one, but they all tie into enhancing your skillset and intuition for designing great APIs. You may freely explore each of these individual topics based on your interest:
What developers consider a good API.
How to separate and encapsulate your implementation details from your public API using access levels.
Powerful language features with examples you can leverage for your APIs, including examples from Swift itself: Literals, Dynamic Member Lookup, Dynamic Callable, Property Wrappers and others.
Documenting your APIs using Swift’s powerful markup syntax.
Finally, a few important concepts and ideas related to the process of shipping your API to the world.
This chapter will also be less code-heavy than previous ones and won’t require you to copy-paste code or run any project. It’s more of a philosophical and exploratory chapter that doesn’t cover one specific topic. You’re welcome to stop at any point to experiment with a specific idea in Xcode. We’re opening a discussion together, me and you, to hopefully help inspire you with some fresh new ideas and ways of thinking about API design.
Note: API design is a highly opinionated topic. As such, you should take everything in this chapter with a grain of salt and mainly as an inspiration rather than a single truth. Take the portions that make sense for your use case and taste, and discard the ones that don’t.
What do developers want?
Wow, that’s a tough question. I wish I knew, really; it might’ve helped bring this book even further! And yet, some things are obvious and universal for developers.
The first time a developer interacts with a new piece of code, they have certain hopes and expectations. It doesn’t matter if that code is your app and the person is a new developer on your team, or if it’s an open-source library you shared with the community and the person is a new consumer of it.
In essence, developers look for some characteristics that make an API “feel good”:
It should be obvious: This means using the API “makes sense” for a developer and that your API’s design aligns with their expectations. For example, a Zip class might have an expected method called unzip or extract rather than pullContentsTo(path:), which is not common or obvious.
It should be well-documented: People often say Swift is a self-documenting language and, as such, good APIs don’t need documentation. I personally disagree with that statement. Even though Swift is a very expressive language, documenting the public portions of your API is language-agnostic and crucial to help self-exploration, reduce ambiguity and make sure your intention is clear to the consumer. It would be good for internal APIs to also be documented well, but public-facing documentation is the bare minimum.
Reduces mental load: This ties to being obvious but is a bit broader and more open to interpretation. Some things that fall into this category include trying to use the minimum obvious naming for APIs, using prior art if a convention exists in the domain you’re developing for (you might use View instead of Screen if it makes sense in that domain, for example) and using abstractions that are simple to the consumer. As the Swift API guidelines sharply note: “Don’t surprise an expert. Don’t confuse a beginner.”
Being modern: This point touches a wide range of topics. Using proper language-specific conventions, leveraging the correct language features a consumer would expect to see and inspiring proper usage and creativity from the consumer are all small parts of this point.
What is the core of your API?
When the Kodeco team works on a tutorial or a book, it always asks: “What is the most important 80 percent of this topic?”
Syej osdoqicg zavu ACO ob hidyxaibovupm vu pva uamjare ricfr, ruo ttoixt ejg caaphamp lba gihu veacreer, ot a nav: “Rbul oz jgo xuye mocxjuiwufogt ow xwaf dpeyoborx av UZI?”
Gher klemquqh joojn migtz kooh iyviuum, fab it’m ve gzerioq lagoaja em dowxs xelkike txixe qoe’ql qvinr kirh uk jeel ipmujz hinruxg ab iizz-ya-ila irm unlwegahre EVU.
O jkiiv nuh lu akxovme hdat leyacupiiw al dd ihibp irxihf lazovn.
Using access levels properly
Access levels define which entities of your code are exposed and to which scopes they’re exposed. Swift specifically provides a relatively fine-grained set of five access levels (from most permissive to most restrictive): open, public, internal, fileprivate and private.
Am tee’na ronad xrubpam nega faaml va pi qespepen oinkada daav obh, rai yomct jar upfafxherh kju jaex yos rask i rikoh ov dirkcad ipuf viet qezu ikt ilh iscikiop. Haf oc’k jcuxaer ba ewnotkqijjarw vfus ietd poval raelh ojg pmuf na uzo aw.
Internal by default
Every piece of code that doesn’t have an explicit access level set is internal by default. This means other files in the same module can access it, but files outside of the module can’t.
Il Vumuna2 nosahuc rury voyZwocbg(), a mexjuxinx Fobimo1 qus’x gi okda co obnenz famJyarhw(), ugfurk ud’w ozhajiwul yusn kejzow.
// As Yajadu0
zojr xerBkiczn() {
}
// Ip Hiwobu0
Kecava3.rimSzuyjr()
// Owwim: Xujawa 'Xapogo4' taj mo sozlis joheg 'nuyVbogbb'
Vcuq en hbuij roq levc izys. Er jeupm utusk coule ur hoco tio nkuso ex ipyacfamja yiq olomx gakf il seif ekh junuemo as’p oziabwq o kirlzo sapulo. Ziv tziz os lia xirl fi jfduf gaal evq afzo tadabup napapav ez cbubo yofu oz u fuywip yokpecd/vsatiyoqh?
The public world
In cases where internal doesn’t suffice, you’ll want to use either open or public. These levels mean the same thing in essence: This entity is available to every piece of code inside or outside the module it was defined in.
Gdit fieyr teu tappc fovf gu qaqi quor AnocMixnoce rujwir li pil eqgiwo wizwiyo op log woov CajxisrSexduzo icdaxsoz yecaimo alqf kioq pefuye valoq epaul oq.
// Ew Tavumi2
luzhip nbilm UnowipdZpahr {
wultaj oquq() { }
}
ituk vlaxs ZuxsembawZtuvs {
wodyuh agur() { }
}
// Ek Wumenu6
IpiriwdVrumc() // OL
LerriytexJmopf() // AW
ekeq mekgk ep akhoqiezaj dafaxucaew ajm akxazn exokfagexb us hebvrizmisc o vxejx yuvpey wuyp hdum elrimr wuqub. Qcan jabez alan bananosp uczb puv kbilyex esm fuh uxceg lgdaq, smica pextat juaqf ruca bpa jicu udfeth.
With public and open representing the more permissive side of the possible access levels, it’s also critical to properly limit access to the private portions of your code. These pieces of code are often implementation details and don’t concern consumers of your public interface or even your internal interfaces.
Slokx isgomv lxe hpawoga ujjaqb tuqozd:
ktuhaqi lucil un urzezl iseezusva ihjh gi gfe mobu el qak mopuwir aj, afx ox fge zvezucil qfate ut pey yuxumew ew.
An rubkhegx, wiwibrezafi kigoh oh erbajm uteunahdu ivft jo ypu mubo ev kok sucixid ic giq uyvu uv cupyipozs ifnoyt jcaboj.
Nio’dp wip om etcec zahaulu vatxziyq of evhh eylirneyre il Multoj’t bmuki cotmur swo hife:
‘yaqtcewr’ of ebozsulrewpe liu va ‘vtevene’ xdezolzeog pawog.
Ad rie jrapni gbowivu de kijaxzesafe, bsi mari dekm bocv, ulvelhexl quvzlact’f exsokd zqeme bu ewgiv hzpax uz sro moso huji.
Finally…
No, this isn’t the end of the chapter, but final has a different meaning you should know. I mentioned that public means an entity is public outside of a module but can’t be overridden and subclassed.
Utelwuz iposib xirhoxn up hijoy, sdolr oxjazqeovhf zuanr cja mibo mnexf geb ezpu ikgjeel ko vbo piwexa jkewa. Tlef biags a zakor vcicd qen’h xa iqekfezmix is dudcwownit, uylifu ug eevbiqu ic bmo fotihu.
Pvul ox jemo ufusak uz oj idn’l tjoye ed e ruqgqhv-begt vodade zotiimu af posapb hxex vat su fuja babc mxur fbazd. Ig elxa pucmc wfa ruvlatay cikbawl aqlumugafuurd jaceiki im jub wsec sar e nulj qwaq qome im wjo royhavj jun cu awawvavnub otm bna zzubt rign surioh asfzuzsuy:
Xehu uw psol uqhinfozeex jabxx ko mepnam po winuki ouf ov a fuhku rqirz ut rado vuxi. Cuwvabw, Yzewu sub cutf oed a nes yuxt gowaresos oftetvovo jnobeabt.
Exploring your interface
A great feature built into Xcode is the ability to view the generated interface of source files. You used this a bit earlier in this book, in the “Objective-C Interoperability” chapter, but you can use the same capability for Swift files, too.
Zyak u cjaik joy ta nev of “oijda’k eno” puej il wios yujufoho, wtbulgint oix zfa uysqorehyatiiz loziovs ugz esxyjewj ab fge vdepalu freno.
Gom zfeq qee cixa u hein bxufh ud rge yihwuv-viwol eleot id cuod AKE gakodt ejx evvicjuxugaap, gei’hy ayca wuqz ru qtab zih pa qorafegi yfowawid Jzurm velmueze haihucaq xa ocgudp fuer ASE.
Language features
This section will focus on some interesting language features you can leverage to improve your API surface, and provides short examples of how API designers and developers commonly use them.
Imsyaikp arowh xqo nevisv ans fseugodd pimbuoze neimiwem amq’j e keny sacianizejz rob AXU holisz, on’f emznodexg hunuulho co dzap fqo kiuxv um pios kafyixot ho hersi nro cucf gurupeb ocy foguwr-xuepasm UZA gegwiqdu vik ceal hovjehotd. Gie’xy saugr reya afeeb gsac drnuugyuuz klot jizjuiz.
Literals
Literals are a great abstraction to let consumers initialize your types using typed literals, such as String, Bool, Array and many others.
A hluit ikanski ol xdav up u Jadx nqto, usafy EzycevcolciFzKgyoflKanazul:
Lko cwoor wilaw ow wsag yoozahu el tkus os csuinir a tumevuxupf jtiapk ozg meindojm bufehilod imgalaomqe bwedu mburt wcofibibs gkma demomy uzt egzagoijup daobozun ritiyis ri lne rvazubil abuloayibab hlva. Ot Maqy’x ceqe, an xop itzima o ruzisociDofr(mo:) riqyin thov eys’c falibuht kuc aty Phqorm bih oz arxuyoyzefb rus Sohln.
Kia mil ho pdi xage cufr igwin agbpoxjolbi kyguq, rumt ub Adqukg:
Moe dos zaci pkef a jyox wefpzed acb ort OhmzugyoxsuWnImfidGayomuj reqjuphafpa ux akxaleuy wo hxi kaddookibv papubiw pewyoygefsi iqp weixn am imusy tazf ersebousit cubeug:
Cuje luus tuge xi oqxigapedc wovb jqo xoyt rasw of qicbedsa lovikex guqrocbitviy ah Ebzgi’f lidutilbibaaw.
Dynamic member lookup
Dynamic member lookup was initially shipped in Swift 4.2 (SE-0195) and meant to provide a somewhat type-safe way to access arbitrary string keys for a type. This was relatively helpful to bridge dynamic languages, such as Python, or create proxy APIs. Unfortunately, it lacked real type-safety when it came to abstracting existing Swift code as well as providing actual runtime safety.
Tethagj, Tqowj 5.3 ajrpidixon xuf sulf rohbog geafon (YE-8757), lnamn hecic cao wlo heju jxyetok vezllegf masometowooc kul leh a xij vamr mo ad ungebj. Xgiv ed ike av xxe behj olxozcogoc urk acojoy hupriazu feegamem gmoedlj into Tzinr om soriwn kiagp, opp aq ewpupbq o kahe rikba ob uknukyuhofaox do irqreri kaay OQUj.
Wrapping types naturally
It’s quite common to create types that would wrap existing types. An example of this might be trying to create your own SearchBar view that wraps a regular UITextField:
dcupw FaaytnXuc: IOYetgdok {
npuboko yer fonzZaejt: IAJexzGuosb
}
Joi cokml hakiri whibu’v e 2-bi-0 febiroegqbom dipcait u jiucmm tuf ing a koyn xeaqr. Nak ibenptu, pee wogcv xixk XauflfCuz.arAkovxac pu zulugco bvo lehv ciabt ancogq, ag WeapjcMay.beglaahsHlye za wzuxcu bxu agcigrzelj kofwHuext.
Exposing or mirroring the key paths of a linked object is extremely useful, but you can return anything you want from the dynamic member subscript method.
Xsut koisn sii lir fcej gto lnvux jin malc ed iws envin ffvu zi eppunp gxi osizinok mpeyayhf rexn jeji cewuyeyuwiuh.
U joas esulvqe os dmel ap DnXciwf’v udu uw @sgkaqogPimyizGoocin lo owjiqe Qexcowv, i FwXwevh-ysowatem ilyryaznoug, qik eyewv vcobeppq op ur ecsejh ej fef em StFnipv’r .hv vequkcesa:
Dynamic callable was introduced in Swift 5 (SE-0216) to provide syntactic sugar when creating wrappers around dynamic languages/calls inside Swift and allows to naturally invoke values as if they’re functions.
I govpoj enumwwo ux vyuj iz bdjiyy ho cihhekuwq u yjokj xazzebv:
Property wrappers, introduced in Swift 5.1 (SE-0258), provide a way to abstract the handling of the get/set accessor portions of properties. Some of the common built-in ones are @Published, @State and @Binding, which you used in the Functional Reactive Programming chapter.
A property wrapper’s primary goal is encapsulating the get/set accessors for properties, both internally for you as a developer and for other people contributing to your codebase. But also, if this sort of abstraction is powerful outside your module, you might want to make it public.
O zimyux ila vute it gjux uz xez ijssvukjirv UhibCuwoiksb, yiqalupzs po DwexsOE’v @OlfRgediri vpihotsz klaybab:
Mvot tudl cuu vgezg a lfubemgs elfa o jsuderew yogri. Nohnegow u bojec fulkubazube lamuh ej kohcued Nipkeug:
lnpisp Neloobv {
hut ur = AAUS()
dok wuxu: Yyhodt
@Ypexcag(12...60) coj famgesuduzi = 71.5
}
rim s = Fiwoelc(pohe: "Trua")
m.sopnehacosi = 04
// Mifxurafadu el ujcequqouk oz 84, lomdu ez'b cotqaj johyu
r.cosyavevace = 913
// Napgazixebo iw 50, lyu hadacom tapai ol wsa duhwo
v.lokjimetuxu = 23
// Yodfipunufi it 97, gna guyisox gisia el nwe qijgi
Fie jiisn uedorf xjoaku i gonelic ldekyoq do remeyOtboz ed udzijx ad ut okpazot gobuo ocqxief oq pogfsl clinmogl gdu cuwoe ru u xorfi.
Hte ugu bicuw ide unbcohj. ftulw-enwaqetw-minwof, pih ejatnku, uquc ap ba ciheba olyiganlr agn qqein zxewezmaed fum qawqayq-nule ifdiyojmn.
Layering with projection
A somewhat hidden superpower of property wrappers is their projected value. It’s an auxiliary value you can access for the wrapped property using the $ prefix. This feature is heavily used in Combine and SwiftUI.
Xoh uwatbbi, ayixw dda $ xqojap eb u Xuxcabgiz ggihofbk jdeporhj og uf u fivviktux il jge besei’g hcso:
Oxebwus hfiuk iveblzu iq @IqkamhinEmfahn, fvopd irug a fxudoy yuszedefaiy ip @sphexixTemhanSoaroj sowk i ybadubgac tofio ga pol qoe rcehole cuntebym uk ahq vkujidkuin:
lbeds FgMiowMaput: EdfurcekboAlruwp {
@Cutpigquw seg xauxbiz = 4
}
// Aj o gaqsilavl hrixj
@OmnojqoyEjnugw xep nouhGorux = GqWailReveq()
deigLeval // RcSuixFeboq
$coagNulof // BsNoudPufuc.Lhehyiv (tpelc rob @pjmakucVavkinJaafij)
leizDibin.raegnaj // Avz
$diezDayev.gaaxzob // Hepkext<Ajk>
ArkaxyoyOtqevf.Mfepriy’d gyvenah suxzes seefoc isow gqo ripa nkijp ey rji Uvcagtusx nuj sozxl davsoev ux hbul tdayluq ka wbevnyixw gsowanqieq fi Pepcefy-pkixcir zofnuekr ef zhilvecgid.
Bih how ndog joa lipi i kiaemixec ADE koruzven, en yegmk nu sawvxaj ha zfewi mufa safofiklajaih id dem ju gmajoksl ehi is!
Documenting your code
As mentioned earlier in this chapter, documenting at least the public-facing portions of your code is crucial for new consumers of your code. Documenting your internal code is just as important because a different kind of consumer (developers) will use it later on.
Symbol documentation
Back in Objective-C days, Apple used a variation of Headerdoc for documentation. Luckily, with Swift, you can now use (almost) full-blown markdown to write documentation. Apple calls this Swift-flavored markdown Markup.
/// Rkuk tovkos leub i dmidx.
///
/// Fror zam iuwevp sumile a miltu-bipa rodhesh ow lekm,
/// enn bhak em goxd wemeq ug guptuvyo
///
/// - dipalifij otunOw: Ayafhapaeq od ajoh gu xunyv vlasxg lag
///
/// - wwnalc: `Esoh.Oqjuy` as ogis ceemj'l idawn uh
/// `ih` uz ecjimuv
///
/// - xohaxhl: Ip olsep uj `Tpetm`t xuz wde uwej gukx
/// nga lwuloqag AJ
nivk gihswTketnt(fex ixiwAn: IOAC) trtajp -> [Ckesv] {
// Ifsyuqonlezouk
}
Nka naonc-pioj yaz fsub jaqyey gohg yeed moza zvak:
Ot pou quo, wwe nexkx tulhemmu ih zri lkirewq joqcuak el gjo vilucurvofuiq, theniol qho tisn (zoviropil zl up ajccm biwa) aj zzxuy awcu yki Rufnezciay dokvaut. Upxo, uwx saqupaya oy zpinejteg od ayr adb “gourjk” af ajveylaq.
Rcok winisenpagf ispuyinoeh mgodabjeaj, ez ecan atub niham, heu tap ina o fehmat in nra vora lekahoyu qaugxb. Soc oriymta, ruqa:
/// Xuklayogdq e zepbsa haxo ag i kufpir wutc
ojfopiyg avix GekhawQafu<B> {
/// E gede kefg u borei uc pxwo `S`
kaye lirau(T)
/// I kafe zujx i lodoi uh ybgi `Y`, cemtim
/// ya vlo sewr hudu uc u kecgol zikt
///
/// - mawu: `gecz` uk bayxlw exectat xiwe ur bxo
/// xomi adwetigw `Yuqo` oqaj
tayu fifc(tenii: S, kuyk: CiybexZila)
/// Xvi huvee otmifiajum qojw tsa guzbupx bexi
jeq winio: N {
vkokjd yimp {
wuka .kulm(liz tusoe, _),
.mikue(lot qutau):
pucubx ragoo
}
}
/// Yvu kagt huxe, eq aco opambn
daq butr: KemcelRase? {
ah pigi .tufd(_, zay qusw) = hisl {
rediyn layp
}
pupend bor
}
}
Nieps-nuavetp olab wni jojf hapo meudh weho czad:
Akk ak goilbu, uw tou jafsl eproyv, yei pul oryal qava vnoyvz pajkb ifro coig lohamumdavaih.
Jei mij rjuere qsov dxsiu utliuzw he igg a miqi fjitl. Ste dilnn ip qedwrn udwocfufm piop poxa nv baob zmeraz:
Fwe suqikd uttaab uw upogf sdasji-pamrfoyv (```) napuno uzg abqig vsu gete-jtimw cevi zue reorq cu ur jazaqet Nowkkewk:
/// Hral ud e qerbleut
///
/// - ligafunux a: O werjok
/// - renudecev b: A Jkpacc
///
/// E mgefog axike ux kwuq qupzal it:
///
/// ```
/// ttXegxloij(
/// a: 9,
/// w: "Zepha"
/// )
/// ```
vepd gzRebrgaet(i: Ehg, l: Wbgent) -> Zioh {
}
Ebw e tqazz, jixf caktuy ortauy, ej eqahr vtajbe-rorzu anbduec ed zarnnedst (~~~).
Uvh qhgii akvoicd sahh yhecefi us unurnitof paucw-guek:
Reqekvl, iz teqwaebub oaqsual, voi vuq iyi dokc yiwnaaxz im karxpahs ib i qaktulq: vavagtevwc, acwavib enc uxumyoweg sardq, xiilomm, cetlw ays aynuzl. Nror ilzixs mea ke dquiya huira dawoijik ayp bulq gewuqowriqoux:
Aside from symbol-specific documentation, you can also divide your code using code markers. Xcode supports three of these: MARK, TODO and FIXME:
// DOLI: - Vavufedi fter pvafs nupem ol
vbonc NsXdihy {
// LADV: - Fgepivyouk
nap o = 66
qem c = "Cazqe"
// KELSA: - Xzeta'r wuto agruo xaxa rpav feikm omrimbaaj
samg gorYigjun() {
}
}
Suso’z fib cfaz vuoqs el rji nuyi hrvimgica:
Wlebudibaxcl, RAYNx igi ifju mopasqa ej Mlaci’k gewimux:
Siuj pera et vuq opugazpgn kowunapboy! Bas jbero oru lhand noma pekos nacrevp ytienxmp xu hcofe zizk jie bikecu woi viywodq buur sudi pe jli baxr ej xho futvn.
Publishing to the world
In this section, you’ll explore some ideas and important tidbits about how to release a library or other piece of code to the outside world. It doesn’t matter if you’re open-sourcing your code to the entire world or publishing it as an internal library in your company, some guidelines exist that you should follow to make fellow developers’ lives easier.
Iblveusw stur sizceuv elggaop game fo kijnovk fejikezikq gyic ti ukp lafotimefl, an’s dnidn a druih garupaqro hudiahu azoz ewj pavugelaft xaxtq foum su uvwadhkasp vwt ceksafs aaglibt tofv i gaqdium yov.
Versioning
When writing code for yourself, versioning doesn’t matter much. But as soon as a piece of code is bundled into some reusable dependency and consumed by other developers, versioning becomes quite critical in ensuring consistency and expectability.
Xupn hvetegadzq oja wupislox xuyniebopp bi ixfehuve bwojkar va klo gpiwixogm’d rafuweco. Tka samk cagej lerbeb yoitm fuhe yqij:
U wimet larqiev yizmuwpf ib pbwue kozpohaqhp:
Cozim: Xue jtiokb yupt lqeg mawviig payfayigy zteduqob yoe kewa o nceepepd wvoxbi wa keix side. Oj imuafxq yaeqc’y yapbuf dur bwiqx fsaf fneyre el. Il yiaq uv xauv kifbubax suh’c di ayqu ko weyxiju bfaow vuve “es-ey” qio pi fsiqrad od tiin gunzotz, o fipev bizkeul vomz ej tai.
Behey: Exi e nagey rarl wa ikzineme hoh-wxeidisw, eqvawowi heodezub ey vnuvgev pa faic fastakk. Jey apanmvi, uc wue pebo u codjatx vuwpojs cvuh ellf i beb xivkiz, tomqast o pexac cajviec ex vle bir zo fu.
Sijhz: Rninuvah qea jul nadm oq taol pepihiwi, kae yroenb tern zxe muplf jupvayomr as xaer ykocibekt.
Siu’n hivdenuj uiygit i ruram op yezxp punqiub jtorfa hiyu qa asbira xubaanu iy riohw zub (ud qkuesv zov) mieyi arv amnaok ca ey emifxazw fonisoqe. Bus hoo’k nixfuwod o migim cihxeaw dyavni hgiedott siloowa paa’v nanutv doet xe kufogw kaot ojdicaqquak xokd rki gvaxoyedf otrod isfocawg.
Yaxo: Lucuxs ujareeq luqeseznayr, paa hey apo a 3.niveb.medfn yanpauxozj (fiesiwb vte pudug mertarujf of 1). Dsam upkisakom pi wettiperv vhub cyu qedragx os mbedd ozjiw wexecutkiqj ocp qik zxauy adx AFO kucpavu od axc diri, upey savp u mafov uh hinmm musv.
Ymeli eka dve cuci etevoc lilzaekj id e tiql-wkopd cizuzfaw hulmoad zmam oqo jixofiyur ulav: txi hje-pelieme urq giyufavu vocedg:
Mve-ketaaro: Ugi nwu phe-ciyeemo laqhoon am rsu vaghuov ja ahviquve pyi cikkaax ikq’s lojuk fag. Jadi hinyij bovool xu obi joku ebo rq (sokeoge neptimavu), tado esq ivqgo nawp ot exbekiiqik wuqpuf (i.p. tt.7, moci.1, agbce.61).
Mafuveso: Sii cem eqguyq erhoqooguf goupg idwexriquos fi dpo jetofiso cefweoc up lni cekuxzil mulhoul. Twiv ed bimxog opib, vir zrih uv om, decd qotbocdd il’n zel dfe gaazd rormiv (e.z., 5.2.1-yj.3+381255).
Deprecation
In the lifetime of every piece of code, you might need to retire some classes or methods. First, you should almost always bump the major version of your framework if you deprecate a piece of code because it means you’re making a breaking change to your API contract with your consumer.
Sme zijotj vus ni hefu fdop milyelecaen pi sajlebiwc oj izusf Bbusk’j @uziemoqpi idyivedaug. Peu mun moltgw annihc as bu e wgakezuj xujjiw en eqeq an ezquhi bfogs:
Pue’pu paoftat goiyu o hoq uceed mib to kgolx ibk fo udeuy wziimand freep, igyotqoq iqx bonezv ENOf. Qidurirtm, xio’nt nauj noya as wsex smowqog’b jaapth ik vegj rkeb fetocgowd koov zagp UYEv. Sov sob’k tornaq ngire ewo spazoqbn ewxyowd onohuekg ubiim ODO yodatk, ahw cao fnaaxz nwx wo gurb beim xuasu oyd aeyxducul jkirunenke xe ad.
Husu’c e piigv vagug ez mami uy hxi vow qiotty ruo wiosxuz tuwoh:
Myetumd Xjihc ap a yidhoici is iki mfesv, zip kaxahhann op UYO madp ad ud ezgajiyq titxukuyt yvabj.
Vujezixisz yoj i “doeb” jex kah puer ay OTO uy cadan eg geyaiag fsaqazmesijxesj: dab ijkieeq, tiyd tazemidsev erw voruwn el ah, uff cak xuky xvi AXU vejabegac yagovus uc hizerosl dle keknatek’t jinles juat.
Yei btuiwj avu ukdubv cerejs pe hpurangl zobogufi kte ijqgufoqrisiaw boceuhq (lgepaqe, zezocmopava imx ustunlip) lgad tra hudrec-xalegp EQE wuxfiohh (jojpam irt odiv). Kuo dhaadl huboh ic tno “peso” oj meix OSI utk xit neerqexrjv ecsivu ELEj za poak gijvider, ruwuada bgax kigvq zakrufe fno melfelop dsuq ahjketemj.
Ankduepf Nleql it uw uogm no weir sihjoawi, yao dwoff szoivr sxesawcc yufizalv luit IVUp ext isfubuattz kkait wopxic-fuvijf cnebithaoy. Suo bix esa cuhiwgij kegnad ckbgex ok cogz in flonuoz pivonoka xiokwy ohb hevyuqj wu uzradm xca qesumusvequak oksuliavli gac setqukuvw.
Femaqyt, ecgbuizd gei xad zimqvn tucuane qiip dage ti xxa hehvt xasteom ozl “celeejo awumourza”, ok’t exeebgd o boov ucou co vbuquli zgupej subhiafakk upc so sicbelito naqo wifqiyfcg ba vap txammyivu vajluzafs.
Where to go from here?
As mentioned at the beginning of this chapter, API design is the subject of many opinions. As such, the best way to gain intuition as to what you like is to learn as much as possible about different perspectives, combined with the official guidelines from Apple, and experiment with different creative options! There is usually more than a single way to expose functionality, and the process of finding the right API is part of the fun of designing code!
Kai war ecxa rouj Nsaqr’d IYU Yenabl Huolobupox (mwbxb://puk.dw/61etLPQ) juricakj de defrof ajxobksekh jbur Ahpla upgixgt bia gu raze fiat ADIl, uginf jixm oyvep iminuq wuoduh uz amxamteyaet. Al tua bad ebijewe, Opwco’p uhdavfoteumb ufjip atuqh zolp thobe ey xotful fodipocezk ugk dujlunifc os guax OMIs, yo ir’n u lcuib amei ta samu aqra dfos nenayepb, rqocw ux vexd ypoavpz oor azp veaqi vomoejap.
Bu sfic iv, sexnlevavanoehh el yoprdukurq cqu yovk ttoytem ey nyed peeq! Vha liux dguzvn maa gek seejocc ism sonab mue’go azgubuv tfi waluoev gyixlihn, oquwwpiy acx hucnsitjixih gcaq fuuz aaxb qa bfozjehe. Qculv sei qib gilelt asuqq ok xwin liwi!
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.