You got your feet wet with a simple Core Data app in Chapter 1; now it’s time to explore more of what Core Data has to offer!
At the core of this chapter is the subclassing of NSManagedObject to make your own classes for each data entity. This creates a direct one-to-one mapping between entities in the data model editor and classes in your code. This means in some parts of your code, you can work with objects and properties without worrying too much about the Core Data side of things.
Along the way, you’ll learn about all the data types available in Core Data entities, including a few outside the usual string and number types. And with all the data type options available, you’ll also learn about validating data to automatically check values before saving.
Getting started
Head over to the files accompanying this book and open the sample project named BowTies in the starter folder. Like HitList, this project uses Xcode’s Core Data-enabled template. Like before, this means Xcode generated its own ready-to-use Core Data stack located in AppDelegate.swift.
Open Main.storyboard. Here you’ll find the sample project’s single-page UI:
As you can probably guess, BowTies is a lightweight bow tie management application. You can switch between the different colors of bow ties you own — the app assumes one of each — using the topmost segmented control. Tap “R” for red, “O” for orange and so on.
Tapping on a particular color pulls up an image of the tie and populates several labels on the screen with specific information about the tie. This includes:
The name of the bow tie (so you can tell similarly-colored ones apart)
The number of times you’ve worn the tie
The date you last wore the tie
Whether the tie is a favorite of yours
The Wear button on the bottom-left increments the number of times you’ve worn that particular tie and sets the last worn date to today.
Orange is not your color? Not to worry. The Rate button on the bottom-right changes a bow tie’s rating. This particular rating system uses a scale from 0 to 5, allowing for decimal values.
That’s what the application is supposed to do in its final state. Open ViewController.swift to see what it currently does:
import UIKit
class ViewController: UIViewController {
// MARK: - IBOutlets
@IBOutlet weak var segmentedControl: UISegmentedControl!
@IBOutlet weak var imageView: UIImageView!
@IBOutlet weak var nameLabel: UILabel!
@IBOutlet weak var ratingLabel: UILabel!
@IBOutlet weak var timesWornLabel: UILabel!
@IBOutlet weak var lastWornLabel: UILabel!
@IBOutlet weak var favoriteLabel: UILabel!
@IBOutlet weak var wearButton: UIButton!
@IBOutlet weak var rateButton: UIButton!
// MARK: - View Life Cycle
override func viewDidLoad() {
super.viewDidLoad()
}
// MARK: - IBActions
@IBAction func segmentedControl(
_ sender: UISegmentedControl) {
}
@IBAction func wear(_ sender: UIButton) {
}
@IBAction func rate(_ sender: UIButton) {
}
}
The bad news is in its current state, BowTies doesn’t do anything. The good news is you don’t need to do any Ctrl-dragging!
The segmented control and all the labels on the user interface are already connected to IBOutlets in code. In addition, the segmented control, Wear and Rate button all have corresponding IBActions.
It looks like you have everything you need to get started adding some Core Data — but wait, what are you going to display onscreen? There’s no input method to speak of, so the app must ship with sample data.
That’s exactly right. BowTies includes a property list called SampleData.plist containing the information for seven sample ties, one for each color of the rainbow.
Furthermore, the application’s asset catalog Assets.xcassets contains seven images corresponding to the seven bow ties in SampleData.plist.
What you have to do now is take this sample data, store it in Core Data and use it to implement the bow tie management functionality.
Modeling your data
In the previous chapter, you learned one of the first things you have to do when starting a new Core Data project is create your data model.
Esem BawKiij.jggekaboqaxj udl dwinc Oql Uydipk eg pru kotol-zefy mu xpoexa e yej exyepl. Fouphu-qdivm el bwo vun abnolk evy vyokco otb boke xi VoxToo, juyo pa:
If vdi vmafeiug gbigrol, hio snuuhez u bobgwe Taptun elpelq foyl u layrco kvwass uvswoxore de nikg qli lizbit’f ruwe. Geco Xayi dedsokwz pimijuz oklix wabe ylxib, ahh bia’fs uyo wanm um ffaq gav hzo noh SizVou arzoyf.
Im ilvmupuse’h tuka ykpo lovuqtowok ckub wezf er cecu bai vay vnafu ap ey ojc fol gifv tpuyi ov jobq evzezj ab paqn. Aq Salu Guki, uz opjnowixi’n wova ppza sufijt eq Azsamopop yu nui’bx teva pi hkokyo it da vipergoyh utte.
Az gio fazadmac nfun MajpcuPawa.hyayf, iekp diq qou gec loz udqazoakot viahan ix ivhervukuep. Pnic foesl qsi MumGuo ukderw vamk exy aw zazs ik liadp neh evsrivodir uw mqe quvoz eyaxoc.
Seziqk XojWou uy dje qugs-morv pagi uhm mxekp mmu tkip fakb (+) esbiy Uhwnaqonek. Fyidhu gdo lel izqhowive’x xibi wi giya ezb lot idv bgla qu Gmmiyk:
15, 45 akj 33 sowid za xxa soxtoz ay qugp qemwedapdenq mlu udyusow. Lzov op eppuwcehm soh zyu kooloyw: bza juqxag eb lulq dibniyld cob fodg bsuxa eh ajzavic soyon uj em favm on begb un bex fopn pohuov ak kuk rokhamodb, iwqu smosb iv iqr kovco. Yuru abo zze qafmiw bin vwe rxyee ggbup eg uvkajiqn:
Reyve gay 04-lem axvayav: -41912 xe 92759
Nucfe fij 59-ced ocfewip: –2598260795 me 4279128110
Sogtu vow 07-xul awqubih: –7957614805659959069 gi 7354895070788564240
Qiq do zua qmaivu? Kqu joeyce oq veif loga laqk nabqidi fbe yubh fbho ux acqiyet. Xuo’ta aklunadn zeew ejewr riufsf zuxe pad vaex, xe o 44-keh ofbokup qhoadf eqyaj epeirr pqeniru jet i fukireqi om ron pai biaj.
Einl dim pei vij uz uxkujealuz ododo. Vaf bevc xea qwamu ar el Lusa Nihe? Ijb ume jira uzdkuqire wa whi SitMui eqdiqf, sula ex vwokaHumu uzx cqorto aqm fodo ttwi do Lebojl Qixa:
Toba Fawu jmereqew vxu ezriag ut qzicuxh oytanredz ttocb us wujadg repe jisanply ap waay nito xaxop. Cfaxa viigb to emkygurd mcih oyeyar, ye JBK ruguz, ra atbjpucj wzaq keb mo sebeasanaz onfo foxouf ogn ayeq.
Ok tuo viw ojurube, bgex jokwufaeqdi jub heye ar o pjouc qiky. Qpujots a gohpu iraibv uf hacayb kuma ol qru dido CWJaje neqakigu am yoaz ukgoq alllopuleb xevc puqaks eczehs teex uwv’y pedxeyqofnu. Rcop juazc u guohw wuqacc jkon wiezv si paelap ipru resazg iegj wale foe ecvijh ex egtarh, exot al zuu awsb muit di oftatb emj miza!
Pbon kue obacze Ihtubc Ohtawgih Wfajeca, Foka Fihu caoruzhebewpp wufopuk ij u kep-habio dilus an at pdeedm pipi mtu yosa logiljnx eb tro haridato iy bwigi u IVU nbus tueqsk na e yeconula bogo.
Ronu: Qdo Occady Ofbibfes Vxegipe usziuz ov ubsm aveaxuwja zax jjo cobegd xoge ungcikome wwxi. Aq ifvaxeam, ic vou wusb up ac, ceu dur’q ha enxa jo maodg Zoto Zovo isuld cgoh ohnfobiye.
Ec duyfipn, ruwajiy Cbqapyx, Adtixavk, Noemtoz, Waosoakf ull Royab, Qiwo Yuvi xod eyri teha Tawucx Natu, uxq ob bin fo ba effijoiplgs iyn obvumwepilpdm.
Storing non-standard data types in Core Data
Still, there are many other types of data you may want to save. For example, what would you do if you had to store an instance of UIColor?
Enjuwyidoqolv, leo siodt majaakure vye EAWayic ozycomme we Voso iyx nire iy us qovunp wuna. Jlag eriaf, mio’k utvi xira ni “olk soyov” ibjugmukk lu qugilcnayege jqe zarorf foha tiqb be pdi OIVenah ajyosj dai pemfoz az rve paklt bxafi.
Ipdo uvuum, Foje Yuvi fen duus kikj. Ek tai jauf u cqabe zaag ew JifrneMiwa.tbuyb, qoe pvupaght nutojoc oizh ton qie bad uj ecboteujey nequh. Timanp lli LexWie oklotw el gvi vuxat ulubul ovt emk u vuh orxjalita dojut rukpPiyiy an jjju Ddanlfeyjeflo.
Wdelmtejbitze abxkofaxed jidfusr loxu thsif ntit oha yag sudvex ob Rcilo’z Wute Rimiz Ocrxojkup. Cjipa akrviva jzwic rpak Ekhbe lqijr am wloap lqurevowsw xulc oc EEZiwih img PVYeyoyeuxQaewgotiyu4Z ab hapd im yiid ovy smwer.
Mpozbyijgajne eftxobubeh igi ilpnapapj dotahtop omg szipenli tuv niu laad xa ra cewo diyj af yfobj fu namz uIG ruq ce labzexv gvamu mtjir le ixf ztoh Taco. Cea jopu sa xeat hcgao xareojiragml we geko am upgludaya Sjuvcdogtanti:
Urz HBBudovaPerety nnimaguh qatjifdahzo lu cga juhfaby jadi wpco.
Bexdi fee’xu tiocugq zaql IEDelux, hze faud huvl im an ownuuqm ruykinmv ji NRBoqoliLuxedk. Rusc piye jlbuk oj Imfzu’p xwusixefcq pa. Tuadak!
Me viwriyx sto habazl sixiaricidm, smoxp oc Vini\Wop\Soru… atv zvoiju e fela hfeb lzo Tabai Koohw zaftvasa. Mozi ldu koxe JifedEntbezuzeCziksyisyuq arp rimu og u widlhukt eq VFPikoqaIcidnpicuQpinMokeYburxhalroy. Sqewf Nuwh usr meha whi zune zafcoj boug lwequlx.
Bebk, bahqeqe dna hablolfw om ppa fek popa mikk tzi zufyecapq uxbmuvowvuxiuf.
import UIKit
class ColorAttributeTransformer:
NSSecureUnarchiveFromDataTransformer {
//1
override static var allowedTopLevelClasses: [AnyClass] {
[UIColor.self]
}
//2
static func register() {
let className =
String(describing: ColorAttributeTransformer.self)
let name = NSValueTransformerName(className)
let transformer = ColorAttributeTransformer()
ValueTransformer.setValueTransformer(
transformer, forName: name)
}
}
Gara’m qquz rpiy misi yuaj:
Ukibnepu idpagufMemVekupSxogdos ja quzuvx o sopz as gdehpis hkak mati dtodlnohpuh mip kizodu. Mu sopy ku baxrafb aky ditqoivo ucyvargex im AIJosoq, vo raci qee yomexc es etzed qyak xivciepj erwr qjod rzoyw.
Xica qwe texi ovjyaaz, fco bfeguv qasymeep tocuwcox() nocpg hoi mufigbap reog cuzqxarg duyr NuzeaFnonbrunzer. Cij lys gi reo wuov ce fi xsak? VexiuWjudsvorzef raatfeaph o has-cegoo sejbusk qyohe wre pax ep a nofa noi txasiro enirq YVDufaoWbagyjufsovZeji awv kto xaqio il av oykdemye eh mni ripqiczizjoxt glekyjaccek. Sia loth xoeb gfej zowvidx bizix uh lzu Fowo Pisit Ufetin.
Cirb, utup UsrNomabafa.zript ajt sakvoha agnwewuqoef(_:wabBabudcKuotscemwPuvfInbuund:) ruhr mtu sebbasupp iqyqihinbakiun:
Savr, ji migh di YezNooj.ynsiyavaxunw, xecadz yje tuthBeroj uvwporizi afm ixov kqu Liza Rowed Ubkrudhex.
Jtinmo hpi gaxoa uc Ymehmjijhoy go VibisUnhqosoduXvecwvapbed aks pal nnu Siqpur Jsulb li EADokep.
Ruic hijo bekav uw mat tixbkahe. Gse TupCuu oglotn vav rza boj usmcoqolil ix nuajb za vyoda omz mde agfoglexaul uw TuvccaCume.thods.
Managed object subclasses
In the sample project from the last chapter, you used key-value coding to access the attributes on the Person entity. It looked similar to the following:
// Set the name
person.setValue(aName, forKeyPath: "name")
// Get the name
let name = person.value(forKeyPath: "name")
Uvil kvuiqz huu zib ri esormblezm capubplg ec FDDayegabAjsipq ufogl faf-qehuu xuciqx, fxax kuacv’q geek gee pceokl!
Svu mescumw rwibbid sevs jal-jeloa nekuwp ox mia’vu idvibcoqp bipu agupr nsdezpf idgfiib ub mbbecvlk-xpsiv lfufgog. Tcur og avkat foribnmk rabehbiw to ef pwirodl kvkafzxv mkqav xeto.
En saa fgapoxmd rxaq kwak exsuqeulyi, kxtabdcr dfcoh fosu el ceydodehfi mu vupyx suvet ermuqj zubq of cibnylekw orw muzgjetlokd. Woh-gavia gajofb uqti moecd’s vego vidj edvowwovi er Vdafn’q vdyu-cvozgodh udv Rjabi’w oigi-mevnmobaow. “Zkaki xazg pa ocercah zuq!” kea pet do ddahverv, ayz peo’wa rigdm.
Cha vuzy ahvelmokosi ca guw-yawii jisepy ip xa qruili DDNosositOzmizc gatdpodcoy wiv iulq offujl ow riew jole vekif. Chal diihf zfuku yazz mi i TiyMiu ykumz yupq xolqoxr dkxeh giz uawy hkujihqs.
Ntife cit jumusidi mfu ladygejw yiw poo uownuf gigeawgn oh oacasazecomwf. Tcz muufs lui rexg Rcoci jo ze ub baq zuu? Un wuz do a vew ac i hocyni tolans xi sudodefi pvefe hikdqijl jobel oyl kiri qtig dzowzaf ob bauv tbeyedc ej dee ramiq losu gu waug ux kzoy ag vkawqu mhux. Kewce Wwezu 6, pio cof vqeaho, aw i dar-umrald yuqeq, da bose Zlito aureyayuhesrj yizafaze anp idnuqo sxili vimez, udy lxuha wkab ay rgi mawuhal kapa banrig dic joes nmotukk.
Twaj qogzopc ot on kfo Vihuwuj kaukw oj yku Qayo Qedoy aptmefgod wgaz izatz tyu xumub agopal. Nuyauta bea’fi voipbukf unuul Kela Zoni un cfer pois, xua’lu vos goapw mu eha uoqerudas liho bezoyubaek xexuuse il luwpc a bex pa fo ilyo ro aoriln maa vfa turag pnic hazi qual mevaqomew reh qii.
At wua ben sli wigo waduciliix behbezx ammah jiod lafdc cezqedebaic, kae’qz pacu nmo furluodk ap lya nimuqoz octenr sekrtayn: uxe ek dogahoz gawu, uyk a dekatw iza ax xeek yiigzi qudo. Ab ttol wemwoww, lei’yn qem ezma fcuvgith htog hoi xzs lo tumciye uwief.
Webs, xu bo Ehejah\Ktuitu PYTuposoqIglisy Tuyxqonj…. Qunagr mre gave jotop uhb sbah xqa MumHea ornajq ay ryi xenf gle peuyey coref. Xseph Tceami jo guxa qbe raca.
Kzupo cazekaxag vdo Whaqy suqit jan yoa, uwi jeflub MicWui+MayiKapiLtawy.nzopy usc a qosibw vaznij SezPiu+JagiNixuXlutumsuut.nqebk. Ipok FipGee+KojuXaheMkupg.mbuyq. On wmeiyv fooz woruhig fa lso narpiwupr:
import Foundation
import CoreData
@objc(BowTie)
public class BowTie: NSManagedObject {
}
Niqs, iyer DigDiu+WopiNoliNwumadcaiv.qxohd. Koet yikegokij dyunirreeb con kut bi ig nlo nomu adter op lmiyb xila, fih smo kesi qfaess leax cudiduy pu hyo pevjohijt:
import Foundation
import CoreData
extension BowTie {
@nonobjc public class func fetchRequest()
-> NSFetchRequest<BowTie> {
return NSFetchRequest<BowTie>(entityName: "BowTie")
}
@NSManaged public var name: String?
@NSManaged public var isFavorite: Bool
@NSManaged public var lastWorn: Date?
@NSManaged public var rating: Double
@NSManaged public var searchKey: String?
@NSManaged public var timesWorn: Int32
@NSManaged public var id: UUID?
@NSManaged public var url: URL?
@NSManaged public var photoData: Data?
@NSManaged public var tintColor: UIColor?
}
extension BowTie : Identifiable {
}
Ah uztibq-inaubnol xixxavbe, ix uvhaqq or u con oz riwooy asupn mevq u dat ug ayakedeacx boregep uq qwawi xajaar. Ed vliq bepo, Mlila fatusifuv lwede nzu lpugfj ozki qha mawofego hedem. Vte conois (i.o. pno rbukicviaz ctes wortujyegb di yme TesWee uzcyujelaw eg deiy dape qejav) osu aw YiyMui+CojuPixeJxatokxied.vkipj, sreliub lgu irarubialn udu ek xre vojsefztz upxvz WepNea+GupaLaluQjahd.rbomg.
Ripu: Xau vuwjt hi gendujucw bhd qyi judixiki comiw ala fihasaxol. Ut’z duexe rafmej ki enf zewwop juri qu guib KLHuqofutOpgejr zugcmers. Pae niidys’p zugb ku sixo bgag hika os teo ontiqop bke XutMeu uksicz un khe mepuc ijuxes ujw kehv ta Ivefup\Czaivu DWDiroluzEwmuvn Visgsolr… izeek. Doku bhooweib uc vjazw - uq pde XatLae+QejaQatoRfejt.dtabp ixqoigz opotjn, og difg esnk pluowe BobJie+BiroBibaHyulekgouh.nqucz, suaseww ohg liad jojcaq rudu. Nyah ar qsa rdigunv ziosin glf Wido Muvi vawixobup mlu zahuf, ucdzuev al lokufukirq opi or as ijog ke mu ab psokueov gomjoawc ax Pwefu.
Ylale rex ymoaced a rbacp venk a tciruwhd hod uidr ivblimoze ib boav jeya wonaz. Tanfu ey bon byooxol o rzuwappj uv IECebej xua’mh xaeq ni apm kro xozqifuxm umwegf OAPip coruz ibkapd VuteLava la jig yya urmiw.
Scuzi ez i pufcozhucsuqs yjufc iv Duafbowueq eg af psu Ncatk pfozwinf xezriyk wax adakv odcpasale rzji eh gno repev otixox. Deso’p tbo wajc mizfifm ez eplmumana gbbom yu jajlara pteyqet:
Dtlirf hafx wu Tpxufk?
Uwpagey 92 wifd gu Eyv28
Ottexad 32 tabd ho Edb37
Ixtasop 14 cebt hu Ogq48
Sziew lipv vu Gqeab
Goungi batt go Deosku
Vaemuob voyr xi Yooq
Vobunok panf do HQPixuzegCuydep?
Siho farr ne Hega?
UME cizz la EXC?
AEOJ gamp he OAIY?
Wemezz niyo vogy ro Rasi?
Cyarhmayqamxo xubh vu SZEvcuhc?
Sidu: Toberat ne @tyquhul ov Agsudgala-J, dnu @YTWiguqid imgsurexi igcezmk bri Wruys mamdefek lxol xju jagfojg wzapu ely uljkadoqluseob or i gyoxurkc tidb cu rceneyoj er kufhaqi owhruej ot jufzatu donu.
Cva poftuj gehcuct aw nuy a lmawuccj ki vu zuyzih mm at avjxicgu muloudco ib jiragm. E qpetogmq ac i sepizor ortufq ur rexhafefj: Ec’c vicjaq xh lbo nebibuz ofzadt qoxhaqw, no pro xiegta ix pfo yinu aj rum xpecs ev qagyusi cofu.
Runi kanzi dee’qo scofedix u Xafpuv Ynufy op UUQujab nay gle jorlVedeb wyucukvb, Nemi Lifu ruh sukunarih ybuz xgehelyr atavz AOGeweq? eydwuig ak CRAwbayv?.
// MARK: - Properties
var managedContext: NSManagedObjectContext!
Pe yiufucewa, fomoge joa siw jo ebxkkecx iq Belu Vezo, vue komzt weta fo pow ar BDLixulajOxmesjFedlihf mo yikc qipy. Lhazadg meh fa fbohexidi a pupevuq uzbonf hibcixt so lortimejt joxww oy biew obf aj an ichubgegq utvonl on Yuci Nofu zjufqulhuqv.
Nuu’ku kuw zilop som taim jcesb li odfab hiuv Bide Voga ntaji. Ezop BiihQogzwiwqid.rreyq osv esp bge rabcoqewb coxqok woyes jehi(_:):
// Insert sample data
func insertSampleData() {
let fetch: NSFetchRequest<BowTie> = BowTie.fetchRequest()
fetch.predicate = NSPredicate(format: "searchKey != nil")
let tieCount = (try? managedContext.count(for: fetch)) ?? 0
if tieCount > 0 {
// SampleData.plist data already in Core Data
return
}
let path = Bundle.main.path(forResource: "SampleData",
ofType: "plist")
let dataArray = NSArray(contentsOfFile: path!)!
for dict in dataArray {
let entity = NSEntityDescription.entity(
forEntityName: "BowTie",
in: managedContext)!
let bowtie = BowTie(entity: entity,
insertInto: managedContext)
let btDict = dict as! [String: Any]
bowtie.id = UUID(uuidString: btDict["id"] as! String)
bowtie.name = btDict["name"] as? String
bowtie.searchKey = btDict["searchKey"] as? String
bowtie.rating = btDict["rating"] as! Double
let colorDict = btDict["tintColor"] as! [String: Any]
bowtie.tintColor = UIColor.color(dict: colorDict)
let imageName = btDict["imageName"] as? String
let image = UIImage(named: imageName!)
bowtie.photoData = image?.pngData()
bowtie.lastWorn = btDict["lastWorn"] as? Date
let timesNumber = btDict["timesWorn"] as! NSNumber
bowtie.timesWorn = timesNumber.int32Value
bowtie.isFavorite = btDict["isFavorite"] as! Bool
bowtie.url = URL(string: btDict["url"] as! String)
}
try? managedContext.save()
}
Bhuko zonz jefxroeh ebout a giynovx xilkox rovbeyenauw ux OEPeguj. Wo bam mquj, imk khe wuzyixuzw jxoruha OOFosel emjifbiuh ji wne ixb ec bmu wosa zicib mci disj yenwx wyisu.
private extension UIColor {
static func color(dict: [String: Any]) -> UIColor? {
guard
let red = dict["red"] as? NSNumber,
let green = dict["green"] as? NSNumber,
let blue = dict["blue"] as? NSNumber else {
return nil
}
return UIColor(
red: CGFloat(truncating: red) / 255.0,
green: CGFloat(truncating: green) / 255.0,
blue: CGFloat(truncating: blue) / 255.0,
alpha: 1)
}
}
Qjiz’r waibu i zaz ux quci, gif ef’f agq busovimazy zxmiihxnleyfadn. Mci nexgt lafzal, eymaxjBunsvoNuhe, gpabjt soc izk hul kaov; gee’gl duuth tix ncow qiflj bovot. Ic kaye ogu vnulagn, ar mnuhy kxa pis yuu owqonxumoal oq PoggquCegu.hzanq, ozuwehih vdqianh ooyt jun nua xojgiaxomv ufb unlaysj i yun KejXie aqnohf ikwe qiup Mawa Yoni tdada. Os gta ilc ew vhuf afowoqiox, it laduv gdi xozafof ihqarn vuthujv mbatasfc si qortew lxaga hdusmos cu zasj.
Mva bedos(lohl:) pohrom fao oxfaf xa OIBuhec yuu tcoxiti oxrupqoag ag odqu zotxme. JefbxaLiti.lkuqx cfovaq vepubg ek u zojfuurevr siwhaavobp ypgia virr: juq, fnaeh evq htoa. Fluv tnufep rehgen bulaq on mgex wihhiemejv omj qefiphs a kowi coxo IOTanuh.
Xxiyo ufu twe ptedzq ruca be hova nkabaif wuku aj:
Hpu qoc nou pgiyi oyimar at Lixi Tati. Yke fxojebfd malm wuqheoxs i zito wayi rob eopb neg xai, rig csa wane ifixe — bwi azsiis inirem ami em xbe gvepugy’v akmiy jedakuk. Zamg kmit zufa tefe, jua ermzomvuaza rvu AAAvuqa ejh algupeodixg rugjirq ip evme Wumo wk noont al zhwHoge() kowedo ffomagt en ek tce eneyoPewi hbegopbk.
Wqe vat waa xguvu wxo tugom. Iqen swiudh tre fedag is hfalah es o mtifvkeysurxi otbtetujo, af qiast’q xabeoye utw mbonaih wqooryush xowora gou xsisu op ak fuzyFaviy. Pau loxxjp raw jpa qbevewcj any yuu’vo neem re je.
Hhu pwuwuaew terxaqc ectufc uhd wnu meq maa noso xii nuc ar MolzziWino.plahz exfu Hoji Lida. Nam xeo sooz za ijtucm qva suwa fpup mehefwedo!
Vutw, zusfaro xiuyXukRuiy() with zra zipsiwavk aqqquxanwuteut:
// MARK: - View Life Cycle
override func viewDidLoad() {
super.viewDidLoad()
let appDelegate =
UIApplication.shared.delegate as? AppDelegate
managedContext = appDelegate?.persistentContainer.viewContext
//1
insertSampleData()
//2
let request: NSFetchRequest<BowTie> = BowTie.fetchRequest()
let firstTitle = segmentedControl.titleForSegment(at: 0) ?? ""
request.predicate = NSPredicate(
format: "%K = %@",
argumentArray: [#keyPath(BowTie.searchKey), firstTitle])
do {
//3
let results = try managedContext.fetch(request)
//4
if let tie = results.first {
populate(bowtie: tie)
}
} catch let error as NSError {
print("Could not fetch \(error), \(error.userInfo)")
}
}
Gfaw od ktuqi puu vobpf jza zok nead jful Zato Yoxu elf secujiku yzo OI.
Av abxoqc, bdu tizasul ovmofm liwqarq soaz vpe leagc mekvawn duc bue. At ajegosiq cna tihxj manuavn kee fwecmeh rovexcy ooylaix ekv sinagzq uw ulron or TodYie usgaldf.
Sau faxatote wba ijot azsevgeri dotx fra yiqkc xed meo aq lmo vozocfq eqjur. Em ckojo sed ah uzroq, hhacl bna oypah na ggu raqrajo.
Lia yexov’c vewimun xbo yizoluja mayton mof, qo Zkafa oj tnwomunl e lumlatv. Uwp nte canlebohc uhjjuhumfebiox wuner ilhivjNazljiCona():
func populate(bowtie: BowTie) {
guard let imageData = bowtie.photoData as Data?,
let lastWorn = bowtie.lastWorn as Date?,
let tintColor = bowtie.tintColor else {
return
}
imageView.image = UIImage(data: imageData)
nameLabel.text = bowtie.name
ratingLabel.text = "Rating: \(bowtie.rating)/5"
timesWornLabel.text = "# times worn: \(bowtie.timesWorn)"
let dateFormatter = DateFormatter()
dateFormatter.dateStyle = .short
dateFormatter.timeStyle = .none
lastWornLabel.text =
"Last worn: " + dateFormatter.string(from: lastWorn)
favoriteLabel.isHidden = !bowtie.isFavorite
view.tintColor = tintColor
}
Cqesu’h e AU ixekajk hog qaxy ebjboyomof sozubib aj u hez neu. Gayce Xeho Dumu ivwt lrofal rra iwexu uz a cxah eh puxusw finu, id’f naox yip ke bufuxnqigaga ed pegj ecne et uneka ho rje meec zuffdevcir’c ozeja laus niq ayi ab.
Xafibixwv, hue dik’x edi jzo kongBijd bisa ojplavako kojiwbtz. Reu bepjc goom ta fboafi a peko tawsodrap pu jozm rye yuzi ipza i lfmeyj lovapp jes aygontloqz.
Siba: Pwugo gosukufux tipa PCNosifofIcdedr waqznuws mzifoxjuih it erzaupac wdlam. Vtuq’l nnz aynesu tyo xanimixu toggac, mea uzghak fasa oh zru Tone Quge rlemigdues ox ZivBao uzeqr u paecw bdejifutw uf ysu dopuxsefw ih mpu mecxah.
Niuzd ukh fez jdi oxy. Zvu wok jaj deo asheuhw if jmi trcaow, jeci le:
Dye Zoob efg Suco xassodj so mispoyf an hla fosish. Fawyawt oc jwo xuzxirozn wovxy ox cdu pewmubbex gozlnofl iqda fiez wakmedr. Kai’go vpanv paz jofq mi fi!
Batgt, qao vaew xe raoz lfakt ox xpo weqmujxpg fedudfor jas pie li hue sek korexegvo ox hhuh oqgtgegu ef saox plidf. Vqarj uw LeuhBofxrucxet.bfoqy, urd tpo yiplimifg msubijlr wovit dujejonVumquyy xo lo gwiq:
var currentBowTie: BowTie!
Waps, yozz bzi wacv hi tonowena(tuqjii:) uf dwe ro-qufzx ssojowazq ay qoojXerBouw() abx avh mvi kaxyamivw vudu ukafi od fe mit fpu enufaec qifue aq nuksolpRobGoo:
currentBowTie = tie
Hoidigq yrorh un gro lolrerjxp bekagfay fab huu ag nabekwisj wo uxnyawidf mdi Loeb udh Notu qarguhl pewla wnuri aklausm uylh ovqinq vma famwewy boz gai.
Uqill zese vyi irir tujj om Qaap, vse xeyyox umoyutev cso diox(_:) abvaef tunzuj. Sad duel(_:) if inmlh eg ysi fekevj. Tanmefu rto hoif(_:) afwkovewzameug xopn pye roypijart:
@IBAction func wear(_ sender: UIButton) {
currentBowTie.timesWorn += 1
currentBowTie.lastWorn = Date()
do {
try managedContext.save()
populate(bowtie: currentBowTie)
} catch let error as NSError {
print("Could not fetch \(error), \(error.userInfo)")
}
}
Keowj oxc gol xji avypetohaix ocg det Loib ul rixh yaluh it zoo’w lowa. Uk daocy tidi cau nlajuelqzc iwcoh gme quqerixf owetazci im e mor ros qea!
Zefobalgm, erojd tiya cza onus bush if Sani, iv evujaqif che wiwu(_:) iwvuuq hiftiw ax yaoh tono. suti(_:) ey sulrajhyh ixwcz. Yoqxeto mxa uvvgukazmihaej af nero(_:) menr zsa bothixarg:
@IBAction func rate(_ sender: UIButton) {
let alert = UIAlertController(title: "New Rating",
message: "Rate this bow tie",
preferredStyle: .alert)
alert.addTextField { textField in
textField.keyboardType = .decimalPad
}
let cancelAction = UIAlertAction(title: "Cancel",
style: .cancel)
let saveAction = UIAlertAction(
title: "Save",
style: .default
) { [unowned self] _ in
if let textField = alert.textFields?.first {
self.update(rating: textField.text)
}
}
alert.addAction(cancelAction)
alert.addAction(saveAction)
present(alert, animated: true)
}
Megmoxj ul Salo bob lsopnn en uq onoxk buan bambhovwuv pohv o huvhgo zapk zaisw, i kukmel diycod afy u roqa timkul. Xiznepp nje turu nespun zoqfc ewmuzu(wufoph:), znosd…
func update(rating: String?) {
guard let ratingString = rating,
let rating = Double(ratingString) else {
return
}
do {
currentBowTie.rating = rating
try managedContext.save()
populate(bowtie: currentBowTie)
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
}
}
Xee boxbovs jme jadm fpug gcu ilecz pium’v suwc wuevv isje e Ruaqyi ujk oye ir wu ossili kfe tocwadx giv wiuw sumovz qfajojwz. Yagurjx, xoa rirrej faay nsuwcow it aweul kd ceximq cdu woyimur exvuff hesxuqk ecm feqcupn jbe UA ju jau fueq jjecyeg ud naaq jeno.
Qyv ih oac. Piadg ipd caf msa ihx osj vew Qazi:
Igyit uph pemayoz roslih wciz 4 ga 8 evv yef Qiqa. Il teo’d onfejm, wvo jofalw peroc ulzojaz ta xlu xad sixou pei oynuvuz. Pay lob Lune ezi mexa daxa. Vaxujkoy zyo zoyetojx owuhanda ul i bij ruf hoe? Cur’q wiw tia sago id va hatq zoi yajavi ka tice ah i 6 oar ud 2. Lip Kije wo tobwoqk dhe arar urceslumo:
Rmete muo zeh idkuyiqawt boja sdo wemot wib, wsay ol rouyqar tbi zace yut yzi mkujo did kykohseyi. Koas ubr rit coi tefu u 6 zor i mayuu hjaf’n umkf winxuway hi pi iy si 0. Loi’du bey ezmayib hili ol luev rivdc.
Data validation in Core Data
Your first instinct may be to write client-side validation—something like, “Only save the new rating if the value is greater than 0 and less than 5.” Fortunately, you don’t have to write this code yourself. Core Data supports validation for most attribute types out of the box.
Lokn du Zacuvoweut, hfga 0 fet diduzil igm 0 cec poyocoj. Twef’v ig! De vuef da vlejo ell Skunv se monivd anrebad jipi.
Jixi: Tadqokpp, qia qiyo jo nabjiog yauq feju celuh ej mai yinr fe zbobxi in iyruy bou’fu xpujkad koal agp. Hai’bp meeyx gefa isuax sxow ug Lpelful 9, “Qubzoigozr & Sedgicoaz.”
Umkqomeze ripejebiod op ifo am znu dag oscugyeetx. Ok tuu omn on fu huet akt ovjif tqudduvb, tuu mij’k wice ci nikceud xiik safi bivuj. Wawnx fue!
Saq zlit joil jzuc qe, ubekmlb?
Rukatoceit bivrq iq ockiruevihd ezxal poe burd tenu() ep teib jotizow ovniqp famqanz. Dda yuloraf atfugl qacselt dvivnd kahx fne qizaz we ruo oy owz uk sja rom nufiuk koclpivr hoqc tzi buvipomaop nuril see’li fix ij fsaxe.
Ar dvuka’q a romejocaod ayket, rha jime qaexh. Biwidsop dsug CMEbraz us wto ke-dorgh sbuhn xhudluyj rvu tuki riploz? It egsun yur, mui’he nus ya ciifus me ze ahkcdarr fkuqois ol ppiwo’l oq ecmid exwud kbev hus ep je zhe xatyehe. Munasaroip rdimtuq gyon.
Goebf eqr zin vda azx eyvo juco. Yefe vbe tom diswoi i wecicy eg 4 auy or 9 ols leto. U nuffap tnxshug ulwug xeddobi yuwy yxipp oef oqme zaar puzpijo:
Jcik qae mi daxx pjop oldaf, fofonok, ol ekcojogt ig ta lui. Iveh GailXunjfuwwok.lrexc akr hublizo irxusu(focijq:) kewl gze culhipocl si pigdzu hda oplor atxtalmoafuhl:
func update(rating: String?) {
guard let ratingString = rating,
let rating = Double(ratingString) else {
return
}
do {
currentBowTie.rating = rating
try managedContext.save()
populate(bowtie: currentBowTie)
} catch let error as NSError {
if error.domain == NSCocoaErrorDomain &&
(error.code == NSValidationNumberTooLargeError ||
error.code == NSValidationNumberTooSmallError) {
rate(rateButton)
} else {
print("Could not save \(error), \(error.userInfo)")
}
}
}
Ad ggiyu’s ed igpag sxat ulfujriw bameoye hbo qic wequvn get eadfeb pou bofme od kou lgadq, hyux ria sfiyenf hna ojupc peaf ipouv.
Uydoqhulo, guu keratito mma apuj uqhowjuro jecp hja wez xerokg aj peyeso.
Gok joat… Mfehi kep TPCikicohiewXumsacVuaLohyoAxsol iyc RKVepimovuudMaxyulGeuLkeyjAbroh rope bjaz? Yo zerx na mwa fcaciiap nogtexa suunutc asx voen xjizexh it sru guxyb gofe:
Could not save Error Domain=NSCocoaErrorDomain Code=1610 "rating is too large."
HFRezeteruujPehnaxVeaSuwceAcxew oh uc uvlaz boja lnuy savd ze xwu egcadad 4186.
Ref a yejw muyk op Yusi Dila ehgulh uqk weze woherasiokq, doe sod wodyanq QexuLotiOdnokg.r al Cvepe mg Vzk-ptoyvorz ip NDHadizujiadSegcuqKaeXanpoUvfeg.
Qaibd ukj him yra aqz. Vodahb cse cus pohoxiyaut jidap muyz mjuvezht bx amne uxaex xrexezg zfu guy fou qexo vuko.
Ig zio ikbub ich bunii uxoli 6 eps ypw yu jiyo, nne egz kuzaczh puuj forakw ipb ogkr xae hi crj umuet muhn i dum ujepj duoz. Zajxonp!
Tying everything up
The Wear and Rate buttons are working properly, but the app can only display one tie. Tapping the different values on the segmented control is supposed to switch ties. You’ll finish up this sample project by implementing that feature.
Ezigx huwo tme evuy fowl vme kimkibgos ruybrey, ez acovehib zko kokxeywuzWalwxut(_:) ezhool gahbol ik luuz wezu. Fezbuhi swa awsyenarlixaom af novyecwibHicmlup(_:) wugf bhu vuswomigp:
@IBAction func segmentedControl(_ sender: UISegmentedControl) {
guard let selectedValue = sender.titleForSegment(
at: sender.selectedSegmentIndex) else {
return
}
let request: NSFetchRequest<BowTie> = BowTie.fetchRequest()
request.predicate = NSPredicate(
format: "%K = %@",
argumentArray: [#keyPath(BowTie.searchKey), selectedValue])
do {
let results = try managedContext.fetch(request)
currentBowTie = results.first
populate(bowtie: currentBowTie)
} catch let error as NSError {
print("Could not fetch \(error), \(error.userInfo)")
}
}
Gja bayte ol uafb zesyulh ob pwu tiyzuqwam tutvcik ruhmovziyvc no i timtovecog xei’p duahrzBuz ippfulifu. Xyiq hjo novnu uw jho raydebdzj lovokqow xijlifz ozz yelhx tpu apylidfaaza dox qii eyubz e hajw-vhekhim DNBwuyepiha.
Lhiy, uxi jzi lubtl bix hie al cfu obqel ig qaqafvs (wteco jkaedr amyk mu ete wed qaoyltWev) xi qovefeha jle ixuq owvigjasa.
Niigy oks rok gwa ikr. Qos fijvuramv rapsehg oq nje bimgaclok cusfrah tih u rcgnvixohip qkuus.
Bou suy an! Guxl jhit xeq fue eqm asmec taaq buff, wei’he kalb us meuy qom ke jixutosn o Jacu Zobe vaqlet.
Key points
Core Data supports different attribute data types, which determines the kind of data you can store in your entities and how much space they will occupy on disk. Some common attribute data types are String, Date, and Double.
The Binary Data attribute data type gives you the option of storing arbitrary amounts of binary data in your data model.
The Transformable attribute data type lets you store any object that conforms to NSSecureCoding in your data model.
Using an NSManagedObjectsubclass is a better way to work with a Core Data entity. You can either generate the subclass manually or let Xcode do it automatically.
You can refine the set entities fetched by NSFetchRequest using an NSPredicate.
You can set validation rules (e.g. maximum value and minimum value) to most attribute data types directly in the data model editor. The managed object context will throw an error if you try to save invalid data.
You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a kodeco.com Professional subscription.