UITableViewCell是UIView的子類。創(chuàng)建UIView子類時(shí),定制界面的方法是覆蓋drawRect:,但是在創(chuàng)建UITableViewCell子類時(shí),定制界面的方法是向UITableViewCell加入子視圖。不過,并不是直接將子視圖加入U(xiǎn)ITableViewCell,而是加入U(xiǎn)ITableViewCell的另一個(gè)子視圖:contentView。
contentView起容器的作用,用于存放其他子視圖。這些子視圖構(gòu)成UITableViewCell的布局(見圖192)。要改變UITableViewCell子類的外觀,需要修改contentView所包含的子視圖。

必須將子視圖加入contentView而不是UITableViewCell對象自身的原因是,UITableViewCell對象會(huì)根據(jù)外部條件改變contentView的大小。例如,當(dāng)UITableView對象進(jìn)入編輯模式時(shí),UITableViewCell對象會(huì)改變contentView的大小,為編輯控件(例如刪除控件和移位控件)留出位置(見圖193)。如果直接將子視圖加入U(xiǎn)ITableViewCell對象,編輯控件就會(huì)遮住這些子視圖。進(jìn)入編輯模式時(shí),UITableViewCell對象不會(huì)改變大小(UITableViewCell對象的寬度必須和UITableView對象的寬度相等),但是其包含的contentView會(huì)改變大小。
讀者可能已經(jīng)注意到視圖層次結(jié)構(gòu)中的UIScrollView對象,當(dāng)UITableView對象進(jìn)入編輯模式時(shí),UITableViewCell對象會(huì)將contentView移動(dòng)到左側(cè),這個(gè)過程需要借助UIScrollView對象。同樣,在UITableViewCell對象中從右向左滑動(dòng)顯示刪除控件時(shí),也需要借助UIScrollView對象。實(shí)際上,contentView是UIScrollView對象的一個(gè)子視圖。

創(chuàng)建UITableViewCell子類界面的最簡單方法就是使用XIB文件。
UITableViewCell的XIB文件不會(huì)使用File'sOwner,所以不用為其設(shè)置類名,也不用為其創(chuàng)建任何關(guān)聯(lián)。與UIViewController的XIB文件不同,UITableViewCell的XIB文件在解固時(shí),不需要使用某個(gè)對象代替File'sOwner,也不需要將其中的固化對象關(guān)聯(lián)到File'sOwner。為了理解兩種XIB文件的區(qū)別,首先需要知道UITableView加載UITableViewCell的過程。

注冊NIB文件的原理非常簡單,僅僅是將UINib對象以“BNRItemCell”作為鍵保存到NSDictionary中。UINib對象包含所有保存在其XIB文件中的數(shù)據(jù),當(dāng)UITableView對象需要使用UITableViewCell對象時(shí),就會(huì)使用相應(yīng)的UINib對象創(chuàng)建新的UITableViewCell對象。
在UITableView對象中注冊了包含xib的UINib對象之后,UITableView對象就可以通過“BNRItemCell”鍵找到并加載BNRItemCell對象。

縮略圖
詳細(xì)看19.2
iOS SDK提供了多種創(chuàng)建縮略圖的途徑,其中之一是根據(jù)原圖在屏外上下文(offscreencontext)中畫出按比率縮小后的版本,然后從上下文取出新創(chuàng)建的圖片。下面通過這種途徑為BNRItem對象的圖片創(chuàng)建縮略圖。
由UITableViewCell對象轉(zhuǎn)發(fā)動(dòng)作消息

請注意,Block被聲明為copy。系統(tǒng)對Block對象和其他對象的內(nèi)存管理方式不同,Block對象是在棧中創(chuàng)建的,而其他對象是在堆中創(chuàng)建的。這意味著,即使應(yīng)用針對新創(chuàng)建的Block對象保留了強(qiáng)引用類型的指針,一旦創(chuàng)建該對象的方法返回,那么與方法內(nèi)部的其他局部變量相同,新創(chuàng)建的Block對象也會(huì)被立即釋放。為了在聲明Block對象的方法返回后仍然保留該對象,必須向其發(fā)送copy消息??截惸硞€(gè)Block對象時(shí),應(yīng)用會(huì)在堆中創(chuàng)建該對象的備份。這樣,即使應(yīng)用釋放了當(dāng)前方法的棧,堆中的Block對象也不會(huì)被釋放。
image.png
捕獲變量
Block對象可以使用其封閉作用域(enclosingscope)內(nèi)的所有變量。對聲明了某個(gè)Block對象的方法,該方法的作用域就是這個(gè)Block對象的封閉作用域。因此,這個(gè)Block對象可以訪問該方法的所有局部變量、傳入該方法的實(shí)參以及所屬對象的實(shí)例變量。如果捕獲變量是ObjectiveC對象,那么Block對象對捕獲變量具有強(qiáng)引用。如果捕獲變量也對Block對象具有強(qiáng)引用,就會(huì)導(dǎo)致強(qiáng)引用循環(huán)。
解決問題的方法是:將actionBlock對cell的引用改為弱引用。
image.png
在Block對象執(zhí)行過程中,必須保證Block對象始終可以訪問cell。因此,以上代碼在actionBlock內(nèi)部創(chuàng)建了strongCell,以保持對cell的強(qiáng)引用。這與Block對象對捕獲變量的強(qiáng)引用不同,strongCell只是在Block對象執(zhí)行過程中對cell保持強(qiáng)引用。
UICollectionView
UICollectionView與UITableView非常相似:
?UICollectionView是UIScrollView的子類。
?與UITableViewCell類似,UICollectionView對象顯示一組UICollectionViewCell或其子類。
?UICollectionView具有數(shù)據(jù)源,負(fù)責(zé)提供UICollectionViewCell。 ?UICollectionView具有委托,可以在委托方法中處理相關(guān)回調(diào)事件,例如選擇了某一個(gè)UICollectionViewCell。
?UICollectionViewController與UITableViewController類似,UICollectionViewController也是UIViewController的子類,其view是UICollectionView。
UICollectionView與UITableView的區(qū)別是,UITableView只能顯示一列UITableViewCell,在大屏幕設(shè)備(如iPad)中有很大的局限性。UICollectionView則可以將UICollectionViewCell按任意方式布局,其中最常見的是網(wǎng)格布局


UICollectionView是如何布局UICollectionViewCell的?UICollectionView含有一個(gè)布局對象,負(fù)責(zé)控制每一個(gè)UICollectionViewCell的屬性,包括位置和大小。UICollectionView的布局對象繼承自一個(gè)名為UICollectionViewLayout的抽象類。如果需要將UICollectionViewCell按網(wǎng)格布局,則可以使用系統(tǒng)提供的UICollectionViewFlowLayout。但是,如果需要實(shí)現(xiàn)其他的布局方式,就必須創(chuàng)建UICollectionViewLayout的自定義子類。
UICollectionViewCell也有contentView,但是與UITableViewCell不同,UICollectionViewCell的contentView在默認(rèn)情況下沒有任何子視圖(UITableView默認(rèn)是有Cell,不一定要自主創(chuàng)建)。因此,如果需要使用UICollectionView,通常還需要?jiǎng)?chuàng)建一個(gè)UICollectionViewCell子類。
最后,UICollectionViewCell也具有背景視圖和選中狀態(tài)下的背景視圖(當(dāng)UICollectionViewCell處于選中狀態(tài)時(shí),該視圖會(huì)覆蓋在背景視圖上方)。


