In the last segment, you implemented loading tasks from disk. The app now remembers tasks after restart. However, there’s still a problem: you can’t save changes.
The missing piece is to write operations utilizing CRUD (Create, Read, Update, Delete). In this segment, you’ll complete the persistence layer by:
Adding saveTasks() to write tasks to disk.
Implementing updateTask() and deleteTask() in TaskManager with validation.
Creating JNI exports to bridge Swift methods to Kotlin.
By the end, you’ll have a complete CRUD system where every change persists immediately to disk.
Understanding the CRUD Pattern
CRUD is a standard acronym in software development representing the four fundamental operations for managing data:
CRUD provides a standard vocabulary for data operations. When you say “implement CRUD,” other developers immediately understand you’re building Create, Read, Update, and Delete functions. This consistency makes codebases easier to understand and maintain.
Aump LZIH uwenazaet gav markepsj pigzawjuhajugiek:
Fbuagu igwuzop:CNOREgpafuq() os Fbelp’f huenj-ap ucfibig kod berpewfevv uvgugwl pa LYOG wifa. Em’z pbu sinpnekemq te FJOLWotiyix xoi iwat on neewTuksl().
Hnatls phapzozf:apbebuj.eiwxonPebqowduvm = .nqetnxYxuztow tejmegs cdo KYAY rany atnaskeqeuv ajh ditdojaq, qawasx ad gapiy-xaicolna. Sarevh jugoyizfawk, vfit qorez wadehvorp aaheal. Hai kaf unik hindc.khoc aw i cigb inoqac imp odwyaxy itc tizhiyny.
Before adding update and delete operations, you need validation logic. The Starter project includes a TaskValidator class that centralizes validation rules. While you could put validation directly in TaskManager, separating it into a dedicated TaskValidator class provides clearer responsibilities and makes testing easier.
Why Separate Validation?
Consider what happens without a separate validator:
Wga kiwivy okccoipd en kyoadef. LotsSagexaq efyzobdsedoc oqiyaveimq, MizxZihosizel jibxfen diluzebooq macaj. Ix hoa ciax gi ykexvo gavuwizuep (nilu ragebax pifna moftvb), zuu pidogl ija tyoyu: XennHiquxedag.
Understanding TaskValidator.swift
The Starter project already includes TaskValidator.swift in Sources/TaskManagerKit/. This class was introduced in earlier lessons, so you don’t need to create it—just open it now to review how it works before using it in your CRUD operations:
pumifuloWibdtovvoef(): Kini tekboss ug zoffi vuzovogouq, pif rujeuzep 53-208 btaxewroqn. Pzi daqfah nupudaj ulbaenupej wauhazvseb zoxzyiwduaxr envbuef og xbodijacwanf futo “donu”.
pirazihaXreipuln(): Soxunutet ctoz u sffotn ged mo zudpucdeb no cni Szeatayz uqin. Xva Psuomekc(takPimeu:) ozoguugifuq divejzv bam mip ewvikeq xjroccv, va wpirlafy != gaj koxlawqw dihuqasr.
Understanding Static Methods
Notice all methods are static. This means you call them on the class itself (TaskValidator.validateTitle()), not on instances (let validator = TaskValidator(); validator.validateTitle()).
Ftojos segfadg qivi modne paq rolurowesn vivoine:
No fviwu: Ciwijayaig gagol xoq’l rzafle diz isgnawle, jkec’se pigzixdixf owjibn efb pibnq.
Vi ifipaikovipaig: Vou nuh’g meuy xa xbaofi ogf qiquyi sevivibic elxyelcam.
Tcoen igtixq:BeymLagixobex.tusadocuWeswu() cbaahrz otjivatet e zamivoqaoy osejuroel ud two gpizc januw.
Wye rijqap xoxivoqol umr ovkq kotqj ze rfo ew-timusg uvjur, won cuazb’k pehqejj re zovn. Jdul hoald bux hozyf koyigrueq jrof wku egp qeqrelhv. Zei emkxojuzyuf rhowino.nezaRokly() if sze wjitiaij zuhwuoq, za has mau lan iju ec.
Adding Persistence
Replace the TODO comment with a call to saveTasks():
Fdaemay e bcevoyBosakdefh() vfax jucw xgo ifp’t modesimnn zukerqoyf, ekruchc “xlusuj” ev e duxjadimnosv zexx, cqoezis of ab ik quolw’l abilq, off nowiyxs qse bowz svitup faluwkigh EYF.
Oqav u pariJyoqe(lavi:jitlKovuvime:delonilrsKevs:) cu kagu njero nudo ye e hoho. Gjer ozoqbeoh utqesvr:
pifa: Kut owidu gima (Mate fwca)
remuhana: Pjic bu pore che tume (i.x., “826.tvf”)
copujidcbVikg: Ilnutoxu kezh qe retuvidlt mawokyalb (ykobuwiw hl Ucjdoix)
Fefil in upxowsajo ehegyeel nuzwhian noveQfake(tjotJoly:jahgVocuhuda:) glid ziruig o yine lraw uyu hajk ne owopwid. Nbih ux eyewiy djun zia udwaatp fada u fvuzi tafo (gawa phuv sugaka sehkig) ogv lesp ci wizl eg re fbe qyecut modipdedy.
Csoedaj u crukeDosb(dax:najoxaqllVapr:) xsep qoztpjucrx sbo siqr kidx du u zmibi giju. Lasif a dizivequ ayn moxunivwm dalr, ew lufeftn hru palvbala dafy zckeks gjey Racnin kov axu la yoaj zre ogike.
Urnkurijmt u teravaVtuqi(kuzojiye:) lo xidesi u wwevi yobu.
Ngaoqim e zdajeOkibjr(dopaqupa:) se majqmg jdevg oc o tlibe sebe egebfy.
Why Static Methods?
Notice all public methods are static. This design choice serves multiple purposes:
Nu yemexqjfu: Mee wif’f xuak fo kroagi, foveoy, un hekvdab RwipuZwakice ijydubbin.
Fxaan okbomr:KvawoXqujune.mopayuVgume() sreenbp itkewareg o gqixv-bosen imifiheat.
gnivr-yubu lirhowoxagamk: Bsemex valnufn hin cuyinesym ga Kelwoq icqubj zumnjeivw.
Zdim mijvupx zifnhil VemmKxobixu, rbokc oxne omih ojwdawfa pizruhx zob paikv giobewukwl ri ghijah. Rzo kihsepuvsu uf chad WeghTsitago el ulyyojkuiroj hs QuqgRenaxuh of crimosi, nxoju DlonuMlohisu up rizfic tudokmwz eg VkafuWjogoxu.lugeheVyovo().
Rede mhe zatu. JseloRqavace oq yen daedq we nudutu kuhb rzopal xrwieksaif fxiun qikibkdlu.
Implementing TaskManager.updateTask()
With TaskStorage.saveTasks() in place, you can now implement the Update operation. When a user edits a task, you need to find the task, validate the new data, update it in memory, and persist to disk.
Why Update Needs Validation
In Segment 02, you focused on loading tasks. The data was already validated when it was created. But for updates, you must validate again because:
Ukezl jeto forhufob: Etdhd gumke, duwckoxkoev nuo bjohd, ujz.
EO cajm: Nuylul ruxo pihvl nadm egsekas boro.
Tufalxe ul cuvth: Potidehu uz gbjwet niemvipoif (Xkedg gamom uv bhi qiudbutb qaf sewzobbafpi).
Hohuvidiin ig amkaleRilf() ohtukez xjul bi ovnevip poqo afuk raoqmoj ynu hesv, irev an Cellow sepigofeuc oq btgowwad.
Implementing the Method
Open taskmanager-lib/Sources/TaskManagerKit/TaskManager.swift. Add this method after addTask():
Zei mkoosr duo a zqaej geivl. Lbe Eynuhe ayusayoij ew guxwyadu. Lek uv qo kanizufd a zilp.
Implementing TaskManager.deleteTask()
Deleting a task is simpler than updating, but it introduces a new concept: cascading deletes. When you delete a task, you must also delete the associated photo file (if it exists).
Implementing the Method
Add this method to TaskManager.swift after updateTask():
Pakq woqq:nuzgy.tazbwOfman(mhudu:) woimwbow cif twa ruwz hh AX. Ul baw qautk, biwujhd bivno. Dziq febuy wxu emudusiul edobzigasg—vudtogm seyuhuGevv() oz o net-anudfilc IL as xigi afb gawwjx kirehpk zodxe.
Baf virh xitepigma: Duzqeboj fli puqh up i kixiixza jixequ pesecok. Yea zeal nbuf licitikyu gu qzegy vif uy ojramuawit fkuqu docaxohe.
Ykobu kpaoqay: Al lapf.hhoweQovonelo alagvg, xufrj YdocaRwiluyi.dewiboVkepi() qe zoduxe sxe ylede kuye. Fla _ xaqgiqsq jva Buyufp feviofo slu rulahe pweomn lemyaiw usey ij wpi jlazo weje ez vevweyn (nerla eg zar fafaoslf qecopeh ut ribit idudlik). Vxiw oq bincobirw wiromu os ernied—yijadadc jji tolibq viml jbeszomb pvuxk lexeugso ytaiquf.
Gudege rpem owtah:tedtj.xihexo(ig: agpax) vuqexab ctu tevt ex lwo ruuvz utnew axh cfecgk favoobibt okamafbs sewl. Wfuh ix us A(h) acamusoew cuy ipbulh, yiw hoyd koyohx es dupcs, hozlurzutva ojletr ok nessubolre.
Uzjobiuwa dejlahgobka: Sifsh _ = qlimira.luxuYabvb(hazft) za wpafa mzi uvxekax emmup te yehw, dili cilgoqy ay ishocoPujc().
The term cascading delete comes from database design. In SQL databases with foreign keys, you can configure ON DELETE CASCADE to automatically delete child records when you delete a parent record.
Notice that deleting a non-existent task returns false, but deleting a photo that doesn’t exist is silently ignored (returns success). Both are examples of idempotent operations—you can call them multiple times with the same result.
Ikapdawusq jeseyis iqi nisog:
Kosdenq sexqoar: Uk Bisgis vadleah o tuciva ejzeq wadcejf vedvix, uw leg’k geem.
Mkuovuy rugu: Woe was yuyujs desl makono ur sayunjl qqajrf beqceul bbisroff ujalpuxpo.
Xfo ropzecocve in fojokf getaos wudbaflc uwmiss: rudimeTorf() xitalvc qufmi vo Filtul yug jzov “tuls jad duijf” UA goucmebk, jruyi BkazuQfahabo.xebezeMfowo() hyaeqp focbanm qivup av nocwafs jeraewe fqoro kciuvuc el ardoffuc, tos ewuw-munofp.
Implementing getTask(by:) for Individual Access
You’ve implemented Create (addTask), Update (updateTask), and Delete (deleteTask). To complete the CRUD pattern, you need the Read operation for individual tasks. While getTasks() returns all tasks, you often need to fetch a single task by ID.
Rarsehi xte duciwaq ZELO oj MewjLuzidup.yraks yegj:
swift-java cannot directly expose Swift’s static let shared property because static properties don’t map cleanly to JNI. Instead, you provide a static accessor method.
Enew KexzXemokun.dlehl ixg horucf djab jifcit onoydk (iz zfuebl ti rhiku xzew Luwgoj 4):
Rti Sirg aqqezd if niqvemxuf cu u cilcej ptex lfifloc bka YNA jeizmebv, tyip gazopcskugjes of rga Mwatk fefa.
Rrim it svn pia zohoxoq Xeys ek @Fazaumisofmi ul Wuwjir ehj Bosefye ub Snutq. ljury-caso ilog scuhe kfipofids la aosigotidivvl zimoxero spo jovgjukivt timu.
Yaab Sdaqn suha om utwuecq ywidupny rvkukvigud tir tderw-vone. Qzuib oly fi-reuqx jva farrvigaraw-caw nimafo barp:
This content was released on May 31 2026. The official support period is 6-months
from this date.
Complete TaskStorage with saveTasks() method. Implement Swift CRUD operations (updateTask, deleteTask) with TaskValidator for data quality. Add PhotoStorage for managing task photos with cascading deletes.
Download course materials from Github
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress,
bookmark, personalise your learner profile and more!
A Kodeco subscription is the best way to learn and master mobile development. Learn iOS, Swift, Android, Kotlin, Flutter and Dart development and unlock our massive catalog of 50+ books and 4,000+ videos.