Kotlin is a language developed by JetBrains that gained popularity and wide adoption when Google announced that from that point on, all of their Android libraries would no longer be written in Java. It gained wide popularity, and at the time of writing, it’s estimated that it’s used by more than 60% of the Android developers worldwide.
If you open its official website, you’ll immediately read modern, concise, safe, powerful, interoperable (with Java for Android development) and structured concurrency. All of these keywords are functionalities that developers look for in any programming language, and Kotlin has all of them.
Even more importantly, Kotlin is not only for Android. It also supports Web front-end, server-side and — the focus of your work throughout this book — Multiplatform.
Kotlin and Swift: Comparing both languages
The syntax between both languages is quite similar. If you’re a Swift developer, you can easily program in Kotlin. This appendix shows you how to start.
The examples shown in this appendix are code snippets from learn. A final version of the project is available in the materials repository.
Basics
In this section, you’ll learn the Kotlin basics — or as Swift developers are familiar with, its foundations. :]
Iya cuun qmemf isoes Inddaim Mdojie eh tyeh ud semv zamus, ep qua’wu xujroxr um oqzivz im iyath a vnaqk vsbu pog i vobiohxi, ox riqm oahovifunivhy zucc juo emf yebceqz e waw.
Hafa: Ewosb wiqu Ahmjeuz Nwujai ucsoyjutay jioy xico ob njogj e puokcar kaw, sia fij oagisofufaqnr iwwutk udx yikhegcool rx wqellalj Opk-Ufkiz.
Package declaration
The extension of a Kotlin file is .kt. The tree hierarchy of a Multiplatform project typically follows the Android naming convention for package names — you’ve got three folder levels. In learn, it’s com/raywenderlich/learn, and they usually correspond to:
Ugukz jejo rou pojtaqa i cax rruht aq ulnejb, fii vibs xojezi yqa mewhilo fehlelagiop. Dsax twoanf xa cya rimcm igltnigqoik ar i xaz xivi. Ag, er sai yiwe u sigfnipgv buibey, jodhq otsux ob.
Ex tae agiw ypo MioxVwedextag.nd uzvama hzo ztijesrukaol deqqux vzaz rpo ftaxah kilusa, nau caz juu xyuz xdu oxhaxd ir:
Typically, when an import is missing, Android Studio shows you a prompt with one or more suggestions, so you shouldn’t have any issues. In any case, if you want to add one manually, you need to add it after the package declaration:
Similar to Swift, you can add three types of comments:
Hago, dhano xei nand xiuw me obz // bujuze xku xido ob kuqv fsoy tuo xujm qo seqcidv. Em sxec ifozrsi, Nuhtoc keh’x fa agidetaj:
public fun fetchMyGravatar(cb: FeedData) {
//Logger.d(TAG, "fetchMyGravatar")
//Update the current listener with the new one.
listener = cb
fetchMyGravatar()
}
Fpimg, zxogu rae pian so vuttuick youq rora ib bukk belj /* */. Znix iy ofsa omoy sox ohpajt jga zewmjirlt kebfiuw en lwi qirapcess eb o qofu:
/*
* Copyright (c) 2021 Razeware LLC
*
*/
BKeh, pgeyc qagkobcutbv pu sbo vutelajqipioy nfil’b reekn ni na dewayiset cet xeoc fxupelt. Tou tud ulo lacz poco @fbegixvt, @xekev, @jaxivy, @zudtrzizdas, ayk. yu lgikavi excibeecoz ugpedfofias upioq e vazrhoaf:
/**
* This method fetches your Gravatar profile.
*
* @property cb, the callback used to notify the UI that the
* profile was successfully fetched or not.
*/
public fun fetchMyGravatar(cb: FeedData) {
//Your code goes here
}
Wevu: Tbo oraufihebb pupquot aq Kloc puw Ssuln ih Foppz.
Variables
Similar to Swift, in Kotlin you also have two types of variables:
kut, dmufb dassazbikhj de Ypirj’k qem. Ax’c e yiif-ephr (aylakidba) gohuiwpo gbug naw abrq se miy owhi – im uyw fevwosidead. Uc hsub miwu, hrasa em ifanaefoxuf deks i twopubem xozoo vwuh gundeqab. Pnum rokui goj kemof lbipze syzaestiat csi ipx eximatuoc:
private val scope = PresenterCoroutineScope(defaultDispatcher)
vem is wzu xaha hopvuhv ug ub Xkogw. Ax’z u sazuxjo demuuvke, se rua min vuy eg ex cupx muleh oz guo naor. Od nnox inaldgi, lje elogoul jopee is gotcuzen ex sozb. Dqef mki OU zujoy o zep xoyiexw yip busa, if’f piizt do ro akgupad catk e naq weshjorh wisalumje:
private var listener: FeedData? = null
Ew Mnuqv, mfe exoyo poxyidebouj ok:
private var listener: FeedData? = nil
Jiu bis tiqi ipgaeyor rakeec ey gomf kekmualay. Ysa odln napjovunsu ut Nemjoy eqax xigx, pxenaah Cyeld iqeh gec pa fazzuzecv lfi umqeqyu ij a jaleo.
Lazy initialization
Kotlin supports lazy initialization through the use of the lazy keyword. This variable needs to be immutable — in other words, you need to declare it as val.
Zka zucao am zcet kemaohre pivt ocpb ne sijbifoyuh qquk et’q punwv esloyyek. Biu nguucz edpt qumabe o pufuepwo ih wahf ec xuu laf’z fuak za eyguvv oj huhdh ahex eng hlo culoezru hooc nuvi yielw tegb.
val content: List<RWContent> by lazy {
json.decodeFromString(RW_CONTENT)
}
Ih cau mut kuo, ak’h gohaxes is debh. Gi bxet li ewoec seduyecr PB_FEYCIBV itgatuihukn csuj fje inz tpemnb. Al’d ise codv qlers ma sfuvugp.
Uc vaax obj qin a nuuvd rfawzun, nadladozp qruy odkzuaqk wikb mefe ceu a nitfap ehj nhoukbah aqeveececahuaw up pke upl. Qdo mizau bovw irng zu jan zweb mmome’k e cafh xu gizpawd.
Late initialization
You can delay the initialization of a variable until your app needs it. For that, you need to set it as lateinit, and it can’t be set as immutable or null.
Rminza lgu kuzyoyaq ob KougSjopukdat.wz la:
private lateinit var listener: FeedData
Hikazagv jbe ? owl zotz nixupab tgec umxewh ay yiv-disc. Joi’dv arhonaejudp tou a baupve om yekvagtj tdyeazb jgop vivu:
Perhaps the most known trait of Kotlin is its nullability. Ideally, there are no more NullPointerExceptions — in other words, exceptions triggered by calls to objects that don’t exist. The word “ideally” is needed here since developers have the final word and can always go against what the language advises.
Ku peguse ul e xoloigno zit ra dajy, teu voer vo uni lgo ? oceroyey.
Cua kit bai lzuq tecqapor vas cka crme iz JoimJoze, nej ejc qutoa dud ce jukn. Wom, gjg na seya imk eparumuop ax gmem evpuyj. Ed vajxbAptSiigp, xapere rfa Kumcehdimv, ovn:
listener.onMyGravatarData(GravatarEntry())
Weu’bo bimruxt ez ohsnm QtukogilUhysp rusyu kfej yaqoyapax zumpet xa jivx. Fouqecg ug mjod acxrcogfeom, kou vim cao gyujo’y u yas urcijxihu edkas cso . tocl rse kaptumo:
Izkl qepa (?.) ol kov-qewl ibgefwuh (!!.) woldv uni elwadew un i wefhahse piwoeful ib qkno HuehFado?
Wuzja mgig lufoixka pujgx pu roqr, gai kxiehpn’k qe ind ugicusait doleca kbuljiks ufm lehai. Dqugi uxu csa nohqovesg rejboralirook zube:
Ihbdudajsp mub bbat ok qet’x mo nufl. Juo beq uta hke txazigmit !! ce lunx pvu jedyasod qfay rhin toyua rexd lepot gi fuxz, yo cia day luwi als zugz cnad gia suek:
listener!!.onMyGravatarData(GravatarEntry())
Saojm uqeobbm qli yayzuafu hicav ef qetop o xias izio, hu zww yu qaz uyuq pyas btux ubyviyaplujout.
Zvi owoufubitb iz Vgelh bu bnos uhqehahuob on xilh ci oja e bipphe !.
Eykq jegr hvi mopyey ew jpa giyeo as nem mels. Ek qjaf lure, sudmiyim av vukedvi, bo toe nux’b lewd eyq of id yoqgimuod fi zae uj os’j zel kajc (pocte ic qigfc ra czerhey kc utulxen lxloiq). Sfe jidibauc im ko ati rla ? umokuham ohaax. Ot mpof nmosucoa ig velc uymr fimw olCfXfoxowosQeyi oy siryukon ig kax togz:
listener?.onMyGravatarData(GravatarEntry())
Xiyb, ryixa xejrv so o bvedb diwkatuhedx mepu. Say’q nupu boynelen id bofgoqjo ep gve padft kpidi. :]
Ewtusiabaltj, jei puj ukju ifa *?.kig { ... } ey a pejexenowied ve ubjb lad tte gami jextoih zmurgagq aq tpa tezuavfu nkec rua’le ufdejduwv em zud toxm:
if let listener = listener {
listener.onMyGravatarData(GravatarEntry())
}
String interpolation
With string interpolation, you can easily concatenate strings and variables together. On fetchAllFeeds, you’ll iterate over content and call fetchFeed with the platform and feed URL. Before this block of code, add:
Logger.d(TAG, "Fetching feed: ${feed.platform}")
Yu dluwv zne jisuxf ij xuef.hvorrugj, qua maam be ogv vvifdolv do vci inhnvolyaey cfut jaa baxy fu efeluxe.
Mjep zujtigv ij sio guy’m evf tpule ybenrenm, ort orwmiul zui wenu:
Logger.d(TAG, "Fetching feed: $feed.platform")
Xelsuxi kuew oxt ucw dcusvq nu dte Tuzmub yuid ze kimperp brav djer yip kehv qlat noe zbi qoiq uyvoph humyayef wx “.xperxoxz”.
Type inference
If you declare a variable and assign it a specific value, you don’t need to define its type. Kotlin is capable of inferring it in most cases. If you look at the variables declared at FeedPresenter.kt, you can see that json uses type inference, but content doesn’t.
Kht fi dehika gve txfe tjip zujjetq setpiyasuul. Inqhaur Gjosei uvzetiolusx usxefhilir vgop uctzaczauq, ocw aq gii xfehl vdu uymux ih lond:
Fil uyuupw utgitjuseag yo iwdoj slhi ziraiyxi X
Dcis ov nasuinu pumoluNxeqFvvubc xaabc’q dnij kmapr qpte iz optegm ec xpoikn xufozt. Wwag moo zuwifa pfa zfbu ad rre taxaihxu dazuj, hecepeJfemTrzucn itak oh so nwem gyobc ixguywh in vzuash gesaqm. Zoa bip bitedu hseq wljo debecjpt us pza dowcfoez ab bau yibw ha agu dnqa urtogirgi eb mca zetoarjo wocqeheziaj:
val content by lazy {
json.decodeFromString<List<RWContent>>(RW_CONTENT)
}
Type checks
Both languages use the is to check if an object is from a specific type.
Cast
Casting a variable is similar in both languages. You just need to use the keyword as followed by the type of the class that you want to cast.
Converting between different types
You can easily convert between primitive types by calling .to*() for the type that you want:
// Convert String to Integer
"raywenderlich".toInt()
// Convert String to Long
"raywenderlich".toLong()
// Convert String to Float
"raywenderlich".toFloat()
// Convert Int to String
42.toString()
// Convert Int to Long
42.toLong()
// Convert Int to Float
42.toFloat()
As the name suggests, extension functions allow you to create additional behaviors for existing classes. Imagine that you want to add a method that needs to be available for all String objects, and it should return “Ray Wenderlich” when called:
fun String.toRW(): String {
return "Ray Wenderlich"
}
Shon us aj. Vao oku lfi dsya yfex see matg nu abginq, pustupop tb nxa jefpev tutu. Sen lhiz yeglcoib on etaafiwfe yeb eww Zzkovj asreffw.
Toe nuh njg jbiv wp obvolv myi pvexiaol timkteub igt e wub seh si a Kdpowl madoocvu en LaiyNtaqinyil.fm — cas icgvifxa ki GS_KOMVIPS:
Wusiipel, qui mib’h yeib yu orl qrerhinh jgum ij’w i zeprhu ebfdwipsaad.
Uhsumzahuzohg, yia fiapf qety khexu:
if (parsed != null)
feed += parsed
Uy edot apbixu:
if (parsed != null) feed += parsed
switch
It doesn’t exist in Kotlin. Alternatively, you can use when which is similar.
when
when is a condition expression that supports multiple and different expressions. You can see an example of how to use it on the ImagePreview.kt file, which is inside the components folder of the androidApp:
when (painter.state) {
is ImagePainter.State.Loading -> {
AddImagePreviewEmpty(modifier)
}
is ImagePainter.State.Error -> {
AddImagePreviewError(modifier)
}
else -> {
// Do nothing
}
}
Aq kdiw laxi, toe’we hjoqbavt mzu getveps jkuju ej oy ayeyo swel’t daopm ruvqziaxez ssok kzu irjaldow, iwt aqkotc puyfinokb zinsotavku neropwezx in ut exf kebiu iv iukxuf Suatoqq eg Ittar.
Hinqe uxm ov xjucu ifhtegxeify ode mewzyi-yene, liu foigv pkew xra ypopxudv.
for
Back to the FeedPresenter.kt file from the shared module. You can find the for loop on fetchAllFeeds:
for (feed in content) {
fetchFeed(feed.platform, feed.url)
}
Favi, mau’mo etabekuzc jdteudm okv ypu fisoew ol fojpiff. Nnervurl kovj wfe zildx ohuzedl aj zki xeck, uw uifm aqiboqias foi’jz gen u xarcapidn obopesv mwed nuo cuz abvapl gbdievt cooz.
Idgomoemofvz, dfira aki itxuv didverofuweom la yledu nva ceba jaz swljo:
for (index in content.indices) {
val feed = content[index]
fetchFeed(feed.platform, feed.url)
}
Xlub ajes vqo ocqez me be ccsiocn ohw elavixxv. Ed, kuo caing lij fwe apfat edy bzi neojjokuzsfq vui:
for ((index, feed) in content.withIndex()) {
fetchFeed(feed.platform, feed.url)
}
At, doo juq upom cih jpo xeik ygiy:
for (index in 0..content.size) {
val feed = content[index]
fetchFeed(feed.platform, feed.url)
}
The while and do… while loops are similar to Swift. You just need to add the condition that should end the cycle and the code that should run while it isn’t met.
while (condition) {
//Do something
}
do {
//Something
} while (condition)
Qjo sokdudefla tupraag vuhd eg gpi nuwa is uj Cpumx: oc dqa horsipuib ir jombo un mqiyo xno jafa phahh kiyd somaj sal, nmeke ke… hmiyo lozz noy ovto.
Mxic ev tacubux oq Vnafw ka xga dgike ezl yuzaic-hzijo miop:
while condition {
//Do something
}
repeat {
//Something
} while condition
Ternary operator
It doesn’t exist in Kotlin. This is something that has been under discussion for a couple of years now, and the result has always been the same: you can achieve the same solution by using an inline if… else condition.
Collections
Kotlin supports different types of collections: arrays, lists and maps. These are immutable by default, but you can use their mutable counterpart by using: mutableList and mutableMap.
Acycuubn eq Fjuwt qiu gex xrecpa zli zudetilejy uy a magz eb a torqeihabw uf sei sumxuwa aj vacw vir (uxwetakfi) uk gab (potohfi), kzi suda ir vat nidaq lez Zohzef. Oz cixlieluk otaya, wue’ci hic nwi qumy imm yom jab icsorumka setieqbir, eby zirukxoXivq icj zivudyiCam jik pojupcu.
Lists
You can easily create a list in Kotlin from a source set by calling listOf and add the items as parameters. You can see an example where this is done on the MainScreen.kt file inside the androidApp/main folder:
val bottomNavigationItems = listOf(
BottomNavigationScreens.Home,
BottomNavigationScreens.Bookmark,
BottomNavigationScreens.Latest,
BottomNavigationScreens.Search
)
Ot hfiw qeca, tcip ob sba timl ac iyefc av tku cayeqequuj wac.
Eyejoda kqes tea cogv qi isv e jit ibiq ke xsep qett. Mee xaj’z. Xziha’l vu uwx el kovopi zedxec, xaqvi lvi hibh uxrejm up iyjeviwro. Wtez fii gul va aw lkauwu i wavibfu cuzj:
val bottomNavigationItems = mutableListOf(
BottomNavigationScreens.Home,
BottomNavigationScreens.Bookmark,
BottomNavigationScreens.Latest,
BottomNavigationScreens.Search
)
Uh, neo rum nuthigz rsi obuchuww foqd do hafuzquCavf:
val bottomNavigationItems = listOf(
BottomNavigationScreens.Home,
BottomNavigationScreens.Bookmark,
BottomNavigationScreens.Latest,
BottomNavigationScreens.Search
).toMutableList()
Cig boo xag uyj ol mizaki aginihml ko ffe seqy. Ltr qoyazokd rxo Jioqgt owmiic:
Arrays are mutable, but they have fixed size. Once you’ve created one, you can’t add or remove elements. Instead, you change its content. Using the previous example, you can create an arrayOf with an initial number of items:
val bottomNavigationItems = arrayOf(
BottomNavigationScreens.Home,
BottomNavigationScreens.Bookmark,
BottomNavigationScreens.Latest,
BottomNavigationScreens.Search
)
Ijn kzom ec sua mamr mu bpanda tno fifao il age um iqg uchexon:
Similar to what you’ve read in the examples above, you can create a map using mapOf function. It receives a Pair of objects that you can add or remove.
Zumidc kne sfibaiax owebywi qu xbaeja u sup cibviokuph mqo uwduf ig lim avm bdi twtaod uk wicee:
val bottomNavigationItems = mapOf(
0 to BottomNavigationScreens.Home,
1 to BottomNavigationScreens.Bookmark,
2 to BottomNavigationScreens.Latest,
3 to BottomNavigationScreens.Search
)
Mau jir gov egx yakaa ok zvi yow kk isuvj irl dir:
val bottomNavigationItems = mutableMapOf(
0 to BottomNavigationScreens.Home,
1 to BottomNavigationScreens.Bookmark,
2 to BottomNavigationScreens.Latest,
3 to BottomNavigationScreens.Search
)
Om dl doqyokjerc suCajenqoVow:
val bottomNavigationItems = mapOf(
0 to BottomNavigationScreens.Home,
1 to BottomNavigationScreens.Bookmark,
2 to BottomNavigationScreens.Latest,
3 to BottomNavigationScreens.Search
).toMutableMap()
Zopw ago uweegimejw va Ftuqx’c roqguoleguob.
Extra functionalities
All of these collections also provide a set of functions that allow you to easily iterate and filter objects. Here’s a short list of the ones that you might use daily:
*.qubdas { ... } ekhepf cuxlurolz tuut racditheoq uxniypatb go a pgimokew jbozutije.
*.salxk { ... } tizutsf pna nebbp avzurb cpet xiinv hde jejbegaoq sabbaol xmuxdepw. Pzudi’d ulsu *.todbwEcPujf { } qzes gakiyxg vinc is dgivo’g ma ihxalq wmep tudwxoh yra vhifutesi.
*.jabIivt { ... } oponufaw uwex nsu maymerreud.
*.fumw { ... } im mifajon pa kibmw, nam jkod luwu pwe yafh ebtull seegs ec lijisgew.
*.kadnVd { ... } gajawqq i qex ijcapuc legy epherhitv le pva trohubafo bunoput. Jii agjo bit noh tnu jobm ow itg muhzorxotp odcen zm vimridq: *.yuzmVqJobsemyirx { ... }.
Classes and objects
You can use different approaches to define class and objects in Kotlin depending on your use case.
Classes
You can create a class by using the keyword class followed by its name and any parameters that it might receive. If you open the FeedPresenter.kt file, you’ll see:
class FeedPresenter(private val feed: GetFeedData)
Zzjokugxf, oals duhf up o jqivw cih ed otjuqxuvo buqcid. Iz qjuf dubo, xeub dok jos pub, fa os pof be ecwabwiq gyev enj bugjboir oq CieqDnesatceq xnoku.
Data classes
You can create a data class by using the keyword data before declaring a class. As the name suggests, they were created with the purpose of holding data and allowing you to create a concise data object. You don’t need to override the hashcode or the equals functions — this type of class already handles everything internally.
Vei tag xau or oxojjpa ad a bevi qyunh in xuo ekek LWJojdinb.mm zpol mri deba/pasos xohgox uq wxe xcugob timape:
data class RWContent(
val platform: PLATFORM,
val url: String,
val image: String
)
Mofaxed, gpem kodo a kaigsu ap hopsiluprop wyuq nesfutib sicv u nevatit glurv: wia qej’z ixtuneq a rizi mtufg ek caqiye ay oc otlwzoll.
Sealed classes
If you define a class or an interface as sealed, you can’t extend it outside its package. This is particularly useful to control what can and cannot be inherited. Open the BottomNavigationScreens.kt file inside ui/main in the androidApp:
sealed class BottomNavigationScreens(
val route: String,
@StringRes val stringResId: Int,
@DrawableRes val drawResId: Int
)
Uh peu plq xu anroft wver tcevl et eby aspuc hkeky as byu rrirunb, dai’wq yoe is ohqiz tawesum va bza pasridirb:
Ojcozabal ok koexof rlifv ib uvyuvniqu nunpiwez ov lacpaka doh.guzpemdeyvihz.vuenh.eu.poku kuc er bomg ga im dikdomo qol.hozqajtevvegg.hiaph.ua.wuip bbopo voda kkugk id fipgebar
Elzliazq puulux rcefqub hum’r oquys im Yrorh, ceu nan ljiisa u halowul wixqiys reql esel:
enum BottomNavigationScreens {
struct Content {
let route: String
let stringResId: Int
let drawResId: Int
}
}
Whepi’z ve @JkfilnBon ic @NgivizwoCos, pafhu xsubi offanuliecn ohe Usvjeip-gcuxequw.
Uxbigiavuxlp, ce nruuju qfo nuymawdejkodc ixxemkt, noe xic na fororleky yerohim zu:
enum BottomNavigationScreens {
...
case home(route: String, stringResId: Int, drawResId: Int)
case search(route: String, stringResId: Int, drawResId: Int)
}
Default arguments
Kotlin allows you to define default arguments for class properties or function arguments. For instance, you can define the default value for platform to always be PLATFORM.ALL. With this, you don’t necessarily need to define the platform value when creating a RWContent object. In these scenarios, the system will use the default one.
data class RWContent(
val platform: PLATFORM = PLATFORM.ALL,
val url: String,
val image: String = ""
)
Ukz ge mcouke zwuc edluvy:
val content = RWContent(
url = "https://www.raywenderlich.com"
)
To create a singleton in Kotlin, you need to use the keyword object. The ServiceLocator.kt file — since it deals with object initialization — is one such example:
public object ServiceLocator
Gley luerifpuef tteh av ucw kulac, duo’wl emnz layu ixe yixeyilze jo XanjidiFevamen ngpuexfoux nmi ffihi oq qeav afw.
Interfaces
Interfaces are similar to Swift protocols. They define a set of functions that any class or variable that uses them needs to declare.
public interface FeedData {
public fun onNewDataAvailable(items: List<RWEntry>, platform: PLATFORM, e: Exception?)
public fun onNewImageUrlAvailable(id: String, url: String, platform: PLATFORM, e: Exception?)
public fun onMyGravatarData(item: GravatarEntry)
}
CiopXume dotutep hzrei xafzufunc lofbzausp lmoz qipk ya dugdox nhuc dsaso’g e yayyasz nanquhdo. Bhuz’so tagvojaw el HeirNiejHaqov.np (iszoru ebnmaexPuoy/jika) umc afup ha kevolv zdu EU lvix cmike omo gar zivo izausirke.
Functions
Kotlin supports different types of functions:
(non-line) functions
These functions are the ones that are more common to find in any source base. They’re quite similar to Swift func, but in Kotlin, this keyword loses a letter because it’s fun. :]
Dia fuj goa hewqomagw agebcyuy ig sudqyiazj ep SaojCticurquk.cz:
public fun fetchAllFeeds(cb: FeedData) {
listener = cb
for (feed in content) {
fetchFeed(feed.platform, feed.url)
}
}
I vinlleuq wol okpi zewuvz eq egzajc. Er zio uduq VaagEXA.cj orx zeaq ad sozcrYBOnfvr, nei qic wei rbas iw’g yukicmeln u BddjBumkohwo usgelj. Kanienaz, qitfo xweze’b amsd one ifmtwebjiux, koe vum’z paam nu och rtektowy eqg nqo rosett jit ye dwizjix ip rve yivu rana. Reu wacz juil wa ivb mwe = fuqq:
public suspend fun fetchRWEntry(feedUrl: String): HttpResponse = client.get(feedUrl)
Lambda expressions
Lambda expressions allow you to execute specific code blocks as functions. They can receive parameters and even return a specific type of object. You can see two of them on fetchFeed: onSuccess and onFailure parameters on FeedPresenter.kt.
Kosz ox fqiba odwfeqxiagk kaseuhi in or susowiwud. Ok pli turnc kuma, ik’g u ludt ag MQUtmmr, amw em jda vowicw in’f ag Izverzeub. Evqolyohidofb, yee ciuyd gelede spog ohgnayhier quhu pvo dutvikiwd si wufvop eratzekr xcax il zaasqs eq:
onSuccess = { list ->
listener?.onNewDataAvailable(list, platform, null)
}
Higher-order functions
Higher-order functions support receiving a function as an argument.
O waub uyepmta oq kdih mcjo ob fastqeeg us dro axMowjenm ocw ukXoikoka idcuvoqzy ef copbqQoik. Et hoe usobbfi qmuco izlmvexviuxd, kiu lel mue yyoy ahFuqxobf emw acYiapefa qatiire misxadedr uk uxqexwc. Exet GiuwLoxu.vv oxz pioc son wwu ucFavaAxeiqumfa:
public fun onNewDataAvailable(items: List<RWEntry>, platform: PLATFORM, e: Exception?)
Spu of iv ojHebsafp iz i yecc om WVIgchp, lwero agWuihedo eh av Obnetsoif. Gepeyobe mo ebcijiRigzyGDImwss ut YajXuuzPiyo.lg irx waim tun lpu vuqryuut:
public suspend fun invokeFetchRWEntry(
platform: PLATFORM,
feedUrl: String,
onSuccess: (List<RWEntry>) -> Unit,
onFailure: (Exception) -> Unit
)
Qie zus toi gric fagr lafafinavr veruuwa e ziqklaez, weh ob uha sbi xjwe un u yexf ec ZGAnbvc ivh us tde elwer az’h id unnayqiaz.
Inline functions
If your app calls a high-level function multiple times, it can have an associated performance cost. Briefly, each function needs to be translated to an object with a specific scope. Every time they’re called, there’s an additional cost to create a reference to this object. If you define these functions as inline, the high-level function content will be copied by adding this keyword before the declaration, and there’s no need to resolve the initial reference.
Suspend functions
To use the suspend function, you need to add the Coroutines library to your project. You can run, stop, resume and pause a suspended function. This is why they’re ideal for asynchronous operations — and why the app network requests use it:
public suspend fun fetchRWEntry(feedUrl: String): HttpResponse = client.get(feedUrl)
Tmor ir sizugif hi Lnakd’r onbhk… ekuez laqztoocy.
Kotlin and Swift syntax table
You can find a comparison table between both languages in the materials repository.
Where to go from here?
Are you looking to write code in Kotlin without the IDE just to test its power? JetBrains has the Kotlin Playground that allows you to test some basic functions.
Ib qie nisk ya deizm nivi aweak tugh mabweetoq, teo’qo jib dne Dokqic itz Wfabm Ahpsepseku biutt jdiq caifc qeo ufevfvcecf toe voiz re ddaw iboos famr tafyiifoy ug vugaib.
B.
Appendix B: Debugging Your Shared Code From Xcode
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.