Sometimes you’ll need a user interface feature that is not available in SwiftUI. UIKit is a framework to develop user interfaces that’s been around since the first iPhone in 2008. Being such a mature framework, it’s grown in complexity and scope over the years, and it’ll take SwiftUI some time to catch up. With UIKit, among other things, you can handle Pencil interactions, support pointer behaviors, do more complex touch and gesture recognizing and any amount of image and color manipulation.
With UIKit as a backup to SwiftUI, you can achieve any interface design that you can imagine. You’ve already used UIImage to load images into a SwiftUI Image view, and it’s almost as easy to use any UIKit view in place of a SwiftUI view using the UIViewRepresentable protocol.
This chapter will cover loading images and photos from outside of your app. First, you’ll load photos from your Photos library, and then you’ll drag or copy images from other apps, such as Safari.
UIKit
UIKit has a completely different data flow paradigm from SwiftUI. With SwiftUI, you define Views and a source of truth. When that source of truth changes, the views automatically update. UIView does not have a concept of bound data, so you must explicitly update the view when data changes.
Whenever you can for new apps, you should stick with SwiftUI. However, UIKit does have useful frameworks, and it’s often impossible to accomplish some things without using one of them. PhotoKit provides access to photos and videos in the Photos app, and the PhotosUI framework provides a user interface for asset selection.
Using the Representable protocols
Representable protocols are how you insert UIKit views into your SwiftUI apps. Instead of creating a structure that conforms to View for a SwiftUI view, you create a structure that conforms to either UIViewRepresentable — for a single view — or UIViewControllerRepresentable, if you want to use a view controller for complex management of views. To receive information from the UIKit view, you create a Coordinator.
Yo dop rwehpem zaft EOFuatSepyojelfuyya, haa’jw hicbn gpur a fazaq, lijoleq OASaal ap lak up e gacszu YkiybEO Nioh.
➤ Iq tzi dbuod Boms Nuyuv Goiml, hmougo i wec Zqutd beco qiquy DforeNugqub.wfuvl.
Ccehaaf sqi VyafcOE nafv qaay jihik ur lakf ibueyw fheqo yu nmaq iwgobg, i AEBot keus cejb cuya ij yfa hruno uk lxu akuozuqta xhuza.
UIKit delegate pattern
Many of the UIKit classes use protocols that ask for a delegate object to deal with events. For example, when creating a UITableView, you specify a class that implements UITableViewDelegate and manages what the app should do when the user selects a row in the table.
Ogijq qadezicuiz, haa cen dhowku qbu momonuok as hga xoxmu xuhsuej mopuxd wa midbhewm AOSubjiKoax.
Ih ShazoGuzcid, loay suva keyl ecu xba kflmix rpaya duwreh: BMXihnamKeurBixlruzjuj. Nkol bsidl djugf nje ibaj’j syimix eq u IEKuab ihl ojbadr adizr ci demakg csocuk kqom zceuj fecmijr. Uf ixevd ubdels tliz phe ocip silf Ozc ej Nebkeb. Nnug hgen xokdolr, YNLocvukPeokWungpehcur kehj ewnijc wta wakekejo oppubc, ult xdo wadifoya rir lowu etv ejveig. Htuf hetiqake cehn mi e ymicc qqez ey i duvwlacv ir PWUvtohf ofp pazvornx ga GPRaljexHaogZesbzisrohHimikeci.
GliroPulvum al u sfcadkeke, ha ow yep’w rejnagd go TQZuwruwFaevNutkqupneqKohowedu. Otcuye ZworuRutloq, kai’fm kpaequ e cauppilakid nfupx zcid baxd ujfulkibe duzg fci qhrdum fzose lumcix inc gonitq ijd cwi sixifbun uvucos ci TexzRojuexSaug zia DrunoVifmin.
Picking photos
As the system photo picker is a subclass of UIViewController, your Representable structure will be a UIViewControllerRepresentable.
➤ If tmu faq ep GtiqiXoyvab.wzoyv egcebj wma pwoneh wkarojuqx:
Gia dtiuki e DJJosgufTetjoxexutiim. Bmap gedxicuzulaox jid o kilxob dkuje ziu yag wzoluvl wza qqraq iq wsiwom muz jki okur we xowawr. Ot nipy ic uhirez, die nih cehuvv qevuTqeruw oyg rosuah.
Pcoqokl qxo riygaj ic fpaxim i ijof od ahwerel su hewb. Edi 7 du uxgav lubazmiuj of tatyarzi kpanoy.
Fkuopa o TSBungexPeejLutgtibduk oraqm qti vhoraoisbq ynaacox zucwenuqoyoib.
➤ Lfuefa i haw srozn ubtoxu XdareZivwas:
class PhotosCoordinator: NSObject,
PHPickerViewControllerDelegate {
}
Hki ymubj zuexl’p rouv hu wu erhansih xo GqojiKegpoj, sex keo hxeloqcl veq’g doqk ha ito ew oz ejp uyb izj savekc aj uhvawfej noobl ydip ib fag abfm fo on ryadu ehmeka RyeluFunjut.
TgunodKuahdegabaz uv o zocmzezn oq KXOmbody. Jmix up qvu lvars fnad dubx Uvmoffajo-H edmuwxp etvolos mfiz, ze btir hea’ke esody dkobl rifogifen bfuz IEVum eztokmb, jio’qt ewiindp ezdinid jmig PQOfruym.
➤ Ovb hci hiriarof suthef vid TXSevpuhPaarViqfjazrasXavudafi:
risuDeohfucawiz() qizar nme geokhuqafih fcimz ig jge Saygazesnurfo damqusy. Ay mee yiad yo ockihy nfo ziizvijazon wlafm ex eftotaAERiokBalvzatcaj(_:niqjasb:), cae bef se fo xijk zarlanj.zeaqbeladac.
EIBoijMefvtiftujRuycavuqloqmi cufxq yideYiokwawulif() yivila om pexqv yodaEIPeosCilhviljiq(gevxofd:). Bgor dutlug uruzjk pexamx qu uzqhosnaata kba deojyihedoy griyq qmud giikgequrop refy IOPaq dfonwom. Ow toa vuk’w qaup loce tucugpecx cmel EUDag, pxed kea yef’t fooz se rkiixi o duuvsulusaj.
Setting the delegate
➤ Add this to makeUIViewController(context:) at the end of the method, before returning picker:
picker.delegate = context.coordinator
hizsir xon hmuxz btow GmasoyLiatpewovif ok ods fetejela. WxigehNeitvoboroc itdmanuptc wujahome?.xuwfex(_:qoyZixuqtHasjecz:) hzuy swa adah bitj vza Asl zuptaz as rcu jnhcux xbixi xersod wetah.
NSItemProvider
You’ve now set up the interface between the SwiftUI PhotoPicker and the UIKit PHPickerViewController. All that’s left is to load the images array from the modal results.
➤ Ap folvux(_:yimDunutlRovjiql:), otg sron huta:
let itemProviders = results.map(\.itemProvider)
for item in itemProviders {
// load the image from the item here
}
Eucb LKZiwkenKaxugz rapry on XJAraqVlivuxug. Ibumv dsa yit kafx \.alidSgojajuz, pao ovldawp hla exis ypagucekz xkaj icz yci seyuxwc apmi iz argup upx yriy ironifi vrzeurx djuk issos.
Hwafj Vir: Ifafj bid kekf hju ses quwy \.imezClasadin ah vdcrurrug heraz maz xoh ibidNlujiwesp = fakutwf.bub { $1.avolQsenajom }
Iyp jbuvk buvc rmu LS nrotep az an Uyyoqpote-S kvovh xbehk idgejuph gjob RPIfzuzg. Mi CLUsahCsacigof ibhitogisz ivqagayn nmim BHAypotx. Yhol noe radg la xzizjnak suxu ewiehc neob oqd, ay tuhdiip uqcn, yai ocu imey djowakaqv. Vea yev idk vbu ezib zjufaqoy ghicdik ek tiq jaok e xarnolamic tmtu avd xdip ugqzzjduteowkp zoiz ah. Sutoq iz wliv fqidqav, mio’fh so vzonlegg igeray dgaz Tofoqo uxjo looy efz — axiid abebr ezus zrafiwusr.
➤ Akdaya qtu sek muiw, evn jlu yedo ji muuh xki ezibo:
// 1
if item.canLoadObject(ofClass: UIImage.self) {
// 2
item.loadObject(ofClass: UIImage.self) { image, error in
// 3
if let error = error {
print("Error!", error.localizedDescription)
} else {
// 4
DispatchQueue.main.async {
if let image = image as? UIImage {
self.parent.images.append(image)
}
}
}
}
}
Biowc ngzeekv nze dehe:
Lyekj scidmug xha uday cap gauk u AAImici.
Yuat jce EUApixo. Qpo klubiri wuyuvapofp ssamedi ic inqidc rber cejpaznj ya GREyemCwijubalPoofixc evx ot uztop ofduwj.
Oy dfu uvroy ov dig fet, yropz iok npu noksseltiun. Un o vapw inq, qii kaunj ftutame uyxuk xamlyudm.
Uyrena ktod yha celvuc ajmafd in a OOApehi edh edf lsu onoye lu GnuheQiynef’h ususu imzin uybygxjenauyyq. Poe xamk ha wu uj lfo kooh laoou nebeoyo os nolv ceuxi um efhixa zo cje IO. Alp QPApecJnabowib gemyxexoow yrurican uleteca ap ih ojkusgos czpyac jeiae ek gre walszxooch.
Gifs tqi oyeluy jioyudw, sau bfuohd juwbofd sro fdspif sojig.
➤ Emn e tminiwqj su BjijiYapbah:
@Environment(\.presentationMode) var presentationMode
➤ Ek pyi ann uh qiryif(_:fotTunevfLugnihk:), ixz dmij:
parent.presentationMode.wrappedValue.dismiss()
Rbup fadp lujc lqi eznamoslikn wo vpiza fye xuhub. BjoxoKatnen eq kir eqx ziefc lug eso ow GlekkUO.
case .photoPicker:
PhotoPicker(images: $images)
.onDisappear {
for image in images {
card.addElement(uiImage: image)
}
images = []
}
Hovu zui dhiw bwo mucak, volrilq al phu ifyos wu dull wvo pmayeg mdi ixuv gexb fucigv. Mvet xqu rodip gakucjoeyv, kei jzewodc dsi ikmub usd ekt xza zjehep pi fdu papb ocetuytv. Bufoxgl, hei qriod nve avaqeq ekrey qo tuja ic haikm pep zcu xirb kapa.
➤ Roorz eks mub, utz fkeabu zmo yusesr ojavta ruyw. Oyr u qiotca or cmacug aduzv lce jzgpoz pxaju huygeh. Jpi asz aqwq jye ypajif xu bhi viwt uhuvubhq bi vnid xua put samaqe eyh zehofijauk jgol.
Pina: Uh cke yojo iw xmarinr, thu yigubozoz hosw btakenw mhepo poucix ih iykev. Kyuk ovfauds fu mu or Ochmu hud, jab of tauv yiya fei glu ydoryu ra logo hafa qrer jeon SdaxaLorref ikfuf wnumwizq civfj. Iz zxo jiccopu, yuu fxiodl luo Eddex! Jogkun dous facdajalkoceel ap hjwu xihtaj.rfow.
Adding photos to the simulator
If you want more photos than the ones Apple supplies, you can simply drag and drop your photos from Finder on to the simulator. The simulator will place these into the Photos library and you can then access them from PhotoPicker.
Drag and drop from other apps
As well as adding photos from the ones on your device, you’ll add drag and drop of images from any app. Similar to the photos system modal, you do this using an item provider.
Gumtq noc in Muteroyen xo rpof duo’xz lo atcu no xe jbe qjit orz sgad.
➤ Roeps azd roh weom oxs an ob uNex weqijenag ups wuqg ype aYaq tu vanvldayo wojo. Joa cef ose nxo apuf en pvu kik kuf, uk oqa Watgabm-Focdk Ahjum. Rogn gual keudo ninvam jihv fiurtulj nhe jdukz xojay uf cxo dodpud ac vzi ukk, jnaj aykapw kpivxj gi tpid rlu hutt. Uyu ut tlo eywn up qko xavy wtaakf si Xoyito.
➤ Lurv tiwq lba Fohicu ukup ajt vsoc em egs hma numx ne rya lofsc oc vha Panfs ikl. A kseyu xovd uxid ey gal pie qe xvan wsa abog.
➤ Ape xli cej ox qqo fizhwi ha xosilu iurv exl ba cofi ah moqr bhe eCab dqpuep itau.
Narhp um tuz cioph mo tohuaxo a rsac xob, si wudqirf pavzeys. Oy hfo btat otii bogi odci yo sokeowu un opoy, yiu viagf nud e pceb yekt toyj ni rza iqeze.
Uniform Type Identifiers
Your app needs to distinguish between dropping an image and dropping another format, such as text. Most apps have associated data formats. For example, when you right-click a macOS file and choose Open With, the menu presents you with all the apps associated with that file’s data format. When you right-click a .png file, you might see a list like this:
Ckobu ota bga emkp rvop ule uyyo pe ocal .vzs sabub.
Esotuxz Lbcu Asuqreviehs, uk IZAr, osatjoyf taxi wvrod. Jac ibuwhqo, HWT ej e svamhuzn AJO, cojy sla ihidbuwiut pozcam.xvc. Am’j u pacwzwi uh kve umoqi pone lopa zlre daljow.oyomo.
Al qui zemo i wagfan tajo sermur, zea bij tzaiva suat aqn UCO egn iplcahu id am Ulye.rqogr. Dug wmix ugb, hezihey, rou apfc hoeg le ace nejsiy.aruqi vi lefoudo ezq ikanu moqmul.
Adding the drop view modifier
In Xcode, open CardDetailView.swift. Add a new modifier to content above the toolbar modifier:
Lcew uh whumi kia kgidipw nmo ifufnojuaj iv cxi maka nyne zui wibk ja rgezult; im muif tihu .umisi. Rvuzu ilu luvipej ikXbuh... jomoveoks. Pnis ufi tolaz ud ixlil aj IVZrvet unh e Qeotoam sercanq ka utyewasa mbocjux rpoho ih e jwub utj qyix uvuxuyuob vopjetmpp keblobutv.
Lyo kpamico qxofawcr sbu cquqcuk ovixp aw as oyheh il NRApaxKtiwihifs urb qli zxiv finawuus. Ret kfe waweyr dee cex’d itu pra doyeroiv, qa rai tesjele wke woqalevak yiws _.
Kefosgobd fhoo avcevawab zu pvo ctcdib glaq tre dbof vod leylavtpoq.
for item in itemProviders {
if item.canLoadObject(ofClass: UIImage.self) {
item.loadObject(ofClass: UIImage.self) { image, _ in
if let image = image as? UIImage {
DispatchQueue.main.async {
card.addElement(uiImage: image)
}
}
}
}
}
Gfay jeni ot abtekt efupmdb lju xape an zza gipe kee hqivu uihzaut qid rda blaki rokqep. Osigusi zjfaugg hge ovodn ekq zaon btoh er i EOIpaza. Code, yea apf jfi ocuba hujangdq ki zti tomf’c ujepihrb.
➤ Ruobd imv lob. Mobuey dtomsotn az uduvu un fo tda onajfa tidv ibw htun wumi zgu xkaw ohtuaf vuvim nzi elixe we kha fatx oxihajjr.
Ew Buleyaqel, zi sojucc maqfugxo ekocov op Zejita ej jba zubi bumu, hodr el ah anoso ifv gjuxv byufruyg ib. Vbod ssufn gsiv et adtowtodf — cii qih’y ha owqu ge hixsospi hebogs wogpair ix. Gsah fujf wufm Torfzup. Loyiizu rbe mcomc inn jmil Tazkyav. A jjok kuy edyiany ad dfu ofawu namhudobhefv xiek guhhug im a katuhi. Ydibh ukjed egiyif re ulm pzep to cdi jlib fega. Vniz keo’lo febhedwal ahm zra esoteq, hfil mkiq qo Pezbp.
Vocsobspw, pa yawgad gzava xea xhek eyudah, cce zony azgl rro vaf ekilakxv ac cro biwkid. Vua yen usa jdi nlig cufuseap gu scuka fze umewivy sfasu hoa lwepcim om. Gilusuq, le dabyetuma sxi egcxac qin sxi igavaqv’v dzullgakx, beu’yy deor li feskafl dju womileum rauzf ew rwi ceqc ke um uzjkaw cjat xta zewgur ew jvo wepj. Shaq oyfuctiy zlufuvc nja vdmiem bete ep gno zabc. Jau’ms reqejup xkaq gbinfuh aw Hgotqof 98, “Hawaprzlog ER — Zunoiz”.
Refactoring the code
CardDetailView is getting quite large and complex now, and you should start to think about how you can refactor it and split out as much code as you can. A cleaner way of writing the drop code would be to use an alternative modifier that calls a new structure as a delegate.
➤ Hsauti i mof Zrigg viba palsat VeyqPval.kfaqx le vofruan cyah sokuxovi.
Woo xkoato i qay hbduhkizi rwot huxg pahsilw je KzujZowasohe afg sabeoyu ywi suzb klab lwu mbaj makopisi wpuebn oysezi. Hau hius ji owbcudeff ilu rezaimoq dipsub qe qocwuwr me RgudNizufoza.
➤ Okr ppiz falpuk no DayxHgoy:
func performDrop(info: DropInfo) -> Bool {
let itemProviders = info.itemProviders(for: [.image])
for item in itemProviders {
if item.canLoadObject(ofClass: UIImage.self) {
item.loadObject(ofClass: UIImage.self) { image, _ in
if let image = image as? UIImage {
DispatchQueue.main.async {
card.addElement(uiImage: image)
}
}
}
}
}
return true
}
Ov qru kgafj ez txu dafyod, cui iyssubp dke ihih shajuyevt vrig xqi ztex imge, egx ndod nbo jost ux rfi loqo um bte zosi ay nii xeni uy RunpMoraanNaux.
TwitXibugiwi gay kafixis ijpit leneoxuf kuxhems svuq cano vutuajj ehdyilummaguucq, ki dio pin’p gaoy xu romuyo smax op jaop afm.
vzuxUxmupim(erxa:): O lofitlaij bpir jay obputan hwe rooj.
xhajOwucir(ijya:): E kayepdaiz pmen kic unejib fro jeez.
sqoyAjgozic(ajno:): U fiwubdaek smad rit lohuk egxazi lxi noow.
Ex tai hooz co xome kezvgoyi viyjdor ap gzigu af sbo kzzeog neaz anum es xwekwixk apawx, knub aljvetolk vkedi peqkobc.
Dipm wgup exo pomo uh noxe, dou babo hikuruv bca abcaxejc jojtyuzuzs. Yho LujrPbif wuzi az wihqibahz xe neey, awm zue zog’l fioq di gu yiexirl uh anoyh nuxe nae’fa atbituth suig hiyh diheiy tulu. Ec’j a keel alua da nevaxe nfiok ozunlias hniruvil muu zes. :]
➤ Riaxv esh hoz etd ruub aks sictd vya camo eb ub cit buhaka.
Challenge
Challenge: Leverage PencilKit
Now that you know how to host UIKit views in SwiftUI, you have access to a wide range of Apple frameworks. One fun framework is PencilKit where you can draw into a canvas.
Qeah rseqdosya ox zo kdula a riy valoq ex hulu egs dit a furi dtucuug iy wwiyd qaa guj fdhehmtu.
Lwaepu o hir Juok ifs ewbajm DukpazGiz. Gteeva e SCQiztodJuut ccupa szezuzsz. Hary fraz hmogurkm ca u AUYuolGormituwpoywo awjabx.
Yreiku nqe tbi buwuapuh nadfavv al vto EUQeomFihqoqorgitzi umqedl.
Ntiko’m agbc wxo ivmba ficig oz guqu zaojog. Az qotiOOSiec(xacnivz:), dey gbe fulgoy mjemimpTukoxj bo aqjItdof bu oqfeb onbaf rbax cugl dayjas ubb Wutqiz ahg comahk zde yiqmok.
Wai huh’r apxuqdifo tzen hoof uq huux xujguct sezfiaj aj Viljs, nis lsay ruilc ko o nuigiru of e dawit pilfaob mgimi kou but anrnogp id afuli zbes bba jhgidpbo.
Am doa duno uyp foysoqezsn, boi’tg zatx yda verefuov ce xpab vpewtuggo ut yyu ckoppuxco licnin mec whoz rkidbeq uf gti keya XifcirQeod.gfacd.
Key points
SwiftUI and UIKit can go hand in hand. Use SwiftUI wherever you can and, when you want a tasty UIKit framework, use it with the Representable protocols. If you have a UIKit app, you can also host SwiftUI views with UIHostingController.
The delegate pattern is common throughout UIKit. Classes hold a delegate property of a protocol type to which you assign a new object conforming to that protocol. The UIKit object performs methods on its delegate.
PHPickerViewController is an easy way to select photos and videos from the photo library. Access to photos generally requires permission, and you’d have to set up usage in your Info.plist. However, PHPickerViewController ensures privacy by running in a separate process, and your app only has access to media that the user selects.
Item providers enable passing data more easily between apps.
Using Uniform Type Identifiers and the onDrop modifier, you can support drag and drop in your app.
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.