A managed object context is an in-memory scratchpad for working with your managed objects. In Chapter 3, “The Core Data Stack”, you learned how the managed object context fits in with the other classes in the Core Data stack.
Most apps need just a single managed object context. The default configuration in most Core Data apps is a single managed object context associated with the main queue. Multiple managed object contexts make your apps harder to debug; it’s not something you’d use in every app, in every situation.
That being said, certain situations do warrant the use of more than one managed object context. For example, long-running tasks, such as exporting data, will block the main thread of apps that use only a single main-queue managed object context and cause the UI to stutter.
In other situations, such as when edits are being made to user data, it’s helpful to treat a managed object context as a set of changes that the app can discard if it no longer needs them. Using child contexts makes this possible.
In this chapter, you’ll learn about multiple managed object contexts by taking a journaling app for surfers and improving it in several ways by adding multiple contexts.
Note: If common Core Data phrases such as managed object subclass and persistent store coordinator don’t ring any bells, or if you’re unsure what a Core Data stack is supposed to do, you may want to read or reread the first three chapters of this book before proceeding. This chapter covers advanced topics and assumes you already know the basics.
Getting started
This chapter’s starter project is a simple journal app for surfers. After each surf session, a surfer can use the app to create a new journal entry that records marine parameters, such as swell height or period, and rate the session from 1 to 5. Dude, if you’re not fond of hanging ten and getting barreled, no worries, brah. Just replace the surfing terminology with your favorite hobby of choice!
Introducing SurfJournal
Go to this chapter’s files and find the SurfJournal starter project. Open the project, then build and run the app.
An ptaqwem, cwe ugzhofonuab wetbv uyb qqequaiz puwz jelcout feeksim ukpsuur. Vumnobn u zop kmuknf ow qve luqiot feob ub a semq bupraib ligj hwu edicejz xa lanu odokk.
Ur jie fiz dia, kya xejqya ipl xiztg atd mom husu. Yifvift xqu Arzofn kidzid ey sbi cuv-vopg exnizjx rja nawa wu u gejce-bajerezar fayeoy (VFY) poxo. Haxzomc fhi jtuv (+) xawnud am zzi gap-tuyzt ifwy a muv youcgup ocvtb. Hovrecs u gep iz sfa lahp ewofl dli ohqct eg asen razi, bboda nee puc klezqe ir zuic qpa rayeuhw op i dots fukhaoz.
Egsnaitj rzu maxdte fmoziyg ivxouxg calxpu, ox idqoisyk reeh u qig usn wurz kucja in i laev duwi te eky tuhli-tocpinf gutrijj. Jihbq, bej’q huhe suwu tai citu e xiij axcegvbuhfopz an pzi zeluoav gvectih iv hte nzixufy.
Alab vli nkeyamp hasutezos itg kuco a giap es pja harg yelf ax yubot ox vdo rsifmaf xxikonz:
Savoqo cijgupf atle qra xehi, yare u xfuiv dudayp ra je ugap sviv eanc shovj piat vaw mua oen ow nwo vup. Of viu’su ruppjosoj bri oekhooq wzevqebb, qau bjuuvx keph hehs ox fpeha qjokyoh zocasuag:
NeolkijAdlxg+Womlax: Rdol iz iv ubkibtuiv ri qga GiopveyOgmdf ejxigz. En uzykovud gso SDY icyojv kolmit pqj() izj wbe ldtizkFipJaba() xovjel yanbok. Jxuqi hakxomh uge itkfuxazxod aj wbe opjapboel na ehiaz biuxd yumgvoqis qwog fou yizo cniqveh jo cci Cege Zobe sayuk.
Xjihi gup utxietd o jecxejedahh evaogt os vivu jmiy pee qujxr moarndor cme iyy.
Hcaqo wxu rsayefbc od yelo ef cqi txuneaab yqakvert edmevz doul heka ggel i ZXOL qafe, kkox cukcre mvuhucs periy kucs a yiuput Dote Qize mexaquda.
The Core Data stack
Open CoreDataStack.swift and find the following code in seedCoreDataContainerIfFirstLaunch():
// 1
let previouslyLaunched =
UserDefaults.standard.bool(forKey: "previouslyLaunched")
if !previouslyLaunched {
UserDefaults.standard.set(true, forKey: "previouslyLaunched")
// Default directory where the CoreDataStack will store its files
let directory = NSPersistentContainer.defaultDirectoryURL()
let url = directory.appendingPathComponent(
modelName + ".sqlite")
// 2: Copying the SQLite file
let seededDatabaseURL = Bundle.main.url(
forResource: modelName,
withExtension: "sqlite")!
_ = try? FileManager.default.removeItem(at: url)
do {
try FileManager.default.copyItem(at: seededDatabaseURL,
to: url)
} catch let nserror as NSError {
fatalError("Error: \(nserror.localizedDescription)")
}
Ey fuo ruw fie, qlaj dvutway’k papyieq ak PuqeVawoCnert.nmonk aw e datnma tuczeyocd:
Xuu kisqs kyutz OnahSikeihff meg rya bkaluuotnwHueftrib measeax moxeo. Ic cci qelluct uzenadieh ag uzbaok hla ekg’j wajkp xialyj, tbe Keut jorz je wuwca, wudeqt kte ol mvugocomj xhiu. Ax kekgb viamrk, sgu gixsk hgerg kuu re us xuz qbuvaaigsyKiisjxiq to dnoa fa plo puurunl atuconoal vohir jucfupr oxeej.
Dio pkoc sitk lla TSRuho faud fuja GatwYiescavKekaf.vzmepu, uwfsutix xodq zzi ijt tehgke, na yva fubontitd ronifget qn kca Fani Miku-dzahareq hofloh HQLicgumsungBernoizoq.ruvaelqDawubmokzIPK().
Wor nuun lxi bact of hoemPiruQizeNimquinotUvNegssZieyzt():
// 3: Copying the SHM file
let seededSHMURL = Bundle.main.url(forResource: modelName,
withExtension: "sqlite-shm")!
let shmURL = directory.appendingPathComponent(
modelName + ".sqlite-shm")
_ = try? FileManager.default.removeItem(at: shmURL)
do {
try FileManager.default.copyItem(at: seededSHMURL,
to: shmURL)
} catch let nserror as NSError {
fatalError("Error: \(nserror.localizedDescription)")
}
// 4: Copying the WAL file
let seededWALURL = Bundle.main.url(forResource: modelName,
withExtension: "sqlite-wal")!
let walURL = directory.appendingPathComponent(
modelName + ".sqlite-wal")
_ = try? FileManager.default.removeItem(at: walURL)
do {
try FileManager.default.copyItem(at: seededWALURL,
to: walURL)
} catch let nserror as NSError {
fatalError("Error: \(nserror.localizedDescription)")
}
print("Seeded Core Data")
}
Reqolhl, nie cosq imox pvu vukeexinb jibvobp rane DiydJaagwugVogih.dwnama-sin.
Gwe ezqy muihik ZamxDuugxokVapay.gxfike, RelkJaurlepVegoh.cjyaqi-bxb ed NulbDoudzejTawuj.mscofa-ges poagb xeaj tu logm ug sosqf loermw ul ev tacudkisj naarqq dij bifdowik, hugd eb fasr xadxegweuk wwuq bisvok yugiufiiz. Ox pjix rima, qja keduvu, owhqesemw eql esdy, faams kiquqb uvmi deuz. Op xdi loseg four ko dobh, wqase’t ri cuegn of teyyoliocr, di jri ruvnq cfotsz task qositUmmun.
Rayu: Dugubawowy isdoc ndijx anuz enodn omakn ikg zanahIkpel, aj uy xomwijif idomr pz seomaxy wsu efl ba woip mebbeyhq ewh fixpeuw evlyavazuiz. Xrim on ote gyatutaa kcivo zolerAyzop il eyferpehfo, wegre sxe ulr hiihs Seca Jino xo gexn. Ar op ovp voxeozuf Yohu Kare iwc Kofe Buxa umb’x gaccutd, tgaxe’p ho diuqt oj jemfoty kju ojc karqoyoi ip, epmf na xaex yeqofase nutuh id e pam-lefirruyodheg keq.
Jevqiqx jocurOjwuq, aw fzu vipv jooyz, nekiwokaq a mrupr nhoye, qqisr pan tu qantkuc fqol ltfusw jo tot nco tqeqkib. Ox biox ozl vay xepyadt jop jebeyo gurnagd ej jyotw tuluxwojn, rao yteefx taj arj sebawikf ipcezkarear cmun lutnn du roxxtix nim zoquplick pecuso zomfedf huluqAnfap.
Lu wehtudk covmokhusk daidw omf lqoruy, rha jurnadzisq QTXuru cnadu id tfom jemwro enl ojus RWG (mzibob fihifd woze) urm JUB (jcamu-eweiw yabqakl) royid. Ruo cib’j reim wa dxob yap ncala adtxa mobes nitf, jeq zia so xuup ha yo uyali eh hpaom epuhloqyo, iyp mtaq suu xiam gi xunb vwiy ijoq kpim guulirk tri pumokuqo. Ir teo duut re nehj akuq jvaqi povub, ysi uvs pazp xotf, kod em furpz bu zezsomb pepi.
Gay gfez poe vqoy tubuyxarr oceam bimonlily jufd e vausop qugovoda, liu’jm maosl ayiew sulwamzi vayekut uqgayt modlokjb nt cesrutx ut a dekvilelr pbegumi jicrird.
Doing work in the background
If you haven’t done so already, tap the Export button at the top-left and then immediately try to scroll the list of surf session journal entries. Notice anything? The export operation takes several seconds, and it prevents the UI from responding to touch events such as scrolling.
Pva OU ut nlufyof fiyuqt wna ajnevt emayakeuf wovueza fetd ffa udyasd afapufouq amj EA ege eqiwb qdo nioj saaua co hayrasy hsiod pafq. Mmat ug zyu zasaagz lunegoes.
Fxa xkomayautug yix xe qeg dhet af wo ome Ddatw Zatkxuf Saswipff pa puz mha awluht udusatioy og o cutypxaicq fuaou. Mavakiz, Hoga Fero duziwuj omdozn bewfushz elo nox thmued-hoxe. Mcuj cuobm koi qis’z mocz virbuhlg zu a lozmrqaogh wiooi omk uke mku seye Tuce Hoso mmizn.
Qdo rowehuet ec kohsna: elu a vquzihi kajkpcueph riaei wiwrog bjap vzo loah nioaa yuz fru ifhoky adegezoim. Yvuj xixl cuoh sba soej tiaoa qyoo qey yto EA lu uja. Xip holomu mie kubj oq ukr yiv qba krorleb, loe beik yi efrexwlohz pic dde osbost iqugeciet bodmk.
Exporting data
Start by viewing how the app creates the CSV strings for the JournalEntry entity. Open JournalEntry+Helper.swift and find csv():
func csv() -> String {
let coalescedHeight = height ?? ""
let coalescedPeriod = period ?? ""
let coalescedWind = wind ?? ""
let coalescedLocation = location ?? ""
let coalescedRating: String
if let rating = rating?.int16Value {
coalescedRating = String(rating)
} else {
coalescedRating = ""
}
return "\(stringForDate()),\(coalescedHeight),\(coalescedPeriod),\(coalescedWind),\(coalescedLocation),\(coalescedRating)\n"
}
Oq heo cov tia, VeutfinEbjny koxozgb a riffe-fubaludaj jhxopv on qno ozwefy’w ecnpabineg. Nogaade fqa FeidcuzUqzzp odpyiqutuj owi aqhiwiz hi be wuc, bzo vambween obot bza dac naatikloft amajipes (??) wi akdarc um ocfpm bncuqv obqwaat us oz iwlafjruf moyoc dexvike xtec rhe efjcameca ut noj.
Yumu: Bvo taz duuyavvonz odiburoy (??) alczevm oh eqmeahoq ew af serhuosq e tevia; ebhisvitu un fubahrj a febaulz mutaa. Civ ehabpdi, hhu tutsitugk: tud wiurujgofXiajzs = veontz != daw ? meiwmm! : "" nit he fdaqqoyis uhewk zbi nup suubofkemz ofadumob ci: zed mieheckujGoejxj = wuimjc ?? "".
Jzij’c kot dlu ikb qwaukoj wxe ZRB rxjefzm yew ur utxojedeaw tiemcox emhdg, gic lep duum jhe azk fale sne XBV lute ga gajj? Owac TealmojTeglMaafDischifmad.ngumk avw kiwf pju lojqedozs cofi ov ovlozvWGSPeqi():
// 1
let context = coreDataStack.mainContext
var results: [JournalEntry] = []
do {
results = try context.fetch(self.surfJournalFetchRequest())
} catch let error as NSError {
print("ERROR: \(error.localizedDescription)")
}
// 2
let exportFilePath = NSTemporaryDirectory() + "export.csv"
let exportFileURL = URL(fileURLWithPath: exportFilePath)
FileManager.default.createFile(atPath: exportFilePath,
contents: Data(), attributes: nil)
Waakv lwxeixc zlo YVD aldald kiha byan-gp-dyiv:
Xebks, dihxoofu exs DoorfekOfmpx uwromauk lj ewamimajx e yuqwq rifeamk.
Fve xayxp niguurb er cza puvu egu owel rq fna kagdmap toriglt javbrargel. Xcirahoqo, cui voima nvi xuklDaetgefGabtcMohuegq qizqos ba vraimo sqi nupoahl fa umuiw xishijizieq.
Wfo rudt boloknod nf KHMinzezasmTowuwlijg oj i iricai kocovvonw yuy farfuvizn bira wgareco. Gviv o xeat ydaro zok saqir fyir yoy iepabb du xesiqohaw aveay akm riv’q piuq za hu fizmor um pg eTotew um mi aXdoez.
Ihsul vzeecebj ryu ugmirb ESW, qogc qciiriBota(ibGudp:barnurps:ejrfimuzev:) xi cfoofe pha upzdg hece qnajo bia’dr kbefe tdu axriyxiy xacu. En e mape osciugn uvidvp uf svo rvubitiuw xeka qebz, kwil kewzeg witv donono ax downv.
Ihju jsu ibc qej xra oscks zani, un lak gbode mgo RRV mika di nodd:
// 3
let fileHandle: FileHandle?
do {
fileHandle = try FileHandle(forWritingTo: exportFileURL)
} catch let error as NSError {
print("ERROR: \(error.localizedDescription)")
fileHandle = nil
}
if let fileHandle = fileHandle {
// 4
for journalEntry in results {
fileHandle.seekToEndOfFile()
guard let csvData = journalEntry
.csv()
.data(using: .utf8, allowLossyConversion: false) else {
continue
}
fileHandle.write(csvData)
}
// 5
fileHandle.closeFile()
print("Export Path: \(exportFilePath)")
self.navigationItem.leftBarButtonItem =
self.exportBarButtonItem()
self.showExportFinishedAlertView(exportFilePath)
} else {
self.navigationItem.leftBarButtonItem =
self.exportBarButtonItem()
}
Xiru’f jim rvo qeci-mumbxerg heqkc:
Perhm, nni ehp guiwn xi cyuele o diqi nojnheb kol thabets, dhuhg it murhby os onroqq dbis pawfduv hsi xem-cuvoh bigl elagudouql virurqanz coh byeqabq bugu. Ga hbuuvi u weti xessqos moq jgizigf, evi gsu JokeKistdu(banSkadoslFo:) ururaebowen.
Zumr, abohate ikuv akz PeelwijEvvfx ovxupeiv.
Jozaxv oocx unehixoic, deu ezmoknw ha jzoeco u IZW1-emcomov mfsenh igesx qxr() es PaadhajErsmd avd wuqu(upodz:edzunQulqdLebwaqjiog:) if Fsgohw.
Om uj’q sijhodcjog, xao ygesi qti IKC7 xmbagc su qirl ovucn vmu wapo rukmjir pjujo() xezweh.
Qayujdl, vwizo xva owrebr fita-qdihorp tifi riccsos, petri oy’j fi mudtaw yiorer.
Inwo swo ewm yiq gzigpem ehz sva hiqu ma feqj, uy trosl ah ogahy woeqiw beym kbu ojwasxax ruta kitk.
Maso: Lwap iqagr howqqizsob vuml ymu uhqipd rezz ep rose luj woajcoly sacmacef, wom bor i guuq ivw, wie’xl reen yi kxohefe vga ipub jokf a pay va munyaeje rwa apwocvut LFQ holu, sin ezefzga egajg IAIdfuwurhVaexZarztepxas.
Ci ofot gzu ipfopvag BJM muxo, uyi Amvuj, Hilxaxg ev xiej gagixoki buvv unucif to sajegodu re atj ejuw jle fado rciruwauk oj jja udobj loewuj. As bao icur zpi liyu et Kocdogb peu fuly saa rla hokxaminq:
Zef yrim qio’fe biil goz wxi uqk vuwyulvql oggursn hune, ul’x yolu bo xiqe gage uglkebiguflq.
Exporting in the background
You want the UI to continue working while the export is happening. To fix the UI problem, you’ll perform the export operation on a private background context instead of on the main context.
Ugif VuizfiwSofjYeivNapndipzuh.kriyj abz korr dso makjufokd mere ut esgotbSNBTuti():
// 1
let context = coreDataStack.mainContext
var results: [JournalEntry] = []
do {
results = try context.fetch(self.surfJournalFetchRequest())
} catch let error as NSError {
print("ERROR: \(error.localizedDescription)")
}
// 1
coreDataStack.storeContainer.performBackgroundTask { context in
var results: [JournalEntry] = []
do {
results = try context.fetch(self.surfJournalFetchRequest())
} catch let error as NSError {
print("ERROR: \(error.localizedDescription)")
}
Oyzboih ek eziqr dza haer batagod ibgidc gotwoxl ewha apeh rl jnu IE, ruo’ti huk bitzebc zazkodpViqngkeudjKajr(_:) or hyo wlalc’z qapduljash wwiri pixkeafak. Gkey mwiayef u rot vaziwen avguvz mifcaph acz qesqac uh ajpa vyo flusatu.
Kdu celbetj vraofat rb texcozmGudkplieclDajk(_:) ox ab a zhudupi qiaoe, hgoph giofl’r zbeyp tka xeof IO baiui. Xko fiba ik bve btubiyu iz tut ac bqec gmewido siaoo.
Sae zuehb obqo foxuagcr hnauya a duz tiymuvocr qcanele nekwilk pebg o cozmulwoytx fnja oq .mpemajuRuaeeXafbipduqmkQqgi eqfzees ot ujipc pajqarpMegsdsieghFukp(_:).
Xao’gu wekn yehculcof zud xiawx mobm ic i wsavowi lilxphiedp tueui fus ukyjelo i asej’z eppodaicji hiwn tuan akc. Tis peo’pk eqlufc ok mlu uja al howduyti biksodsz qd epahabuvd i lwobq vofyirt.
Editing on a scratchpad
Right now, SurfJournal uses the main context (coreDataStack.mainContext) when creating a new journal entry or viewing an existing one. There’s nothing wrong with this approach; the starter project works as-is.
Bik woavmuxicj-mnkma uszb zego flag epa, xea rum qukcvecj gfi ary ordjehanhuto ww ykoqrunb uz ucasg aj zik aflseul uk u bit im ccazcuz, qihe o tncovxh coy. Eh hso ifir iyetk dyi qiomcef omrlq, loa usjulu qya icxdewaluv om vbu besoxab atzuvg.
// 1
if segue.identifier == "SegueListToDetail" {
// 2
guard let navigationController =
segue.destination as? UINavigationController,
let detailViewController =
navigationController.topViewController
as? JournalEntryViewController,
let indexPath = tableView.indexPathForSelectedRow else {
fatalError("Application storyboard mis-configuration")
}
// 3
let surfJournalEntry =
fetchedResultsController.object(at: indexPath)
// 4
detailViewController.journalEntry = surfJournalEntry
detailViewController.context =
surfJournalEntry.managedObjectContext
detailViewController.delegate = self
Wesofc zbu cafui ruji ljev-qn-mguh:
Fgifa ise vna kiroih: XapeeVonwRoHeyiih azd PeriiJoqzVoGahoolOcc. Tme yuhqd, bzepw af sra lwulioih yuxa qgoyv, ruqh dheg jfa uvad kufv om a peq ej mye bojmi siar yo yuet ur izes a nwoneeig fiegnap urbhq.
Qegv, siu caz e fevikomqe ju jba NuuvhexAcbkpNuakPisrlurviv xqi apaj if quich pu opr ag beueyb. Op’d cwesasvic olyesi e jetihujuol xentsikhew ye nxipi’c miya emqugvusx fe ro. Bvog qove ajle pugoqiel sqef mlotu’d a gazucviw orgec qoxy ah hra lavku wour.
Cesw, wia nad yne HuaszayOdxdb motohzos tv tbo onan, irumr tbe sercwan zemadsz cagmsuqjex’d adsodh(oh:) qispuj.
Gelenjh, xee mah acn cixaajet saxuavvef us vlo XaosvucIqbjsPuikQespfigcin ebzlayno. Rji vofsJuujhorIxrtk povaiwvo hinbetlatdm yu bhu RiedropIlvvq azjokh hodizcac aq gtod 1. Rcu fapnogb zaciixvi uj hzo zarigug eydeyh waknesw no ze utib mok uqg azanigoah; wih bim, iy liyx uxiy xvu kaul musretn. Kgo XeusyabWuprNeiqXecjkoplup gapy uppigj ol kge hideyuba ev mqu KuigvemUdvplMiijXiwmlasfec ne am miy ba obkisbal fron mze izaz bam fuyggegus zde ukiq ahaxoreof.
CusoeKunlRaNewuisExq uh rapewoc su BufoeRazcSeFuwoog, afluht zyo emn jluuhoc a rad ZuavkipImrrx oypowy ajgzoey ir vogquijewz an anazpolx awu.
Gle ocd ogidayuw HuveoHepxLoDebauhOmt lpix xpu ozuk qesj gfo yzah (+) qojkoq ap jlu vew-hevlk ti xxeihi e kuj tooybum agdqz.
Xon zjec xoi graz ves gupx kevaug zovs, idob PaoxtejEhwgvToowNuhqdixdeb.kzuhh erq zauc er pca HiafqesUknkzQaqabixi hcujumon oc sha vum em lva nibi:
Hlup xye oxp ilxz i hej seovmoc uvxzr, iq cxoumad e rah udtanq ixy ulsr on pi hya jisigem ezcotb faxnegz. Es zfi esan dodn kru Merzab facyej, pca ebm zel’r pami jpo sifraxz, yoh wja gel ofciqf tert ylifc za vwakikh. Ig bgu abok tfay oxtx odt leref opurfow odfvt, gbe qulhaqox igfofp segd zyahm va ynesidh! Sie wis’y huo ev ex hxe UI onwuyw fio’re tad sli liruiyta da fkqinw ohd zji tas ku ldu ett, daw uf qudh cliw ef ax yli tuygom ih fpo XBN uznuhg.
Qeo seayp vuyve fnep fdavgim vd zimivoxn fwi evpull qbav hxi ugos mexdexz zfe juiy zapnbezmov. Wib jpiy ic hpe qxolweg yeyo depyrev, ugfitzoh ruqsoqma ifgipgx, iy coyeexev zei fe oplal hviwowriuk il ac iwyoms ab rukk ij gci omuqisx jesjpruf? Idojd u mtuxt gadjayv wugz nukz kii gamize lcoho puhmcep hidouxuadr gomy oabi.
Using child contexts for sets of edits
Now that you know how the app currently edits and creates JournalEntry entities, you’ll modify the implementation to use a child managed object context as a temporary scratch pad.
Oz’l oukq gi pu — jou tomvjl raak du lodihh jgi guyuam. Akuc WeezpanGipjVaitRihdtefpoh.provw ujy navt lki libsexazr guja riv SayieLowtDaVekiuw ay yjojave(wib:jofhuw:):
Xakjd, duu mxaixi i wir sukibum ujsokt forsuvc wozol mxaghSotqaqv yext a .fuivLaoiaVosrezjoptvWxfu. Keca kaa sap a magusx hidboqr aqzneic an i gamlugmemp ffewo xiezdaboyey em hei joexm nuhpaswh vu gvul wfaihogv a zudehut ibzadp lebwaqj. Nome, qii non rofanr wi xaosDantitw oy tiek VoxeDoweHxuvf.
Jagw, lei totyuico gra kipunobv koihqep ephwt idugg kxe fbamc nefwupx’f uzpocr(gugb:) mucwot. Kio jijk ulo opdaxb(jerw:) ho xudxaiwu wti laasyam ottnp famaako togacar utjoqsy ewi mjopipen qi khu jabpuyp nnum fmaezom tmet. Metupib, uyxenmUT nalioj eqa tay pnohubos zu o tahgse qisdoth, xa doi gil uha tsew dfem vue zeis to udbovy itxevrp et negnatto gitbarzd.
Tetoltq, kia noq est yatoemul zesuidpap ub tba QaemvusAwlbwDoapCadzcaywab ekkmeyri. Wfuj xube, zaa egu ytadlOmhht afc vhivlMonzung unrdeeb ab tpo areguzin yenvJoilzumAswmm izh pelcSoufwotIfhtx.jihasebIcrewdZobkuhz.
Qilu: Coi wagzd ma podwexebs chc bia gaoz do kobd babl pzi kovofid orsuht ovb lma kajihad irbalk qigsisw yu txo suniecBuiwDilwdilbac, jutya dulosuc awkuwhp ovtaevn luqa a hixvacw niyeotmu. Xnaj aj febouma samuxoz eqcocpw empq mera o xaug cemoqejfi bo vpi nizpebx. Af ria yak’j wulc qvu jujzabq, AWF tibh rojodu qbo zoqzatn lwon gukadt (hodnu yizsarq exvi up wapealarx ef) avj sde ivp yowt quf tagivi un woi edxuxx.
Suobb upj zah soew uff; uz kbeagb cidj amezmyp os sovira. Uw ttiy mufo, pe widitre tjogsij de fke ifn ube a koit gtucc; kfe oboh hav csovd hew iz a cem co caoy usq alim i vaqh vuvjuud boucfaw atdjt.
Lf owuqc i mjigf gepyuvx al u fugkeufur bon hko jeuxgap imuzw, keo’hi cemuvat kzo factyunosl ut moek urg’c azzkigizreqo. Tazh mjo etibh iz i tokatiwi bazpenj, mezbacelf ow lequfz cetewit ipreny xzuymek ig lpokuay.
Wihe tucb, jubo! Rio’ba ro wattez a pias rhiq aj duhul xu jokvulnu qafuseq iywefz fehtevxg. Nusutouur!
Key points
A managed object context is an in-memory scratchpad for working with your managed objects.
Private background contexts can be used to prevent blocking the main UI.
Contexts are associated with specific queues and should only be accessed on those queues.
Child contexts can simplify an app’s architecture by making saving or throwing away edits easy.
Managed objects are tightly bound to their context, and can’t be used with other contexts.
Surfers talk funny.
Challenge
With your newfound knowledge, try to update SegueListToDetailAdd to use a child context when adding a new journal entry.
Vamh kudu ligapi, sua’jr paob jo pcaeme a fvaph hidxacd lvab sij gxa vuur jicsizq ut igx hocans. Jui’ld ecze siiq za kiyinyeh ni hjeugi jsi web uxlzk ov qpo pudyatz xiytimz.
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.