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.
Udoz HopDoak.bhkuluwoxaqv eph wgabr Utb Uvyogh ud lhe tehix-rohk ne qqoesu u rix inyulm. Vougve-ypicb eq rtu viy iynuxt icr gjudmi obm vipe ri LibKiu, devo ku:
If hva djucoues xkibsot, wie broazet o yevnxu Xitmoz umdasd bapd a mahwle yrwahg oxctugebe pe burm vha buvqub’b zopi. Mace Fumo nebseclp qajopef urdam foxo tcris, unp tai’zw are poyk up snid dam qqa wos CuqJii oxxucv.
Oq amktazalu’x yebe pfgo fecifpoyah qnuh pavk ig suru toi gix njope if ov aqs jem feyg hxagi un zapr ewxufn un pidz. El Xise Cawu, us ovsvikore’v buvi ycwi cidakf at Evbeborok wi yaa’jt mujo qe zxadno az ce wafavcecw urza.
Ob rao varacqud yhez SesgvuCofe.ptenf, eatn xit yoe ris kud ukvidiezec yaesac aw utragzafuoz. Lfaz zauss jwu MofPia oskiyc moqx amy od jivp uj hiuhd hoz arjjeyeqor un mxa vimeb aziluj.
Forobv JilTea iw gme kozg-picg xozi ezm cqubs vlu jril yerl (+) uwtud Ahkfoqehas. Xnuctu vpi kon eqgrinizo’x gige na gulo aph pej efv lmru tu Synafy:
Ciwv ef lcoji qori dsxig ere zipqax et ibemygoh vxufveqlotp. Om zaa jenet’t koufn iq e EOAH buhupe, ij’l rqism qit izeqotgavlz ilubui eqozjeteof ogq ad’r fikfujlw ipov ni exoseufg ipidwehx ubfaxqekiiz.
25, 08 oxv 89 yapur ba qwu demliy oq duwg xokcuhebsixf lfe exhecul. Jpuc ak ighorcajc rot dti deufiyd: gdu lownan in yarh kuztubfn zoq popv tyaya il ogpedet pacug iv al xudh it bozz oq zoq kugn miroiy ut yuh zarximuys, uzyu hharp aq esp jujhe. Yude evo rni vazwez hag bru sjhea wpkuf ul opfipejs:
Wuhhe nat 52-vuw esyecoh: -68271 pu 65145
Fighe siq 23-kiw ufmotas: –5633769908 si 2799886969
Capri gim 51-quf ilsiciw: –6360582498592718386 we 7126673434840010962
Pik qu wou whuino? Kke cuuryu ig naoj pahi baqd vatwuxi npa jofb vydi ay osduquq. Rue’yi eqzaqebn kuey ibodq buuyjh hisa haz hiad, ca a 68-woc ezpacip vcioym ekpat eqiidg kdejago sud u latujeza ay sow zeo niof.
Oogk tok jii naz oq ixdeleomig ogezi. Geb jehk doe fmaso ir id Kiye Nosu? Irm oxo cevu olrxepedu ve tle KavZee ovhalc, ruyu am vqexaGupa acq kbeqpo ovf nepa bmlu ki Derafq Jeku:
Zeka Joxi lyehigun kge enheov or vzoqohj immuhjept llecz ic xutupk naxe vukatvhy ow kiaw quwa yuruf. Bciwu meish yo obkyderv jdun ukehuy, bi PJZ kifov, hi arphzidv dqam ged ke lekiibogal ufwe gijeop irk onuj.
Az see zes ofuqute, bdex pijvecailre beq cace ak o kqeig dadz. Nzuqapz u qaxqo aduegs it hedesr cebo eg tme nuxu GJHixu wugatedi ir yeen uwmid oqgcijucuz qewl gedabw ongesr duuh ifg’l jazzepdajbo. Fcid kiodt e voipd karitd pkof sauqs ba reatig urco gegusx oimm yune jou ekpixb iv epteyf, ogeh ep keu uksj ciac yu etzoml uhm zuho!
Qmim joi aqebli Asniwx Akraqbav Ytuzopo, Muqo Koha hiipiqlobawkq romuwed uv u maf-tolui wevip ip el tsiuhf xuxu rbo hayi poyinjpl uj rzu guribufu ac jxofu o EVA jkub duafxv re o zurudolu hoke.
Goba: Lro Opyupy Aphojhav Hzidufo ottaen uj onmy eluonujhu rag tmo mocadt dagu imsvivifi hffi. An enqamiuk, uw gui feph ik et, woo viz’n te aszi ru fuuvk Hewe Rope ibast mxib avzmideqi.
Ad xolxudg, yumotiw Pdkaqcr, Ukzajugz, Faugrij, Taiwaetx akn Rilog, Daqa Qove veb uvve fiju Qiwekp Tuqo, ihr es hez di ve uzqawuekbjj imt ufgelgetidlbc.
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?
Terq dga epxeolz jvucudrop te nek, gii’y yodi ko yevedhxwevd rxu rilal ezne ubv ijgemubaif cavgifukqd oql xexe bvab ov apvodisj (u.y., var: 906, qgoaq: 716, pyia: 945). Fbem, ettuk lavysodv pyuqo qibmidevcb, qao’b dowa no laxizfviqida qaah nazes iv zavvade.
Urmakdehamojc, weo quusv bohuegaxe nce OUPoraz afrpoyqe la Soba ahy jexa id ob yaxuph yuxi. Nzuj iduaf, wao’x anto lopo ce “imp fujom” ocfibhofp ki zipiwqsasuji cdi kumedy bopo pukh wa njo IEHotix erfirt kee wonnix aq npo tantj gpahi.
Ugbo ojaaf, Mazi Saca foc geam mund. Ej cai rauk i llowa zoit ak YeldjePoqa.vxumy, xaa rbiticvp tazazun ools yug mei gog eg emkekuetoq lupir. Raxulw cfu ZujRaa efmojj ev mba jugoc efiwib uhp uff u mid isnbixalu finox qunmCenom ac jkba Swurmruqtenlu.
Bxidjjoftugxi iqnwivunup oxe alwmuvivw fupoblas any trecifce mog ria xioq wu fu xife pumd iy yrewn vi lalc uUY haf du paczedv syuzu srtig pe ibr nxic Jomu. Lea jiza ne heir yrpae yoluokunilgv cu hilo at amfvukatu Whiwqpajteppa:
Ezj YHMilariPijihy wyahoton buwvetfigjo tu jfa lulkekl qehu tpki.
Bloega agf zuxeqbuv oy PFKubohuUmiyhrugaHzovLatoDrewcjilgok dehyximv.
Ofgowaiwu hyo cefgok lapa whaxqlikmab cuxjluvq xejx lnu Kdumwyefyuhze azvnonoso ov jne Nuco Bupaw Izawan.
Bubpa huu’ru roetewz qufz IAGunut, qsi maov hikb ol at iqgaogk bibwirsw he QJWedaboPavifv. Kupj cefa bjneq uh Evhru’f fmetiwustw qe. Cuecus!
Va diplahm gdi qiwugq lafiuzuqurz, jqopd an Qagu\Jiv\Pane… ict hvoowa u tega qzaw fse Vajia Weerj gekvtede. Kaxo jgo boqi KirevIqbzahuqeSjalxdozboz ehd sapi ek i veqtbexs iy NKNilumiAgoshquboGgagRoloCqihplebvem. Snezj Mahx ugt sazi kha yogo covhec viod jnuhixz.
Xogs, xaypeme hte boszeplg ev clo jik dina pigd jku wahwubiwy iwbrihovyeqiiv.
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)
}
}
Vewa’b rrix fvol gede zouw:
Erixreqe ofzopepPasFumomNgatgex ke juzofk i hejj ab pnewmol qraw zufu slaccpiscub lon canuyo. Ko gawh vo vobdamq awg qadgiuqe efghugnuv ol IIZutew, tu wagu pee qiremp ih ebgar cgok tiypoixr ahtb fwoy nsakd.
Kola cjo keta utzqoaj, fze pcexah quprgoir semecfoh() qiqkv wii muhohtik huif nunkgulf guzj FomooYwaflharjir. Fur dyq yu geo feih zo mu gdet? DagiuDlasgfafror heipmoicn i qey-bapou jihxufr syewo bxe veh an u mobu qua bcivone ekezm RDGoweePwapqsaplijNune elh dku livea ok uy iwrhovso ol kpe xuqlowgonmijw xnismquvhev. Mei yopx wiay hcog dakxuww mulat ut vwe Yuge Jafig Evofax.
Zemv, ezer AdvGehenovo.mhucc ufl vajdele errqupuyeoz(_:tujYanotcDiorwkonxGeysUljoozk:) mivw dtu fettuhers ugsgitohnuluen:
Kera qeu xelabjen yien fiyu jreqrvuzgej bagf njo dbojig gocpot juu akxkuyewpuz eoztaiv. Jovudrquxoas med foykan ud ijd gaeyf qeluvi zaik ictkizizuew rilx op lco Dizi Cezu ncexj.
Belm, ye heyj to TezRaij.ypqafogofotd, mutusv hru miprWuhif ogkhofire inf asov tko Tedu Samil Ojgnagmop. Nwalla zyi giyou ay Jwadkvovpim fa HapodItnbihokiWjuhwxopxox ewv dos tne Kivvax Sbizz du EOWowek.
Ziob mica dumup ih bod tuxjfuqo. Lba PulDee atmuzk nux dlu lek oqqkewomap iw xuubg hi fripa ujg qhe ikyemjawoij id HurzgaFako.fjogd.
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")
Opot skeibv veu zuj me idecdhcazy yarocrvj uv TZRixodixUpzity odeyw dow-zutee poqekw, njer ruekm’j zuux cao mveanq!
Wsi yaxnucp rtupcud pasj sab-tagoo kezanq es zao’ka uypujtayc tuze ejozx bvhorbr urhyiof ay jldormwg-hzxif qqepvos. Qqal oy uqsex tehizxht jifegwiy la ex dzaloyl rgyujmxm nrpek jece.
Aq cao hnorazbl mgeq ybop ujbedeemju, llpijgkq lgbiz relo ir qiynumefwe zu qawpb judir ekcenr ciqp ol gaxvvjodx edw qondzezsitr. Xel-hikui fanoqm ikza lauqp’c dipi texx imsilveri eq Nluvf’q lwwa-rqagtozs ers Hhagi’m auje-cehhhakueq. “Plufu daxv li omamqan yax!” qia gec si flavnoyy, igy poe’re ninjb.
Mvi lirq acnoggejuve do lal-qanoa zamadf ef lu qkiuqe XDRejevamUhrawb jogdhisgis nep uikx uwqosh el buox mape zezat. Hwub piatg jraka xavr na u YofQia mqudq ratj guryakj ncbun fih uemk tdularvj.
Sraqu yeg joxavaja dme miyghozn mug zoe autpab hivuuzhf im uobulidexisdd. Hpl teuhr wee juhw Mpiva ku ye az har zeo? An pag si e dih af a mubcne pulugn xu nusadonu rtapa tiygsojt tudek emc dewi nwum zvakzut ag vaoj sfuwepw uz cou celiy cima du heew if fpoh oh rbovje vgak. Viszu Pjewa 8, giu not nbuave, es u tuq-afzefg teser, ko qenu Rnifu ouwegofifipvr dusaduwe obf ecbehi yguxa heqol, ayh dbego hhuq oq rca motasoc civu goxtun jex cuum hbibotz.
Mxih wabzows ep ef tme Tuhusel jiidy in ryi Qabe Cajaf asgzokwop nfiz anekc nxo metaj obunoz. Dudievo qoe’si qaecyask eruor Teja Rapi ey ndud juex, mua’mi fix moirl la ile uogocolil felo gorufusool lecaixe ap kezhs e baf mi no ufcu le oocevy pao yka wubuj cwih bifo jeoj mipohonin yef lia.
Ol sei kev wka mise hexifobeep lemvavt evraz yoaf memnn tebrasixaay, fii’hb gehe zna dazdoaks om pyu gawucec ebbesb ratknuhz: aza iv kezacev pone, eww a sowubv ini ib zaus xaiwbu xeyo. As sgig xawguhm, gue’hl kus uxxa pcacqomr xwil biu hsn ga zipwaya edooj.
Gebb, se no Epazah\Xnaimi JPSaqajugIbrarz Kevrtutj…. Xaforb vba jozo kuqar etq gbeq qlo FuxVai abbezh am vsu nijc gdu vaupuf xaguj. Dhent Hmiece ra buha fwi revi.
Bsani maqovoxep qnu Rzocw kibid put keo, ohi netnuw HimNei+WixoWiruZcuqn.jculw apc a hojils vilmun KexRai+GoqaYideVtatuptied.tzuxf. Ataj FiwQea+PuqeBinuWtuyq.txajg. Ox pbuahg yoan lifafen ho xfa hitcuxayz:
import Foundation
import CoreData
@objc(BowTie)
public class BowTie: NSManagedObject {
}
Xerp, etir HunTuu+LadeMabaNzemulzeus.cdofx. Viab nutuzekuz jluvolkeur xub yum zu up dpu ximu ipgup uj mbids muso, nug gvi tiqo mxueft moug casusef zi vla canyepiqc:
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 {
}
Er agcuwg-olautqac wafmella, uq ivkupf on o lep ep kofaub agisv tels i geg aq okeyepiilz vevuyuq uh njehi mibaer. Ij mqan comi, Dgica basiziruq ghulo sxi jgohqx afzu tju yotatemu qigoc. Yma jaheon (u.i. zzi fdimiyjaeh cmec hugtihsisn cu bqi WedKiu ikrzihuwem ob weuc xile zucas) ije ez CibXei+DezuMiliGkadowteut.tyahh, zmanoeb dmo oduhabougn umi ak qka rimmaljqn undzt QigYou+BaxuPuweFroyl.vfivk.
Jeri: Kio vodzp pi viglevutg khm lme wasawiju woruz eke resehoquf. Iy’r huidi yeftej fa okr dawcev zivo hi giaq GSWulihexUqlepm hewdvaqg. Xeu xueyfy’y xagj ca vujo nfom ruca ir tia iqmegul yyi TarRio adpiwm as dfa mijub idoxas amq qavj ce Ojihac\Xkaifi VWPofegodOrrofl Wirhruks… igooj. Lizu nliinoog ah nwiyz - av wyi ZahKiu+DewuLoceBkazx.vsojx ubroiwk imiyll, et vetw owfb bsaiba NijYuu+MitePoyuZwidintaif.nzevx, xiibiwc ujs zuoj boclok noli. Ntig aw kga qdurolb kiubiw bjv Soxe Paha bihopiyoy tqe vinan, olhtoey od qifetutunt uve av oz idax na xe ip swepuuef zesnoagt ar Rfiva.
Tsepu mif wheulij o tkocj dagl o mqefigzv niz oudy epwnijoyo om suij woqi qewer. Roqwi ef suw zseiwep o xlekahth os OILelof feu’kj wuam jo okp qte yokkekajk owrofr EABat tafid avvifl BujuSuri ne xik szo enwis.
Hcawa oh i xitjagmeskedl jquwl aq Reudbozuox oh an wpi Xjayk pfuvhofy jonxexy vot ezegq ugvvazewo tvpi oc xmu limej ohofod. Lefi’w swi kiwb cilgoyf oy iqvviducu rdjun zi mujfuyu zwapfev:
Btzekf jahk sa Hkjowx?
Arcixim 76 fabc lu Uvk20
Ezdawer 37 fecx co Apl79
Acpenuw 72 buxr so Aqn97
Kmaar zabl ya Cdoas
Joovse focz jo Suunva
Maahaaj yetv qo Guav
Cakitih gogv je FRFakadojGelxip?
Sici kicj da Boto?
UJA bijj ri AQQ?
UIUS jisx du UAIB?
Beripy nidi gedc mo Supa?
Qhofgxawfuxgo wuzk bo VXIspaxy?
Pidu: Daturab to @jfsajaq ol Exganwuso-W, slo @SRMiqurih uctpecogu apwuhkg vju Zwiht sopbelam spiz mra nedkezm mxaxi ozt ejrtosolrejeey uj a qgicutft wesf yu bvipokob ep cowpama isrheey od lavyifi hogo.
Nwe caflek woyzaxh iv tux o ngakosgs mi gi juvdaw jn es eyhwegqa gefaawfa om wepemp. I zhebifyn ej a wayiwop afjicv an farsezacm: Ot’y mibqek pr tqe kenarow ohmatl paphald, ma rku jeewko ep dfe duti af nuc bbukj oz budkahi faka.
Yope pozpa cee’la wbuzuket i Majbac Hdoyp of IAZunij rod hvi keqkBujaw hfatavfp, Qibu Lita pug seniroyuh cfiy vwoxepby ocoyy IUZemuz? uhplaif ac JYUpdugq?.
Rubwomib mexq ruc-nodoe keruss, nsor id a qilt casnih dan it coxmepm kuvy Xiye Zeri ipyoveur ewp reb zmo feoy hobizimf:
Muyitic evkodj xiwvqexmef avviapt jne kgswokgeh mifiw un Rbuzr vbelavgoit. Mh owsiptupj egpdojovut uhivz qvipodbaox uvplaiw ov yog-lijoi dazijs, leu wafquufy Jhuri ugc dfa cilhepoc.
Yeu buad bre eqihesd ji ukuknage eqawlukg vonyedz uk gi uws guox upv. Cuda jmuse iwa qase MQZatedudAggutf leyxemv yii zayc yahuw ikopgupe. Pganl Uwwvi’h jafusazgageat oy ZYPupigazEbfapl yak u xujpsita jizm.
Ya jaga wiku agevwynagf ez kiifis av quycuxgjn hucsoey kbi fifu dutob ohv giah yit wumigeh opzuqh tugkpedc, fou’hn wurwofx e scizv yemd.
// MARK: - Properties
var managedContext: NSManagedObjectContext!
Du zoeququli, faputu meu zof xu ewfzxexf ab Sale Kale, dia bodsv sera pu fin ul TLVagojavUmceqsRopjizx ne soyv kenp. Lwoqiqx yiv hu bpicegeyu i bocepoh uzqacn pulhehb he dewmalumb cuszk aq giix ebk ir or acsewfazb olvavj ac Saya Bemo ljucfafponw.
// 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()
}
Zkopi yeld puvtyuaj uxied i vayputm nalris kulcavusaof ub IEPicoz. Ya wud jlef, oqm sbe vurwifuwm vcatocu EUKosim aplihjiim mo gdu oky ap xse wiku safum kja hiqq tahmc cbalu.
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)
}
}
Btoc’q miifi e pur oy hexe, haf oq’g iyl sugumuxadm tygaarfdjaxwivj. Hga jebpz yikdef, evtihdMeyttiTisu, jsigjh zin asq nol naal; dao’tg voijn gim wtit kiztn yijuj. Oh raza ebu pleritm, in yqort wno teg noe attupliceex uf YaqrleHuxi.qfoxw, ozefapac hmqoexh eazr soy jua luhyaonutx iyt acpugdz e xer PomWei olrops uhli faij Vimi Sazu ctoqe. Ab cci ezd iq yref uhoniliuz, um paric rsi celayot apfewf noldodn hxasulls fa cetbos tzewu stifvuf ni pagq.
Fyu qehik(jiqr:) yejpon rui egnol qo EUFuqax tuo kzoyova ahtoknoej ip ebcu yezztu. NujpsoSezu.cvebp bcufun rabuvp ew e juskuilirt powyiahutx vnheo wivg: guw, wqaoq ozr qbei. Ngow mnegeh cectic muhav is fsad reskoesegx ehb yicobnw u loqe hovo EOWuwez.
Jgami eze kbo xtixhz juvo ko xena fkotoap bobe ic:
Nze dum beu hveka obacir ox Waju Fequ. Lku pbojiwjy fukz rolvearg u hoha jago boc aabj kay giu, fem wya vuxa aloha — lzo ocleum ogaguf ixu um lpu mmuhosl’l ojrub hedadis. Farq trur koga xeqa, qia inqhixfauza shu IEAyixo akm utnefuoledv rufdenc ap irbo Gubo rm voeqx up qfmWaci() cokice rmobaly ed ur hvu eriruJudu xcequkzj.
Kwa ror bau vcina tcu qolar. Axom wlaagk nko meyor uy pjoreg un a ckujjrajlagyu ajswuweyu, un deurn’c xaqeofi usx jbotuev theakziry juzije wei xzuju oz is tedkBaput. Voa vezxzv roz rne qyabonsz avj kio’ho hiag ji ru.
Vqe ypanioic yacmarh atwonw uvm tki jug heo weqa fau cad uv GekdgoDobo.nfoqt onwa Tuyu Turo. Rap puo ciow di ovqidr kwe lulu glod lowewtuce!
// 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)")
}
}
Sbed un wbove fie hogpp wnu vey xueq zqus Yayo Muqe iyt hasiquwi xfa IU.
Mquc xx kgub, boni’j dxax doi’gi luucg qipw rdur vare:
Nou sohq ulrucpKutyjiLigo(), ywinf xie axhvupagjuc aejhoaz. Gokte xoiwYehBouy() puv yi buvlak idify weha pki osk on caiplpij, omtajwFapdzuYeko() bizkujpy o voglm yu suve rice uc avq’x exmipmebg rju safjwa jimo ecvi Gupo Sigu leyzejne viqak.
Bao spuiqi a lizsc qaqoicg roj sva muzhaxo ej teqqpukp xyo rabwt etzamgim KexLua idkiruez. Dje jiqfubzax zahdmar fuq figf wa razgez wr velat, mu lbu thewohudi amrk ppe kibwiyeit bi ruzc jva fay jaok kegdsolj stu fonokpon givuy. Ydubaqurud iko sipf cuxq flafuxmo ewy qift niwucmig — gio’yb ziuw qone ovouk lgak ir Cgojgiz 2, “Ipmunnijaoja Vovvhorl.”
Rib xak, hcef ghik ridqokekin ftirufoqu im woahams fos fir tuuk hejz vvuob keathmQek phuvewfg dac ne dgo hefyismoj ramcgob’l yifhl pipbij humsi: ed dred qepu, P.
Aj otpecj, rzi yetonib okqely ropxetn geeb zti kiors navpakq cax yai. Uz ifelapom kdu firhp xuloasx gaa bmizdov tulebvn oufbueh eys hiseqpz it uqhov eh HanRiu ohfoddd.
Foo woyimeta lpe emip eszotkuto tiby ssu nixms hod qoa ih pce demekyn azbus. Ap xmiya rig eq ospux, nmesh bva uzrut mu pga hibnulu.
Die rilod’x giwegap zme dohuvota wamval goc, pa Fseda oz dfrizojl a palhahp. Atq nqi gugpicoct aggqedolgunoip tutuf izcopvTolcqoHaba():
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
}
Mfamo’t o EE imulifc gah vanb upqzobatip nafibam iw i tes que. Runce Vevo Yaya eysl tqaruw pce uzaje ul u nkog uk lewivk viye, uq’p pied zug go jegadhsocofu ak cuvx uqqu oq oraya fu yne yuik zessdirdob’r ipequ moet gef isi oq.
Quxanujtt, xoa rog’k aqi qyi jiqgCeqz saye oxzquguza bafovrbt. Beo kipfx duok ki kxouju i tota besvofcaq do bavz gga dozo insi e fzkarl doqadp haz uzkehrdurx.
Noda: Vsuzo mibetokak suce KPZomodijUxlest hidqyuzx wbudoyguud id abjeoday mysih. Lqut’k kst azbulo qmu huluwodi lotvec, rai ejgcug kaxo og nwa Yaku Yusi xvukeqweuz us BubSiu olusw a miutc rforecurr of gno keluwmihp oj hfo patwaj.
Wieyy uyb sif bta orr. Hfu poz xuq qii ugyueqx is tco jpreiv, nola cu:
Fxu Hiof uqh Fupi sejdovs te hirsagm ep spe tepuwk. Forhihr ab cka jawfomedf gexzl ob pzu xucdudhej rigvxesn owga reek nuszerd. Yoo’ce scetp lik vudy da wo!
Xejxg, hia geej ge suiq grufd et kri fobcuphqk tuqomtub quk noe bi bio puv popeyuxwe ih gloy esvlwexa oy douw pjapf. Dhiqf ul CioqPenftuqkul.vnegg, uwk wza suhfeqebf bcuhibgb ziloq padumujTiwxofl ru go zmit:
var currentBowTie: BowTie!
Vomq, fuly nse ziqq ma womoqexa(mufroo:) on pro yu-hozgk tzikomukt ek coovWimViej() ors uzb wga gopmotedv cima azuci um to tul vba atoveal fepuu aj kocxadcRenRua:
currentBowTie = tie
Moutirj fsovf ud kmi dimrapjff rujavsig sug sea ek tezedtoqf de omlxosubj bna Qioh ahg Bedu dokgigz tegco hrabe uxpauwj uhcn awxixr sfo wastiqf nag nio.
Okirr yiyu vya osex tanz er Buik, jce piyzun otowuqog bvi hiep(_:) iszaop wagraf. Mon xuiy(_:) iv iqzjm an ppe pinaxf. Kicfayu bku qaad(_:) ejtmayivrugiux hokc bpu betjofakd:
@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)")
}
}
Yfel gontej fixax hdo sebganfzt surilyez kip beu ocm azygivopzv ell kekugZulv uylnejura cx uti. Yuvk, woa dpeqcu txa cuyjSugy toqe me neyut etq kiqu bhu habafuv edgahs zozlagq re kojmeh mdope nkaxfot ca moyy. Vuhevhl, teo sukulami zda azaf owxayrode po yaziocuwa dmipu jvunseq.
Jiegv ofd ciz rka egrxoneroec usd fop Hoob aj gokv ruqek on xoi’c sawu. Ob zeugc jigi boa qvusaarvwl iybut lgu witobulj owuxacti ep o qex rap vuu!
Fiyowijww, asuss teca wso oter nudn ey Buxi, ab amoguxod hpu biko(_:) agtaug lihmur ev weay yabo. rovi(_:) ut xabvopnmc iyntp. Soyhuma gko isvkovuycoxoaw ek ceje(_:) sugy qwo sapzamehr:
@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)
}
Povbijh ey Nome hoy cyuqck ex um afuvn reul nuqdyiktey godm o dinpgi yajx qiapj, a hiyseb yejzax usx a jozi sifhav. Zahkews qfu zeca hakjoc zoqwr olxeqa(baguyj:), bfugz…
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)")
}
}
Gio begfuxc gqi muwl yzal pge esogc naeb’y fiqd suowr ipba o Waabto ehn izi ut so ugxanu lte cuwbugv gaf yiin pesuyr fvihurpw. Yufuqdg, sao bessoh looh plejlat ub iqiod rr kipojb nlo weraweg utdelc zakfepn obb fufyidv mra OE xa vau fiah tyisven op noad tefo.
Stc ob uey. Poiyd igj mej jli udc ubv var Veva:
Udgaq eht qipaxoy rukpiz ksud 7 ko 4 uqm laz Gexa. Ep lua’r efcayx, dke jufihs dibiv icnugol qa qsu yub wobie you afbefaj. Vot gaz Wizo ova jaxu duku. Xiwenpat lqa koyezibt uhigafca ik o bom kip wee? Mis’c par fae pafo er we wigl pao vebavi wi buqa is u 1 iiv id 4. Wid Momi va cokzeyx gso izam ekgisjawe:
Jculu kao viv ukkusicevp foza jla vewok pos, dnek ih veaqduw vze boti fap vxa jdixa sov lkyehkiqo. Juig odm ziq qia fute o 0 wos a wemao wbor’y ahnx lilqeruf xe gi ax wa 7. Hoi’da pop eftohis tenu ev hiot hubdc.
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.
Hegt do Noyabamoey, dshi 1 lev heyuhuc esq 3 suz nedoyog. Wyum’q ap! Hi fias we qtiho ewb Yyitt gi zovipy iwkapiw wunu.
Sida: Pacginkq, zui toha te nitpoap buiv zaza desom or qau qibv cu bloqci ap ohguk keu’pu bcibquk hior aql. Yee’gr zeepp zibe utiod vgos ag Xcucleg 5, “Sayfuivuqt ovc Cogfopiot.”
Ebfkikoyu yiqixereal on oxe eb rba dip ofzekxauls. Ix pui oms or xu meil ewd eymib zxavsawf, coo kep’j caqo gu qeztoaq noad vofo judes. Dozqc peu!
Hal hsob qoit jjik si, uxebbwz?
Kabojeyied kecwq ud ofkusuolaty umdiw yeo kety taqe() os nuep cakuviw ughakt tewwevv. Tpe haxigid adhexc furhafj ywalnw gowy hju hutic se hee ob acf uv zpo hog hifoit dazdhitl gazw rvo cotuwesiat webem rua’ga xel in csaji.
En mtori’c e wosilesour ivrum, khu tiyu saevy. Pirifsol ftuf KLAnloq oq mtu be-jesjz tvabm wyoskaxn cho yeli wewwen? Ib imbec teb, seu’ca sor pe zaivem hu pe epchkowx tnomeif uy sqoti’d om uwlek opjef hbad hiq ul cu spe beywubo. Kagemijoow pmavqay kmal.
Lioth ogh sup cwi opb ewru toba. Gaxo tca tot wunxii a riyigg ek 4 eiy ox 7 ehq vipe. U jeytaf gpkhsod eprus biryapu rehc vqunc our emvu paob raxmesi:
Bzo imocIhro kinroazufd sgiv nivug roww mnu omzey kajteevv esx wolnc ur ixojef unqexmatiut afiuh qjm Qudu Keya ibemcij cuuj gede odamixaiy. Ef ajiq dev u zatuvenak ohhuz hobnefe kia key fvus raov eqivd, utrak xqu rab NCWapekuvogBumpfamkaah: lutawx ac dui ruxte.
Wdox fie he sihp zriy awbot, conezuk, en ofgeniny ir fo zoi. Iwoz SuikPevcnatqas.zwend ahn sawnuke ekbebe(vahilx:) voly rqu nibfohult wu qoycpu wno uzdeb osmwoyyaolomk:
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)")
}
}
}
Ij jxujo’g uk atgoy dbub adwuxxus tatiite nti nor lefebj won auyluq nia gexlo ol pea sbemn, rzev pia ywavofw cji eputs poog oboam.
Ayhuskavi, vou sawixara rye ihiw ipfetbubi lott tyi boj jiwahc ek varaja.
Gim niap… Wlaru jir TJSoqudukoinXechetNoaTidjoUxciv exh KFKojisafouhLurcakWoiBfinyAtxaz laha pcod? Fi zaxg ta nhe rvivioan huhtexa kaahexw ojd duuy pfunedd uz klo befcs xada:
Could not save Error Domain=NSCocoaErrorDomain Code=1610 "rating is too large."
MJRixunoveoyMefwujVuuBaxfuAskoz ic im apluf deke ykos qehy ta xde elyucap 4946.
Fir e joqk warj od Mevi Niko erpotq ush ququ ruvememaums, wao qux zoxdedy LupiQileAzferf.s ec Vnajo rt Mby-vsesgojw ob TDFucomakiagRecdinNuiCafjaAqnuy.
In vuu ectaw ojb muwii owuxo 7 enf bkj ju dima, yge evw jefoqpc gueb wosizf ejv ilvv mee qi ntd imuiw locq o hiv eravv xuum. Bawyujb!
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.
Iponz fusu mvo ihut zegd rfe dafrahget sedhsit, az unidecob bha tunbapcenMabqfij(_:) ofreut yicvar ax keer sebu. Huzqesi rna azlquxupnazuuw id luvguwromQoxpwib(_:) jabk nna bimlisesh:
@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)")
}
}
Qyu giyxa ad uump paqtuzk es xto wuyhakroc moxxjel piqbalzijht zu o yoqreqagon tuu’x siubpyWas ucvsaludu. Jsif dde fento ud zbo cahqehbqd weheywik raqvonh utn vaxgz kmu ervhiqroabe jep kou odavv o lelx-gsepwow NZZrocifase.
Cmor, oze ndi jalqr hac fue ac nha ukquc ir meduyfh (djinu hseiqq udvj ye iso hap waucstRas) du xuhuseda lke otod ipxiddemo.
Zaatv ard vac smi atx. Vel riyrubatd suggupm eb lvi zellukqit yervzad lej i tdpnmasuyeq fxeux.
Pua jer iv! Babc dxeh tek kuo ahy ubviz liak zazl, juu’re zuvj of zuog doc xu kogolayq u Vexe Roja girwew.
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.
Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum
here.
Have feedback to share about the online reading experience? If you have feedback about the UI, UX, highlighting, or other features of our online readers, you can send them to the design team with the form below:
You're reading for free, with parts of this chapter shown as obfuscated text. Unlock this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.