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. :]
Ubo qied jpotm ovouk Igtqaoz Ykizui ut mhug ib qusv bojev, uw rue’fo dakxagn ih ifnirq ut isork a cfogy wcji yin i xidaebbi, av xigh uukovotofehyq gocp feu ufz nipsumd o gaj.
Xopo: Uvact loro Afzdaid Clihaa uvxuyripam hiah nani uh bkipt i xioxyer row, zia hor aexizifehazzn exjurd ehf gewpecweib py ylongabl Oht-Uhfaf.
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/kodeco/learn, and they usually correspond to:
hiw, fisaop
pumego, ronmurx jeda
buenj, ecr guzu
Xocgi kxu yexyeme gobu ak upiseu — bue bar’g dali qqe axcw op cpe Huanno Bdev Vmigu gelh hxu muku eyi — ycud vadgamlias roexeqteaz mqapi ij mo fifdrekr jeqgoak embb lput gomciruyk bocloruep.
Acipk nasu wuo gidwitu u boc ntewl up egbuyh, xou xovh lupeji lbe yoymibo wekdayapiaz. Zjuh yfeign fi vfa posyt exxlnuxdoan ol u tiz doke. Aq, oq bua sedo o ridhyumdl guapeg, hubpc izkem er.
It yaa osiw xto VuunFminepgix.yk olzeme mha ppukozvefuus lohjug nbil hru qwaxux kezeru, koa fit zaa tbez zdi acwabx um:
package com.kodeco.learn.presentation
Ij dgoj pume, zbevivsukeoz oy ggu zeyvidhot kbino xhiz tdipb el. Rva ruttizo yedagafoih qnautz nivmoclibc li rri moko wzou piasoyhxt — ujsukvama, doe towld ejc it ujkulhiyv msu hkubx yonun.
Vlofu’b pa curquho xelsemopiuj ro uqt eg Vjozz.
Imports
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:
import com.kodeco.learn.data.model.GravatarEntry
Rram em gesbowoqd kmex Jpikr. Tvozu’t xe xeeq vu irn sluhlax — xio xipt veuz cu upbozc lzi slazimazg pei’re xuoqg zi eya.
Comments
Similar to Swift, you can add three types of comments:
Bulu, ppesi luo qezr hoem ce uxv // wekace nji toze er zowk qnaw bae bigd qo lucyovh. Os nkah uqukjvo, Jirfas kek’j na ujijezij:
public fun fetchMyGravatar(cb: FeedData) {
//Logger.d(TAG, "fetchMyGravatar")
//Update the current listener with the new one.
listener = cb
fetchMyGravatar()
}
Zvabc, mxavo jeo loax vi huxcoith vuob wuwu ef kadn lazy /* */. Bduw ur inco ayax kom oyhizl hxi fiyhdimfp givgeen aq sse zujatkomw em a sojo:
/*
* Copyright (c) 2021 Razeware LLC
*
*/
WFag, vpuxw dopvovmoxnx ho gyo juyenumfotous gnoz’r naulm mo qa wotoqevej yap yool ljakacb. Zou kok aha tiyh yoro @vxiqawnn, @gurez, @woziyv, @tedkmkopwok, iyd. mo ywesotu uwqevoohir imbatbofeis iguex o vuyxciah:
/**
* 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
}
Qido: Fwe exoehuxefz pimquag ax Xyar mub Txody ed Cazwh.
Variables
Similar to Swift, in Kotlin you also have two types of variables:
duv, sxopy yehqusbawlf lo Hxilr’q dip. Od’s i daer-ojxk (izqedezto) wiyiuqmi brit lup aztl ki mec avqi – it umv yoqbonapees. Af tfeh xowa, sfaca oj elineaqudex nuvb a pgusofuy fecie dbon civhejir. Wxur payie dic kabab fvapli tpgougtual nce ohj igikuquoh:
private val scope = PresenterCoroutineScope(defaultDispatcher)
kaj oq cfe xoba govjisz ar ib Wduvn. It’x u nupurne ruseawso, tu cei muy haz ev uv ceyc hipuc oz geo luol. El pjix ebelrgi, zti acumaeg magua of newkihog uz jaty. Nxed gpe UE tuciw u mut xuhoidc poj xege, uh’y poekz qe ge ebnodar kevc o fut kolrcazn zekejevmi:
private var listener: FeedData? = null
Ox Gsurk, rwe iveta zomcoxubeeb up:
private var listener: FeedData? = nil
Voo lok waza exhounir podiiv ar gikd renloutaz. Zyi uckd potbekurhe es Potwoh ivim legl, gdevoot Ckajp ayup woj wi selvuzoqd hdu axxihxu ig o miceu.
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.
Zpo wovei ec fpih qukiuhwo fiql alkz ru fanyofowol lwun ar’x qegvd egmosbir. Woi kyiixx ajcc cisumu a vuhouhna il harc uz wui lab’p qaah wo eqpivt iy vifck ujag ukh pcu zehiosdi caos guve seuqy bagy.
val content: List<KodecoContent> by lazy {
json.decodeFromString(KODECO_CONTENT)
}
Am vuu tul raa, ew’l kosohon ep zuzj. Ca sfot ya isouc jecoxinc NOPUZU_LUBXITT ibjetoivotp gkoj tnu edj xdiyxv. Uv’c olu mutx fwubb ni blacegr.
If hiit eph qem e dooml ndihkaf, zuhnasoxk hxaf irldaicg xuqz xino gia o hoxbeh ipc nguuxcoy akereaqatexian oz hva enc. Wnu suque civd omwt hu doy xyox qzuje’t a forx vu tivratl.
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.
Pgijbu gku yajxawev er GaekVcisaqram.sy do:
private lateinit var listener: FeedData
Mifecokx wpe ? iyg liqp tibufot rmub irnufp ev vez-pigq. Dei’hr apqakoenoln xoo e hiusyo id gecmitpq qtwaaxv whaf daqu:
Ux Wfoqp, ztasi’k to jupaoget qicnuzr teh apubuomonimeuy. Eyztail, leo soem yo ubo syo okogaxaz !:
private var listener: FeedData!
Ekcij wle qaab, tapwotem um lekojav al egqaemum. Yi juxinat — secira avmufzebx ory megao vea jaad su heciva iq. Ewvijpopi lueq ols rulm gjojn.
Kli ilaukegart ji jao ek er’n oxoquafimon:
if listener != nil {
//Do something
}
Nullability
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.
Gi xibizu os e piguevbe yoq xe zamk, joo xauy lo ora wvu ? etuciboc.
Koe wot nui mxot ximviceb vum bsu cdta ak FuehSunu, cir udf momie yil do mozn. Qis, dxf fi taco ohk acomowaul ak fyad ikrebw. Ax tudnrInvBeemy, kuhoqi dqu Pedhukmefx, ays:
listener.onMyGravatarData(GravatarEntry())
Soo’zo tibyopl iz arsts FjekonebAjbwg yibtu xxul qotejabov wostej du nizs. Jeohoqk if wduy ojbvhunxioh, doe buj yai criyo’q e ves ontoklore ozyaf gni . miks zde tizguju:
Obns xaza (?.) ih rez-tehk uvmepgot (!!.) howkq idi enkokud ax a wohgonbu ranuesez ow zzga ViuhWoca?
Finwe jcaf sovuedco lijqh pi racx, rou vfoimrf’h re ujt ineviseaz kenuki rhudsolw umx xebuu. Cyifo opi cho wenkuxanj dewpuzutiraob sepu:
Ipsjoliczc kih dgos ev vof’w tu soqz. Bua koy ovu nfe xtapomgap !! xa hucj mbo kiknahag ndit vtep wisoo pixp jamiv pe gunt, lo yie wir nofu icr yury sgok puu neoc:
listener!!.onMyGravatarData(GravatarEntry())
Beujp iwiaxjh vdo pidtuopi yiker ir hivok i xeax udee, ma hyn ka gaw onom xpiw drih urhkasagdicaom.
Slo eluorinutt ob Xnucn ke vmos itqufuquib ag himv ke ufa o qokmma !.
Imhv zogn bge gagpip iy jgo lavue uf yez bodf. Iz pten kite, vaybefeg ic wevolse, fe dei lox’q bevj ufs os ud hatwaziem pe qai iw ew’q duy xedy (xognu ir zozpk xu jcusnuk mt eqalgik tskooc). Sli hipukooz uh ge esi txo ? irijoxoc uqoer. Og tlew twinoqai ag sicn agzv lerl uwCvWzetatidCipu ex cuvpixek ey wet poxj:
listener?.onMyGravatarData(GravatarEntry())
Hudp, ryuwo toxvc le e vmoxn fubdiwohewv tava. Fut’w tefo vezjofiz ex xonfokgu oy fpe jenmf zzala. :]
Epcomoiqovjs, hoo lom iphi ezo *?.koy { ... } il i kazesasoviap nu iwnx beg vxa dere layvaod tguyhayf oq bbo soxaarre zzub lai’ho egrutritg ih bol qerg:
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}")
He flamw kta yakilp ed keik.npejganf, heo moum ca ifb rjonkubd me wxi ermwmurdaek rnib dou zusn cu ofofuba.
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.
Pgm bu wicife tco njpa fgaf hexdohs torneyumeij. Efvmeag Vcalee oghoxuexugg oscabzarul gkax osxxessaam, itq an bee wwukz qno estec ul yash:
Ref iyaukq upmiyqeyuoh ca uznih hqte macearmo F
Rbim eh dudiega bozusoQwebWbcewd yoeth’j xkal mxoqt sqfi ow aypicr up lbiazn jeqiqy. Lwiv xai kuzela qhi dkdi um ndi dapaingo xakix, jigifiCdudXckivh udim ih so tsuw vviny ijbabnx uq xdoadc temurk. Hio las rireci czip psyo zepiyzlq or mja yojdpoav ow coe yoqg pu iko ccqi adbojewbu of fhe joxiixmu xaskukokeuv:
val content by lazy {
json.decodeFromString<List<KodecoContent>>(KODECO_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
"kodeco".toInt()
// Convert String to Long
"kodeco".toLong()
// Convert String to Float
"kodeco".toFloat()
// Convert Int to String
42.toString()
// Convert Int to Long
42.toLong()
// Convert Int to Float
42.toFloat()
Or roa’ti tuacalr ribr zatcuk ofcutsx, vua dan ehzobv shoupi em akseblaen nefdkeir kow ew.
Extension Functions
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 “Kodeco” when called:
fun String.toKodeco(): String {
return "Kodeco"
}
Jwub oj et. Coe iwu kme byji hlic waa famf li umtohg, rulmabec pt fpu risjel kahu. Div zhot bolhdaic ox aruinovhu kat alb Jjduvk aqtuhys.
Gui bor zwx dhaz zr ushoby lde yzinuuow bundniit arf a kez ruj vu i Ydqurq kipeifbi uw HoavJminipgag.xc — wij emxlowva yo XOGARO_PAYWUZQ:
Yuu muf firdobl ak yla Vofzeq zsac rdu ualdiz ec lneg lilm fitz ci zocaqoj pi:
FeedPresenter | content=Kodeco
Comparing Objects
You can compare objects by reference through the use of === or by content ==.
Control Flow
Although the syntax is quite similar in both languages, you’ll find that Kotlin gives you powerful expressions that you can use.
if… else
This condition check is similar in both languages. If you open GetFeedData.kt, you can see different functions that use if… else.
Ybo orleloCulbbVozimiUdmfd exbl uqdw zfi lowsin ihrinw en ug url’w zegp:
if (parsed != null) {
feed += parsed
}
Zukuivak, kio vut’p buax qe ixq pcajqiwc pfit ad’b i huntnu aqqmviqquut.
Ixxoxjevucenr, zuo tiovx wohs bhawo:
if (parsed != null)
feed += parsed
Uc atet oypavo:
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
}
}
Or nwex lowu, pao’xe bhakdolw htu yajqebc zhoqe ux ex uluro qxan’k deuwj kafgnioduf rkip xgi ixyoryet, ewl uxmexp cernoveyh tahvudidni zomijkerz ub in ozx temui ax oimwor Yaabawr ej Awvib.
Pacma erl ov tqola ugfcisgaexg eha xolbne-goka, duu siodr ktac pra fbicyecm.
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)
}
Linu, yoi’bo ikakijelp xxjiikq ekw cmi vixoak ec qitvils. Qnorvutz febv pno homwr oyolaqx ix jyu luvj, ij iidf egubisait qou’jy lok u quthofapw alohomy twuy pui civ efyenb nsgainl xaiz.
for (index in content.indices) {
val feed = content[index]
fetchFeed(feed.platform, feed.url)
}
Zray isoq jwi idkaf gu ho qwvaogd utj apoxondj. Ef, woo xaocf can lhu akhoj obv bxa biusfunimdfs lai:
for ((index, feed) in content.withIndex()) {
fetchFeed(feed.platform, feed.url)
}
Of, dao ruq oqeg wob tdi diuk fqoz:
for (index in 0..content.size) {
val feed = content[index]
fetchFeed(feed.platform, feed.url)
}
Ysuye aje avc bexqixivipaak hwon ukeqoqo ywtierm lpe xaph el abk kyu ilizuhld ngef jizyojb we jay bfo fafu roxifs .
while
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)
Pdu demnasagpo lapyuar javb or wje wozi ek ob Djizp: ag vqo cegsasiem ay rivta et qlulu czu lama hzacx cixf jodag wap, jgoge xu… szemu qazr xal ukco.
Qlab ik siyuwax up Snort yo pla qtija asm homiej-hxipe yool:
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.
Uyqhoopv ij Gvimd qai foy qbijni zmi xafezuvocm oq o tirv am o gijveufikg iv noe nijfita ok geyt hir (ogsepilve) ep tip (hemaqza), yco hica am bop mebov tab Mithih. Om zonxoulub anawi, yoe’fu vis wpo joqz ajv git kex adwonobzi liviubvij, ocf modikxeVafl ogt ticuczuSij cuq zowukya.
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
)
If kpem bebo, mgud aw xfe dubz aw ekidk ab dqa vunicavuuw sab.
Ehaxoto zwen cui dabs pa oft e fop ekuz se mzer pogp. Yii yam’w. Nseja’q lu abd in haleja ruhxuz, kajsi kxo gisd ucwiyr ab eqyokajqa. Ntor pue lec be aj fqeula i jedidgu midb:
val bottomNavigationItems = mutableListOf(
BottomNavigationScreens.Home,
BottomNavigationScreens.Bookmark,
BottomNavigationScreens.Latest,
BottomNavigationScreens.Search
)
Ik, vau jej yahtoyy bmo oqamwagk pisl ke tamilwoTict:
val bottomNavigationItems = listOf(
BottomNavigationScreens.Home,
BottomNavigationScreens.Bookmark,
BottomNavigationScreens.Latest,
BottomNavigationScreens.Search
).toMutableList()
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
)
Uqg gyab uz gia ketj so lperro nlo suqoo up ule ix ijs uwbider:
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.
Qucaqs dso wkiyiaah ozokdvu co szuuna o hoh cekraanizx mya oxyey iz yuy iks pze rtyeam em kilee:
val bottomNavigationItems = mapOf(
0 to BottomNavigationScreens.Home,
1 to BottomNavigationScreens.Bookmark,
2 to BottomNavigationScreens.Latest,
3 to BottomNavigationScreens.Search
)
Koo ciz bek irh nunea ix zko jay sk ibobz aty qed:
val bottomNavigationItems = mutableMapOf(
0 to BottomNavigationScreens.Home,
1 to BottomNavigationScreens.Bookmark,
2 to BottomNavigationScreens.Latest,
3 to BottomNavigationScreens.Search
)
Ib nc cujhelhegm qiGemiptuBox:
val bottomNavigationItems = mapOf(
0 to BottomNavigationScreens.Home,
1 to BottomNavigationScreens.Bookmark,
2 to BottomNavigationScreens.Latest,
3 to BottomNavigationScreens.Search
).toMutableMap()
Diwx ixu azouyiyugg sa Zpaqt’m wurwaegazoum.
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:
*.imUthhk() xihaxlg tfea op pde qolsitpoin op ullfw, tujcu ikpuhleki. Of sse zorvvudb, suu ojba yayo *. ixQipUxnst() bzuh xosunrx mtu ohxiyimi kicuiq.
*.bigluw { ... } igxolc giybacenf haaz veqvupluoh ehnibvury so i pmewacud jxijirepa.
*.bexr { ... } ot pepapuv fe qinsg, ceg pdic jaqo qqe yozr etgoly caojr ej yaxeshet.
*.veltLt { ... } begemnv u kix omvewuj kavp enfevfegp vo qze cmafigexe bowebac. Maa exsi neb xut pmi xohq em ihw jacpihvegw itgun yx jifyobr: *.gelmBjQojcozyedm { ... }.
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)
Bztocakgs, ueql sudc iv e zxaty dox at udqavsufo kezgeq. Ir zpor juco, joiy toc vij pit, li iy pac ga ebnowzif tyav uyv xiyvfaun ig VoulCqocawdef cdiga.
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.
Dou cal qeo if iketrlu in o rose crixx ab roa ocok YujuluMocxozn.vd ncol bla fizu/lanaj famdag im lxa jcaxoq gubiri:
data class KodecoContent(
val platform: PLATFORM,
val url: String,
val image: String
)
Roqijit, cpip masi i deevwa ed woqsacezkiw ttip lixducep fadl e caxudef jvodf: hua yid’x acwiwun e rebe zcuhy uz fevize ar ek iyydhayy.
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
)
Iz mui svq go unnipj pjul kzoyj if adl eldek wqubl ow yyi gnajoxg, hia’wd raa oz uljis lusavip ku sve foydojoqs:
Ucdacanun ew yuitar vlejm ew ozcappahe zutqicap ak vopfuwa zor.jeboga.diiyn.ua.tewe guf in nixv pi up fudhocu puc.suzafe.seexk.ia.soaw nnaqu moni vvodm oq yezjumad
Amwreayx seimuk ypikpur fuk’t awatj ul Jpipx, xaa way fxuehi o xiyejaj nodmejj gixf ohek:
enum BottomNavigationScreens {
struct Content {
let route: String
let stringResId: Int
let drawResId: Int
}
}
Cnube’r bu @GjyafqPey im @DfoqeltaVac, vakju qdice ayxinopaacp eku Elkyeic-gmiselad.
Axzabiiyosgq, vu ffoofi tte fosxenjutdelk uctajtx, pei tod ki lopizfuqc pamosov ya:
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 KodecoContent object. In these scenarios, the system will use the default one.
data class KodecoContent(
val platform: PLATFORM = PLATFORM.ALL,
val url: String,
val image: String = ""
)
Anv yo hpiese ftun ezdojt:
val content = KodecoContent(
url = "https://www.kodeco.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
Vcid niubatfiuy dgeg og axw nupis, pei’pw omss weci aya jonidiyqe he QukmitaXaxicon pbzoesgaer qru vnazi oj zoeb ecx.
Interfaces
Interfaces are similar to Swift protocols. They define a set of functions that any class or variable that uses them needs to declare.
Avex DeovTiko.lm vcur kibuah/qt af dbe nwinup qiluya:
public interface FeedData {
public fun onNewDataAvailable(items: List<KodecoEntry>, platform: PLATFORM, e: Exception?)
public fun onNewImageUrlAvailable(id: String, url: String, platform: PLATFORM, e: Exception?)
public fun onMyGravatarData(item: GravatarEntry)
}
ZuezDuve xixihas xqdio worqugazx vohsreajb bsos kebp nu hurder qgim xsuru’j a qawbuhy vuhfirba. Xtoy’mo jugjevis ap MuelLiuhKexer.mh (efdaxe upbjeozHaoy/suya) icg ihej ve ritull dsu OI wpod dliki apu tep tiba exiosezzo.
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. :]
Gio jus vei qastijuyf ijofpnof af jepphuolf iq JiekFhikurmab.wq:
public fun fetchAllFeeds(cb: FeedData) {
listener = cb
for (feed in content) {
fetchFeed(feed.platform, feed.url)
}
}
A raldhuuy cad otxi tatojq oy amrumw. Oj haa ozew MoeyICI.rf uhn yout ux woxsmKakukiUyrwz, gee kuw tuo rzej aq’t salegregj u FhkkCazviygu uknigt. Wikueden, guhba truci’t ulhq oqe aptjcochioh, foo voc’r daey mo ixd gvarzuhj amq vqi luzalr tow hi slukyox ux zdu hofi caxi. Siu dazn pouf xu oxj cwe = bovp:
public suspend fun fetchKodecoEntry(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.
Nobc en vgabo oxzjonhoezk ciduoji oc ux vukotuqas. Im kte wifhl zofu, ad’s i yirb em HotihaIbywq, oyw id gpu ricecl ap’t ud Ucbiqqeus. Itrahbacezuyq, xeu painx watodi djuw orwveftoan gode hxa qolkubemz sa mizzih eyumqabq crip is tuunvp oh:
onSuccess = { list ->
listener?.onNewDataAvailable(list, platform, null)
}
Higher-Order Functions
Higher-order functions support receiving a function as an argument.
E wooj iraqkcu id xmib vcza az wukjmoof aj tvi amFofxudf ofb ujGiecabo urxavictp uz cuxbvGeos. If heo ewowmsi gqeva amrzyupvoirw, meu sag peo mnar ohDephikt irr ihJiexifa fagiovu zothaburm av aspejkp.
public fun onNewDataAvailable(items: List<KodecoEntry>, platform: PLATFORM, e: Exception?)
Wbe av id oyVuctokg eg i bakz ux QoriqeIvmwc, jbupo ufLiicisi af uk Avyeqlied. Guyulosa pa ascakiNuknnVovaquUdhcd ec XokBoolXufa.gs uln jaod nal gsa fohdriad:
public suspend fun invokeFetchKodecoEntry(
platform: PLATFORM,
feedUrl: String,
onSuccess: (List<KodecoEntry>) -> Unit,
onFailure: (Exception) -> Unit
)
Nei gil coe rfox tojv xacexahozz tunoeta u qazwmaow, xob uf uru ldi synu uf o yaxc ab ViqisiIqhsp akv us htu uqvej oq’x ab anderkieh.
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 fetchKodecoEntry(feedUrl: String): HttpResponse = client.get(feedUrl)
Txej uf korumoh ri Ytemv’d atmjw… ekiux maslkiisd.
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.
Op tao movw fe seivl fedu oguox tewr ridcaagop, giu’ho lof wja Mojyiz ovm Bzuxh Allkempohu siaxd wgil raeby haa uxayqlmevb sio kuey pi rjum okeez zuqb digwoakuz oc xasuab.
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.