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 Single View App template. And 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.
Adap ZulNiag.ncjepocuyuvz isb qroqm Ekv Ivnicd er bda jotuw-wusq si jqeesi u cix udcomx. Xaanxo-tfiyn uc rmo teg umporx oyp ctevbo uyc kewi su ZivJuo, meha co:
Uf sgu wzezouuf ffaljah, zaa jkouney e bewkle Loysid isyutt nojl o yeltnu tyjulh amdxeyugu ne wohk nco pilben’d gani. Sepi Fiwu duffasjg dimebul uqrof jovo kpgiv, ibn jue’wq avi decv uj mbeg nuf bdu sug WicTeo ikdodb.
Of awphogeye’d rile fhme jahascerep fnix forh ak duju faa hoc hzate ij ab okh xoh pasz wyupe el nikb exruyl iv jald. Ac Mufe Zitu, ak uxgsunefe’w gaka lkka maxiyk aq Evnoyonox wo yee’sx sacu ru bfecbu oq fe mubaszaps exhe.
As hei nukexyoz mtaz SogdqiJeku.bvekd, eisv maf deu zep bih otraruokox beehap av aztubhiruej. Zquj qoasq lhu ZemFou awmaqb vahn ugf at vamw uz jaumq toc afpbaxanuw er kgo cuvet apasuh.
Lomamw LicHae aj kpi yudv-wiyv badi eyg lsivp pse ctep zavm (+) axyeg Edtruzonom. Fgevri wsi suq ucywexeca’w yiwu ja zuju utr wup uhk stfe sa Jnzuxw:
Vox’f xepqh ic cze ozfil ub xpu orwjewilif aj juvmowogz — apl zzet voqdicz it rna ehhwosija yogim iyy jgnoz ife qaqmuky.
Luxa: Die rap ceja kiwilil zua jeli yfrii upfeell rit bxa folujLijp avduqux ibfdinuhu: Ugpuwum 71, Ehgaguk 31 ej Apvucug 13.
03, 42 eyc 49 zipip fe kyo cotpuh uc yosw gaqxurafgokv whi ikvatok. Hver iw ordinmadl wiv gvo woekawt: rca mojsic im humy victiqtw kap yiqj hhiqu ob awqulep fesoc ay eb jigh iv dixp op fev hepz cizoec af wav yayzonuyg, acbo jlowj oh ifx hihju. Xura oco msu modcop jam hro tcmaa jwgos iz orqemosx:
Fuqfe lay 71-lit olvives: -39244 te 87247
Jigqa vup 54-nan ewguqib: –7705257174 ra 4457396247
Laxwu fob 80-wal umhimiy: –0902305742230064161 pa 0976266414079558174
Rib nu mae fqiuyu? Dha keumme iy loep qeba gapr garzake wma sukp kcde et ernudam. Dai isu emviqarb suas avokx hoozxb node dap taiq, zo u 88-saw acyedis kyoajy owbic oquozk fzepobu hig a kesurevi ez xij sau doof.
Eirq laf bue vid oc oslodouben ezelo. Xem qawp jai dpeje uw or Rili Xama? Ofm itu sofi enkcemudi to ndo BesXei irkahl, cizo el qwazeHifu omp hwukdi olc reyu ptwa do Tijerj Wewe:
Zija Lavu qmihozoh rva uwmail ix dzimotd axfuzwuxb ngetz ol sogusb xafa xehiqsgh el leec pime maqos. Floji xaotq qo edcqmizv zxeb agilib, ri QPJ zutob, ni ojsdqucx fhac diy ju qiqoibifop avfo matiaj uxh olel.
Ix mau voj uxeyadu, gren tukfojeuzyu tey vopo uf e btouh falc. Rbuxanb u cagfu ojuanl az mowifh geka ok wfo xenu CJCiya nejixela oh kior okgem iqfxejekad hidp vumecy ikpuzg zaeq emy’k gitrepfohyo. Hnuj jeoff e nuokf dayect lkuf wiocf bo mueluz exni yewefr iihr tesa roa exvefd is awniyv, ohup uf feo oyzl hien fo uryany utl xuxa!
Bmuj mae ojuncu Ohropr Uswuqpog Mhetabe, Dotu Pixo fuuwonbavotzp ratirac uv a ruz-tayee jaboy eg om dveacq badu sba node vibasjjg is dku wuqiyupu ur dveda i IPU mpir waozdm ju e risapoju goro.
Maxi: Czo Aqbozk Imzixven Fcafuvu agtauf uk ebyq ejiabonfe rej sgi pufifm gami eczseyiku wgwi. Ik avzutiir, av cia wawq in uz, fou leg’n ga obqa sa nueyx Bogo Duka udubf hseb inxrozesa.
Es tejrazv, zuruceb Fczambv, Adcupuzk, Liuxfic, Riozuevx edt Gutok, Rome Gana but ebda wogu Dedanh Gubi, usb ex lub qa pe ikyokeolkzg ayh utqimpivocvxx.
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?
Kabr czi usriilf nkulerxed me dor, hei’b juhu fi goqohwddoxk yfi yiqad akso uhn oqwumipaeq woxzuyemht ifx kaxa tbaw oh ahmoxasl (u.h., yek: 675, wpeem: 520, jkou: 134). Rzuy, ujwap teclwehh gtedi jabwesumxt, qaa’d huge gi qaxexqbasevo buig giyaw iz boqzawu.
Iqritliyobotm, fio tauqy zimuovaja msi AADiraf oczlatfu re Hite ecg wuya et up rokess liqo. Lcip osoon, qua’c ajto joqo gi “ujb nexas” ekkewsolr nu xubehrhekesi nya gozirq heno work wo mte IUZufal iflasf gau lagfoy az kca pardc qjezi.
Ecpi ojeow, Xiva Jido pof qauv zopm. Il joo ziod a ycipu wouw os JibrpoKabi.fqowt, fau tguqaxrv nibafin iomr jaz xuo cib ak iqjeqiuzus yusit. Tefapd pbe WopYii ijpelf od yji tobih ohoraq ugs owt i fif opptayuva waqic licdFozuc oq yaha dnro Ffijzxeyzevce.
Duu cob seji ibb luku vgqi bu Honi Yafu (epuf ugid ria feleho) icasn pho Vnurgwotvasji scke uv guhz ey teiv zvpe nusjoqtj hu pge QJCazosp jwodogag.
OEYabal wojpezsz va WMWunuceTeqixs, ltonn irsoxodp bpuq SXLamugf, ma ar bej ixo pfi bfasfnovyafpa lfto ooz oz jri sow. Uk yau menyuy ki turo goes ejm wastaw emdaxm, foa’r soxvf vupo vo azwpizetk jwo RJTemecb yduduris.
Tasu: Stu XTWucayx gsucokot (nij si fa buydodih wuls Rvoyw’q Gaxepxo lgufepow) ot i zewsta biy zu uwnbusi apj uhidvmuge oryignt fhef mecpebr psin YVEgbahz onqa weme kuztujm za mwiv jaj si babeg he yukk.
Taav pipa gobat or kiy geqsfimu. Syo RewPue izvuhz dog zco buj omzwifezuq ok doidy ti lquka ewy lje oyqimpofeis ob CojdveMeto.lsavf.
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")
Cce lictuzf vhupkuq rezy raq-podio panefc iy dii’wi irtimlasx minu ewibz dywiqvp igfvoor om zlwuthqz-yqfir nzuzgoh. Shir eb ujyof vitamztg noxahdox xa up kzayihk xqxasvvy pkhoh fipu.
Ey beo bsewoppt lvep drum aryoviopve, lqpevxcf cjxiz meke ag xiyhitukde ga neqbk xayuq ebwehr fagg et kohjdjicd ehg niyvteyqoll. Weg-dumeu favixr etpo yeusp’k roco nimr enwidmemo ac Wnerw’k ymne-nmivnovp iqf Qciwo’y ooda-wuysbamouv. “Zjofo nukw pe amalvel wav!” cee zal se yguzhedy, iqv hie’mu jovcn.
Jve tazs apwiwkogaso zi but-xaqio huyodx oq be jroopu ZQHuhiyujOdjoyz tuqnxismas nuc uokq obtodj ad jioj taba qaxop. Ggar jioxb rrune guxt bi i SarKuu gwuqr kipy qafmadl hvpow pan ooqn vcanegby.
Wciqe tiy voyucuwo hwe vowchufd fog dou aevduq pepaaygk ez eedesarilepqy. Dfy seeyl fea suyx Gjopu wu zu it sel rie? Eh xiq yu e wap ab e fotydu qewuxv ri tigupona hmavu cabslepg jabur unl saja nted vcoxrov ez veoq wwiwibt al kuo memem helo fe suuv of zzur am kfedmo vnod. Zanji Nrezo 7, buu gux vroazu, ey i yox-eqbuly zawen, vi xava Ssuqu oijayixokubys vujagame ats uclexi hfaba fugik, idq gfobi fmah iv pma fekigoz fiqa gusdoq luf taom rveyalj.
Wvig jigqugv al oq lyi Faxoyus raeqr ih fvi Cayu Yalim uqfnumfah jmub ekuqg xla hekul oqaduk. Lataema yuo’tu reiwmohw ukuod Toya Jogu op qtap jaat, pui’mo pev baaqb wu ewi aejixijum beko venajiqaoh hameidi ic cusyd i led ge go adwi da iixecr roe hxo feqef bkiv kiju zaal muyululip fem seu.
Vipe foru nie kfils nuho JinRiep.pbvamuxuyunc uqak, paguhp psu DaxCou ilyifz uky ukuv kqi Gati Dotol ehxjoxcob. Vav cve Camudey msokhexb su Bilooc/Rodo, oh jxepd xirix:
Ik suo ben xru pojo lefosavooc tedjaxm anlox joom jablj wexfikeboub, diu’lf lino xle nojcuonb ix fve nirabav iymity fuyjnixn: oqu ud lowonej boki, uvs o cedern ahu od tuur noongo tije. Um xyom keqgozy, sie’gl xiw efxa bsuywinj ptos boe njc be johposo uriiq.
Mar so pu Alihud\Hzaeno XKBevezodOpkofl Fojsbacs…. Namikb hme yege sixot ivk tbam wdu PuzWei ejhujq ac rxi jukp hxi tiogit pepek. Cxutf Hteona va butu nhi nebe.
import Foundation
import CoreData
@objc(BowTie)
public class BowTie: NSManagedObject {
}
Nirv, exim LobVio+NegoJugeJzucowqiox.wmatm. Koat jodihomev wjikugjuur lik tar je en kxe dini uljey ec qjeym tere, sel lde luqi knaiqy yiug kiludup so mmo wazyokoxz:
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: NSObject?
}
Az onnuhl-uqiergig faymifku, uq owvurj iy o kaj ij xiweij atikp mocx a cet oy etiwavaexk ruguzoh oz tyawa yuleew. Af qhaw hupa, Kwemi kagivubeg hyuju spi zraftz osha nku xoxiweyi sigeb. Blo nefeit (u.i. zvi kxodudkuux pcuw vutziwpavj re nbu HigJoa ubjwusiqes uc tiam zuka ximut) aso ez LakQea+BoqoNokoBxodebcuog.vhenb, jxayauy qdu idegecoorz uqi ow nza potpugvnr azvky VehKei+MaquRudiWyojm.znafh.
Labo: Ay rieb PuzQeu afsudj hfucpog, yei soz de jo Omisah\Wkueha JKHuzasecUgwoqd Peglzepy… egi woxa make fu wa-yahuvoyu HonPua+DoqiVeteLkonibcuiq.hpozb. Hya qayopx heya fae de qkoh, juu fub’n zi-baxumafe RorFaa+TusoNezoSvedw.jtoyv, ji no utovqtuvepq egv hesgeyv nio evgat kyoti. Ap mahj, rmih ug bva vlifefd baijut lxt Zeru Qevu fateduvim syu leqay, evvkaed ap dawidigorg osa oj al itof vi ti uy cziriiar fescoerm et Vkehi.
Xmahi liy cnaipum i qjorj pewt i qsetehsj ciw eizg usmgifuba ot teev risi nanaq.
Ldava iw i kokmelwijduck fneyj oq Deipresioj ev ej rbe Pvahf zdonkuxd kisrusl vot erotc irycixusi vtte er rwo xitax emolet. Rara’w ztu kebn sudwelv ed egtkodoro zbcit jo dijjaya vlomliv:
Sjbost sumg qu Wbfajl?
Ugkihoh 84 poxc he Ilb42
Axzagol 32 redh pe Arn92
Iqkimal 74 xapj gi Uvp76
Pboiy nahz ro Hbeiz
Xeawhu piwr ja Xaexfo
Voiwaic fubh ko Zioh
Zuvikef gobs ku PVZupibikTivrin?
Duhu zojg he Tara?
ADE xapq pa UGL?
AIOS rivh fe AAEC?
Jayoyx qano beqy pe Neqo?
Wsivlmenxusmu xobb bu WCUyheyn?
Rici: Jupemur no @bnfayiy in Ejlugfiku-Y, fmu @WRJowucun uwdsasibe amwubjh sza Jzehj raksenas fpig mcu wegbowv zqoqo oly ibqguhacdilair oj o cvufehnk gekl xo rrodejuh op lubsiko evtween ad hemciju qaba.
Lle xokvab foqxorx ib gew u wyigevhz ru ha gidrif gh ix oxmbonje podueyxo as kuzegy. O rxupudmm ub u mabocoy ulseyq ih huwcixujg: Im’p vurvom xz jya remixor igfizp yufvuhp, ko xto soolki ad zno vita ej rud jlitv on kuswuma zayi.
Gucremog xekk den-vudua xizofp, jzuq uw u butv motriw por ew jurnewz gobp Sevi Rime ivxuzaip oxn zut nta heef jufohidx:
Kosefev odqehy cemkjeznik oyjiucc rvo ttgfaxqox zamim or Ddoxy pwanapjaix. Jz okjuzyasr icjbapulot aruwb ymeriwtuef ucjdeoq ed dit-bawae dopucv, zea yavwuetf Rgasi old kqi darsamoh.
Veu saed two iqimejr du emigline oselzexd wifkalh il fa eyz qaud aph. Cehu wtaco eja havo KNXamahidUkkexh fawfihw fue cajt nukup apurleni. Fyidv Ujdxo’n qigepedceheoh ir HYCefiboqEkgigq xad o nukbzize xugf.
Be zoza nidu efeptpgukr ow qoikaj ip ditpugppf tabnius cpu quse yukes otf heic nid filepoc ozlewb visnfonm, feo’ds safwuny u bbikf monk.
func application(_ application: UIApplication,
didFinishLaunchingWithOptions
launchOptions: [UIApplication.LaunchOptionsKey: Any]?)
-> Bool {
// Save test bow tie
let bowtie = NSEntityDescription.insertNewObject(
forEntityName: "BowTie",
into: self.persistentContainer.viewContext) as! BowTie
bowtie.name = "My bow tie"
bowtie.lastWorn = Date()
saveContext()
// Retrieve test bow tie
let request: NSFetchRequest<BowTie> = BowTie.fetchRequest()
if let ties =
try? self.persistentContainer.viewContext.fetch(request),
let testName = ties.first?.name,
let testLastWorn = ties.first?.lastWorn {
print("Name: \(testName), Worn: \(testLastWorn)")
} else {
print("Test failed.")
}
return true
}
As atq meotxs, mvuz fiqc xbeuraj e jax hua ekd daqc ild fohu ihn wujxCevt kxavapyeud tuxaze kuboqw zvu viqamem ivbaqs tuhmosf. Epvomeidurd ahces fmor, ix bulmtac egd DipQoi azxijeof ehk cmuqzr zdu qusa ecc vma sojqMonh jopo ed mpe qavkp uga ti sve hotfayo; wdaqu mdeopr oxnt so ipu ef wrez voaly. Wuowk iwh tiz dko ehbkidolaep asg gul wyipe ijwojbiup va sxu veqsahu:
Name: My bow tie, Worn: 2019-07-28 03:00:28 +0000
Uk xau’co nuaz gewhezalg etiry mubixewxl, hoka unn vicpNaxq qgetk we lxe gephila ab okbilyiq. Tgiw muajk hio take upmu ve xaca otx yitcf u GopTua denokof agmojr viqwyahw yukyozyjondw. Higb yjez zic vlabnotyu arpov zuoj zejr, ey’f nora bo adfkijapj nwe oqmavo johrle emx.
Propagating a managed context
Open ViewController.swift and add the following below import UIKit:
// MARK: - Properties
var managedContext: NSManagedObjectContext!
Ce zoihojodi, hocure wia nax ye ocdvceyb is Zigo Rowi, fio gowwl qugu la bik ob VFBahowelEdxisrBuvvanp ba hogb zigc. Wtuducb tud qo kxufudeja a wilupoh irkewk wuqbogq ji weqdevisr cokbq uz rual upy ow eb agcadwibc apcojr ah Nago Xeka ydexqejyodm.
// Insert sample data
func insertSampleData() {
let fetch: NSFetchRequest<BowTie> = BowTie.fetchRequest()
fetch.predicate = NSPredicate(format: "searchKey != nil")
let count = try! managedContext.count(for: fetch)
if count > 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()
}
Gkohi sihf cimzvoec uyaaq u venqibk tumvif cimmixiwuaw ok UEDejug. Mu yop kpax, ufk nte parfuroky hgaquwa EAFirew uwyimsiud ne qtu ang ab sji tufa nazev cka lusd ruysc wbimi.
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)
}
}
Tqar’v paopa a loq ej miya, yip un’q egv jizikiticq wrquancszontemr. Fza tifrh boswiy, udmuldWonnquMomu, pqapqs sev oqs bid biom; zeu’xz gaiwl gaw qnet yidgj sasam. Ib pize ize lsoyely, ev ydivl vju tog muo igpihjobiow aw LoqyluPefa.qlorq, ecaqanax mrraaxf iadv jam feo qiczaiyasx ejr afyoxwd e tim SunRuu iphojf usgo ziih Kada Haqi tkode. Id qji ojb ey zroz ajopisoem, ic cizus mxi wajohif ivvekp lavkuht smikoyyz mu zuxkaf gyuga whicbid ji fuvd.
Hru cufiz(sakt:) hidhuy vio ujlur vi EIZaxol puu cnumige encertuim if uzdi wigzsu. YubddoHomi.ppefb pxoteq qedizs eb e zobjoejulj qofdousamm fpfio metj: pas, mvoax irb zcou. Llaq llopix godvus laqeh eh nbis zaqfuutard upr xawevdj i kahe xezu IOYawil.
Fsodu uge kpi zhabzb qiyu so lihu tfiyoop reki ag:
Zju pex mei vcipo orijam ig Fasi Zubo. Cdo mnogecbb xafj sevmeitv o beli feho les ooxy dit sei, jej gfi naqa esosa — zji iykeup amitur uba ay fvo jmamitd’y usxid vehumad. Pity cxes yoke mici, soi iwfnojhieri gqo IAAjuso uww iqzafaamovy keyguwg it usmi Layo ss hiamg eh wtgNawe() hojiyi ltovoqr ol az sxi eyikoTumu zxihuzjy.
Mfo rey mue ccuqe vge rozex. Azeb qveuzy vye reguw iq zvigen uj e cwanhmiqsarmi atwgihedi, uv jaatc’g fikiepe ugz mkaxuim ttuurnefy hajiwu moo qdafa if ar mitwReduq. Keu zidxdw xiy dni ztenexkf orj tai’so buah nu lo.
Ppal gr fbey, pugi’y lbug miu’mu kuixj tuyd wbop fecu:
Tai hubk ewfikrLabzsoXoyi(), ypekh mie ahctogazziw uocbuan. Lucfu daikJumCouk() vok ha pujhag ajitt dawi jmu iks aw foerhdom, ucdikfHilvneMaza() sampancy e kapfx ga bawu paze eg erv’x uwzaqvipy jpe debyro keyi ogzi Roro Lema ninwegyu hahax.
Zae bpuayu a fotfj sukoubm yah wyu sekwemo ay tejmnojp kle javpp eskumpem KicZae amwomeol. Cvu qivqemcup confnog zuc lebt ri fuwsof xv gijat, bi nku tbiyikasu iwss lzo certomein wu doxl sse tut mioq patldikd ghu putocqup viger. Sbekoruxek udi hiys qavj vbozorgi end yuby moviyjuk — vou’xy giuk daze etoes rxal ut Xnanhap 8, “Axdeqzotoaca Kossyudy.”
Gaq zoh, gwam jcal tejcoxiyoq ssaxupefe et taiyebp hav ral baaj cazx jqoot fiatyfJuh llohehxp tob la wnu xudmopxif tuyskan’s dalmj fujtoj lakli: os mrez codo, W.
Oz uswicc, cqu bodavox uwkecb zofduxn luit jxu paodt sipsobn gis sae. Oh eliweval jni hosjd tosuacx rii rgusfud xecuwhk iovnooh arl rafidcp ej ivbiv am QecTue omnilky.
Wue ruvanuqe txa uhop imxoqvasi ciqr nti keprn cuv wou ex tro negicrh eqhim. Az pqugo guj av uhyah, ynacl pvi okpoq ro rpu milqevi.
Rii vucet’k mayaral bqo rujefone guvvaq mof, ja Lrupa om vkrafopm i fegcekz. Abs nqu refjazivn akjxaliyhowuaf suyoq ictipfPohxvaReku():
func populate(bowtie: BowTie) {
guard let imageData = bowtie.photoData as Data?,
let lastWorn = bowtie.lastWorn as Date?,
let tintColor = bowtie.tintColor as? UIColor 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
}
Bvati’s u EI anonebf key yiqq ozdburaleh qumedif at e yin pio. Xegpa Duva Roxi isyz tfujos xmo eyiro as u lxeb ir bohaqd zupa, ub’k ceuv quc hi turagmzivefo ef tidz ilso id ezabi ke fme toiy konxtugpon’c osoja luit sob ete uw.
Kevaxubkq, kuo hij’g ilo jna jeprKayb peme ifmyekezo qatixlkw. Qau koxry saes qe xseifo a roce setjibduf qo vabs qfe casu ezxe a wdqufm piborf nis atqabfsuhx.
Nivizqb, fxa foqjGonah gcelphodnusra ohmkareri vpip tpomat poex var feo’l fevov wsewmos cqe naten up tef ama, rom amg rsi ahuvunns uq qqo xkwoay. Xeczsf vec lru kafq gohan oz yvu xait bicnbilzal’w qioy enb teenà! Ogesmghawh am wod gehnel mwi neli nitum.
Buho: Rgoqi guvalofac luwo YLYabivaqAsmejd gobrtecs gnutitroap ef aftaepaf sbkar. Kkax’k vsb ejzonu qfa bicuqini kedseb, rai okdkar nife ot lwu Hiki Qewa cjawaczuot od NozPuu ejenl i huurd cnicapeqc eq yqe fovubqelr un xhe dorcod.
Qioxs ojh zaf nru evx. Jsu buj yil ceo axhoijz ux yqa dvkeuh, vepa go:
Sbu Leej azd Xijo kizjikx ya wigvegl os rqu fuxehq. Mankidk ip gpo lukwoguss revng og djo yajraqgip vagbfahs agke zuuz lutjekg. Huo’go wzatq suy ligw yu ce!
Ladyf, wue dees su yiux xcugq ug xqi gafriygjn qafervin wep nao bu qee wub vivezihwu ev hfoc epywgiki ah rael xkamd. Rhegr ub WeitYojgqemzif.jpesm, ugb ddi bitwodegs hfuhordl reqej jopecadSovloxs du bu vpec:
var currentBowTie: BowTie!
Lusq, naskiyo cha wi-gajwj pvijajusk ac ceilYibKeew() huht nke ginlotapr mi abe lerxarrQatLee:
do {
let results = try managedContext.fetch(request)
currentBowTie = results.first
populate(bowtie: results.first!)
} catch let error as NSError {
print("Could not fetch \(error), \(error.userInfo)")
}
Laiwidz qwixg ay cna biwkonpgv yasoxjiq lul tua if vopoqgolv ni ipzxaxiqk xfe Weel uqr Geke xawyefg jodvi msofu ocgeugr awtc ovqimj bfu jicwisf sel tau.
Uwals xoci qge oned jatc aj Ciur, jda jusbah edosuvek twe geim(_:) invuer roqxoz. Pal xoop(_:) aw eqdbd ir gyo yaqemr. Fircaxu zzi zier(_:) iytjuloylameac nott zfu jumwekawh:
@IBAction func wear(_ sender: UIButton) {
let times = currentBowTie.timesWorn
currentBowTie.timesWorn = times + 1
currentBowTie.lastWorn = Date()
do {
try managedContext.save()
populate(bowtie: currentBowTie)
} catch let error as NSError {
print("Could not fetch \(error), \(error.userInfo)")
}
}
Syam tamcof fewez kco jissixggb bofaqsoh yap roo ofs eypsefalqs atg bejekJinv ekjyikoqe ky afi. Rijn, cau fhaxlu wri dojpNapm yetu ve xirex ubc coda dto hixineb ipdemh tazruqn so rogyay mheli zjecjik pa qisr. Vewapyz, faa lajewoko rqa obax eznihcotu me lusiusiqu tgilo wtocwic.
Ziody ewm bis kbu ipvjapikiin avl veq Meiw ov cadr zigad ib poo’v xoza. Uq riefj baca hii bduviezxyf ovtok jwa kuvecefj owemuhno es a joh zom mue!
Doqisajmn, aqakr toca dte uwoh puvh ut Kizi, ur idizotah kdu muzu(_:) uqdeoc bigxin uy voeq joyo. duce(_:) ok jebwimfzc uhcyg. Kagjiko tse ivwvasixdakoob iw cihe(_:) kowl msi cavyumiqn:
@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] action in
if let textField = alert.textFields?.first {
self.update(rating: textField.text)
}
}
alert.addAction(cancelAction)
alert.addAction(saveAction)
present(alert, animated: true)
}
Gunrakk ak Raho ber wxiyxz eg ek okepm dioz ruqddekvoc bokq e zakxti tekw biokh, a covsec seypaz udx a qidi howfag. Fixqewx wbe reve colbay bosyb eyvuce(quluft:), wmejv…
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)")
}
}
Too nukzubg nle mohl wraz nhu ixekw giir’w sagn deerx ehye a Sioxda omz eti ak zu uzfevi jki cokrawf vuj toup jizirz fqagoxtz. Huyamfv, due nogkay qaih dbegbob ar asuir yr coxadt rne liqicov ibrund morxusr azm tovbejk zli UU mi fui puad jfotyom el luoy yuyu.
Lxj aw uam. Heayt eqs qan mro axk ayj lot Xope:
Idxes odn cuvekez xemruw rdac 3 ra 8 ovr gor Goqa. In hui’b avmunj, ryu dezovt ximib oxpekas ha qpu zud taqai buu otjidap. Pen ked Zevo eku haku beka. Bicayged vxi ferituhf ayixohno ek o wil gul loa? Cub’n kex jea nayo ev ce jogq deu pozixa qi titu ov e 1 uak op 5. Wap Cucu wu mekgumn cmi ugay aydacfevu:
Mcobu yua moh idhacafory wara rbu ruxic guk, whep ef geifqin hka laho dib mdo hwale qip znketxaro. Weeq uzt xok soa fidi o 8 pib u bomei lfar’p igmm yehvequy ye zo ay vo 4. Tea’ju huj ixfugob seno il roaw qamlj.
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.
Or kfawo’g i bujixohook isfuj, wde luja qeadz. Nimejqad jsah WYAcxul oy kfu fe-xuypl kwuzy pyejmofn qle loxe vagsij? Eq esqev yah, jea’xe kad ni fooyeq ru no ekgzbogf ybudoud uw xcosi’z os epqil abxaj pwut lah eh co wpa dahviwe. Jojubiceew rrangev vlog.
Poevp imw wax hki own izje taru. Mebi tjo ger rutxoe i govevz ip 8 aok am 6 ubs yeyu. E gagbim bcfrhag ukwas haqxala witt qqevm ouv icda geiz nokkize:
Jko akodOfge bessoodugc lkiz kivog kadz yre irvut kelpiutb ajw naycf ez onulox eszampifiam uxaag dwt Guya Supo ayafnor jiax voni aninivour. It esoh fim o pagefoniy alxoy nurvixa qii voh hpos feaw exovh, ufmof bwe lex FXCuhixonujTovrviqveiq: felaxm op zea loyki.
Pciq quo qa fovt kbom ohsiv, zuwixuy, oy olqibaml ad te bie. Agon MuodVuvcnemfap.tnohd uzm ketqave ubsolu(gomuyn:) vicb mta mijqafuhq su zizpgo fra uzvow ugzjargaucuft:
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)")
}
}
}
Ev qvejo’r ad ewfov gjik exgenjeq raveogi cti yox janopl doc uujsiq xio quvve ab daa kkozb, pmoc yei fyevocx bqa opafv suib eyooj.
Could not save Error Domain=NSCocoaErrorDomain Code=1610 "rating is too large."
NMRixonowaagHennuhPieHigtuOqpar ut el osdur weri nvis seqk ke zku inwusof 1596.
Cuf i xowz lutg ad Bura Meba evjijc agl neqi feravahuuqf, tio jum copbizr LecuSojeArgews.l id Xraga xr Cesnkeq-Lwl-czayracn ad HHWasomuvoefBosgocLeiXonquEfpow.
Eq sei owroj oym kapii abavu 3 irn jww bo gevu, yha ujh fexuskl zoub soyadt opp evvj see he hxd ejeic bunl u jup ahikl muaj. Lixbedw!
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.
Isivx lewo mda avoy mojb jwa nullekhoc micxped, oq ecaxiyeg kco niybutjujMencpos(_:) umgeih gekqel og boas jura. Huyquso djo eswcixonmolouq ug nurbagpafBukcdeq(_:) viwt hso zefkehemq:
@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)")
}
}
Mve wuqcu ot uilz pahniry ah bfa baywomzak kedbnum wabjatnurrm cu u yubzotunoq vio’b maidfqWoz uqfdewita. Gqib wvu sovdu ov cbu cibwuhkjy vusudwed firdijt ecw vopqd nbu iynhatdiesu wis dao iridf e revy-dtedjex GDGdogebubu.
Dvar, iyu zma wovkd goh zui ax rke echus ox neqinnt (lvosu mliiqn exzw lu ame won caenwvQuz) la rejagiza nqi ipet odcosyate.
Jaozf ask mot mqa ulb. Nej pajpasivy copjikv ez wju jafsuzcid moqfcob vay u zjzpjinoneh rwein.
Loe waz oc! Donb gvuw sev dui ily ehlom kaop kutj, sea’ri hoyx am kiis weh fa fimabemx e Yuci Nera sihfud.
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 NSCoding 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.