iOS回顧筆記( 02 ) -- 由九宮格布局引出的一系列編程思想

前言(扯幾句淡先)

回顧到學(xué)習(xí)UI過程中的九宮格布局時,發(fā)現(xiàn)當(dāng)時學(xué)的東西真是不少荚虚。

這個階段最大的特點(diǎn)就是:知識點(diǎn)繁多且瑣碎洼滚。

我們的目標(biāo)就是要將這瑣碎的知識點(diǎn)靈活運(yùn)用、融匯貫通良蒸,通過不同的實(shí)現(xiàn)方式來實(shí)現(xiàn)相同的功能,最后進(jìn)行比較得到最好的那種方式伍玖。這個求知的過程就是我們最需要學(xué)習(xí)的嫩痰,在過程中我們學(xué)會了自我思考,并且在自己的思考和比較中窍箍,我們的腦海里逐漸形成了自己的編程思想串纺。

本文主要以九宮格購物車的實(shí)現(xiàn)為引子,從最基礎(chǔ)的實(shí)現(xiàn)方法層層遞進(jìn)直到最完美的實(shí)現(xiàn)方式椰棘。代碼從起初的低效造垛、耦合度高到后期的層層分離、MVC各模塊封裝晰搀,高內(nèi)聚五辽、低耦合,更具擴(kuò)展性等方面逐步深化和擴(kuò)展外恕;經(jīng)過編程思想的層層深入和代碼的步步完善最后完整的展現(xiàn)在用戶面前杆逗。

本文大體目錄

  • 九宮格購物車demo
  • 對應(yīng)物品封裝(View的簡單封裝)
  • 數(shù)據(jù)的加載方式對比 與 演變
  • 屬性列表文件(plist)的創(chuàng)建和使用
  • MVC 思想的引入和介紹

九宮格購物車Demo

九宮格是我們在開發(fā)過程中對于一些有規(guī)律的UI布局常用的一種布局算法。
九宮格特點(diǎn):簡單鳞疲,封裝性好罪郊,可復(fù)用性高,很適合一些頁面同類型item數(shù)量動態(tài)變化UI頁面布局

下面就實(shí)現(xiàn)一個買書購物車

Snip20170301_3.png

基本要求和思路如下

思路:
1. 最初沒有書(刪除按鈕不可用)
2. 點(diǎn)擊添加就添加一本書(刪除按鈕可用)
3. 添加基本之后(提示購物車已滿尚洽,添加按鈕不可用)
4. 刪除按鈕點(diǎn)擊(購物車不滿的時候添加按鈕又可以使用)
5. 添加書籍按九宮格的樣式在頁面中顯示



先說說最直接的方法

// 添加書
- (IBAction)addBook:(id)sender {
    
    
    // 1. 創(chuàng)建書圖標(biāo)
    UIImageView *bookIcon = [UIImageView new];
    bookIcon.image = [UIImage imageNamed:@"0"];
    bookIcon.frame = CGRectMake(0, 0, 50, 50);
    [self.shopView addSubview:bookIcon];
    
    // 2.書名
    UILabel *bookName = [UILabel new];
    bookName.frame = CGRectMake(0, 50, 50, 20);
    bookName.text = @"book1";
    bookName.textAlignment = NSTextAlignmentCenter;
    [self.shopView addSubview:bookName];
    
    // 3.添加到數(shù)組(分開寫好像很難明確如何添加這本書)

}

這是最直接的方法來添加的一本書悔橄,這樣確實(shí)能添加一本書,但是這種直觀腺毫、死板的思想是不對的癣疟。

  • 面對這樣的動態(tài)變化的UI頁面,每次添加和刪除書籍的操作都是用戶隨機(jī)的潮酒,所以代碼每次也是根據(jù)對應(yīng)的點(diǎn)擊來計(jì)算對應(yīng)書籍要添加的位置睛挚。
  • 每本書的位置主要是和它對應(yīng)的index來確定,這就涉及到“書”這個對象要每次計(jì)數(shù)急黎,書是一個整體扎狱,所以書內(nèi)部的東西應(yīng)當(dāng)封裝起來侧到。
  • “書”在UI上表現(xiàn)是 圖標(biāo) + 書名,也就是iamgeview + label淤击,從用戶看到的整體性上來說匠抗,每次添加和刪除同一本書也需要對 圖標(biāo) 和 書名 分別計(jì)算兩次來計(jì)算和排列。這也是非常不合理的污抬,并且很容易計(jì)算出現(xiàn)問題汞贸。應(yīng)該根據(jù)UIView 父子控件相關(guān)特性對“書”進(jìn)行封裝,添加/刪除的時候統(tǒng)一處理父控件壕吹,至于內(nèi)部屬性都會根據(jù)父控件來自動布局,方便管理删铃。

書的封裝

了解以上說的直接把代碼分開寫的局限性之后耳贬,現(xiàn)在來封裝一下“書”這個對象。

  • UI層的封裝猎唁,我們先分析UI布局:內(nèi)部屬性只有 圖標(biāo)(UIImagevView) 和 書名(UILabel)
  • 父控件選取原則:父控件只是承載子控件的容器咒劲,應(yīng)當(dāng)簡潔為主,所以選擇 UIView

    // 0. 創(chuàng)建書
    UIView *book = [UIView new];
    book.frame = CGRectMake(0, 0, 60, 70);
    book.backgroundColor = [UIColor redColor];
    [self.shopView addSubview:book];
    
    
    // 1. 創(chuàng)建書圖標(biāo)
    UIImageView *bookIcon = [UIImageView new];
    bookIcon.image = [UIImage imageNamed:@"0"];
    bookIcon.frame = CGRectMake(0, 0, 60, 50);
    [book addSubview:bookIcon];
    
    // 2.書名
    UILabel *bookName = [UILabel new];
    bookName.frame = CGRectMake(0, 50, 60, 20);
    bookName.text = @"book1";
    bookName.textAlignment = NSTextAlignmentCenter;
    [book addSubview:bookName];
    
    // 3.添加到數(shù)組(直接添加書這個對象)
    [self.books addObject:book];
    

這樣在創(chuàng)建和管理書的時候就方便多了诫隅,并且有一個數(shù)組來記錄添加書的數(shù)量腐魂,在添加和刪除的時候有計(jì)算的依據(jù):可計(jì)算對應(yīng)位置和兩個按鈕的可用情況

九宮格布局的思路和實(shí)現(xiàn)

書的對象已經(jīng)封裝好了,我們可以以整體思維來操作它逐纬,下面就是計(jì)算位置的思路蛔屹。

  • 書的數(shù)量不定,但列數(shù)是固定的豁生,可以設(shè)置成變量 int clos = 3兔毒;
  • 每本書之間可能有一定間距,橫向間距 margin = ( width - clos * book.width)/ ( clos / 2) ;
  • 每本書的位置(x,y)可根據(jù)下圖發(fā)現(xiàn)規(guī)律 x = 列號 * (W + margin)甸箱; y = 行號 * (H+margin)
  • 行號規(guī)律 : 行號 = index / clos ;
  • 列號規(guī)律 : 列號 = index % clos ;
Snip20170301_4.png

有了上面的鋪墊育叁,就可以寫動態(tài)代碼了,只需要用戶 設(shè)置一個列數(shù)芍殖,知道最終有多少本書豪嗽,遍歷每本書,根據(jù)書的索引來計(jì)算對應(yīng)的書的位置即可豌骏。

廢話不多說了龟梦,上代碼

// 添加書
- (IBAction)addBook:(id)sender {
    
    
    // 設(shè)置列數(shù)為 3
    int clos = 3;
    
    // 設(shè)置書的寬高分別為 W H
    CGFloat W = 60;
    CGFloat H = 70;
    CGFloat iconH = 50;
    
    
    // 0. 創(chuàng)建書
    UIView *book = [UIView new];
    book.backgroundColor = [UIColor redColor];
    [self.shopView addSubview:book];
    
    // 計(jì)算書的位置
    // 獲得索引
    NSUInteger index = [self.books count];
    // 計(jì)算橫間距 margin
    CGFloat margin = (self.shopView.frame.size.width - clos * W) / (clos - 1);
    // 書 frame 的 X
    CGFloat x = (index % clos) * (W + margin);
    // 書 frame 的 Y
    CGFloat y = (index / clos) * (H + margin);
    
    book.frame = CGRectMake(x, y, W, H);
    
    
    // 1. 創(chuàng)建書圖標(biāo)
    UIImageView *bookIcon = [UIImageView new];
    bookIcon.image = [UIImage imageNamed:@"0"];
    bookIcon.frame = CGRectMake(0, 0, W, iconH);
    [book addSubview:bookIcon];
    
    // 2.書名
    UILabel *bookName = [UILabel new];
    bookName.frame = CGRectMake(0, iconH, W, H-iconH);
    bookName.text = @"book1";
    bookName.textAlignment = NSTextAlignmentCenter;
    [book addSubview:bookName];
    
    // 3.添加到數(shù)組(分開寫好像很難明確如何添加這本書)
    [self.books addObject:book];
    
}

效果圖如下

Snip20170301_5.png

書數(shù)據(jù)加載方式和對比

到這里購物車?yán)锏臅呀?jīng)可以隨意添加了,并且可以根據(jù)用戶的點(diǎn)擊窃躲,無限制的添加变秦。
如果項(xiàng)目需求修改了,比如變成5列了框舔,寬高什么的也是根據(jù)項(xiàng)目自行修改就行蹦玫。
九宮格布局的代碼已經(jīng)完成了赎婚。

現(xiàn)在需要注意的問題是,“書”的屬性數(shù)據(jù)的添加問題樱溉,現(xiàn)在簡單的來說挣输,書屬性有 :書名 + icon。

“書”的各屬性值福贞,應(yīng)該如何賦值呢撩嚼?



幾種簡單數(shù)據(jù)加載方法與對比

  • 直接根據(jù) index 來進(jìn)行if判斷,逐個添加數(shù)據(jù)
    if (index == 0) {
        
        bookIcon.image = [UIImage imageNamed:@"0"];
        bookName.text = @"Book1";
        
    }else if(index == 1)
    {
        bookIcon.image = [UIImage imageNamed:@"1"];
        bookName.text = @"Book2";
    }
    else if(index == 2)
    {
        bookIcon.image = [UIImage imageNamed:@"2"];
        bookName.text = @"Book3";
    }
    ...
    
  • 創(chuàng)建一個書的數(shù)組挖帘,數(shù)組存放對應(yīng)的字典完丽,作為書的屬性方法的數(shù)據(jù)源,從中取值
// 0.創(chuàng)建書的數(shù)據(jù)源
    self.books = @[
                       @{
                           @"icon":@"0",
                           @"name":@"book1"
                        },
                       @{
                           @"icon":@"1",
                           @"name":@"book2"
                           },
                       @{
                           @"icon":@"2",
                           @"name":@"book3"
                           },
                       @{
                           @"icon":@"3",
                           @"name":@"book4"
                           },
                       ];
                       
// 1.書圖標(biāo)
bookIcon.image = [UIImage imageNamed:self.books[index][@"icon"]];  
// 2.書名
bookName.text = self.books[index][@"name"];

  • 進(jìn)一步分離數(shù)據(jù)拇舀,將數(shù)據(jù)信息放到其他文件中逻族,用的時候從文件中讀取
    // 獲取文件路徑
    NSString *books = [[NSBundle mainBundle] pathForResource:@"bookData" ofType:@"plist"];
    // 加載路徑中內(nèi)容放到數(shù)組中
    _books = [NSMutableArray arrayWithContentsOfFile:books];
    
    // 1.書圖標(biāo)
    bookIcon.image = [UIImage imageNamed:self.books[index][@"icon"]];  
    // 2.書名
    bookName.text = self.books[index][@"name"];
    

對于三種方法簡單的比較和點(diǎn)評

  • 第一種直接if判斷index的位置
    • 直接把動態(tài)判斷代碼寫到代碼中,過于死板
    • 代碼耦合性太高骄崩,及其不利于后期擴(kuò)展聘鳞,如果加數(shù)據(jù)簡直是惡魔
    • 一些死布局并且元素個數(shù)極少(幾個)的時候可以使用
    • 代碼重復(fù)性高,技術(shù)含量低
  • 第二種把數(shù)據(jù)代碼獨(dú)立出來放到一個數(shù)組中
    • 避免了第一種直接寫到代碼中的低效且惡心的做法
    • 代碼還是和數(shù)據(jù)耦合到一起了要拂,如果后期修改需要修改代碼
    • 如果數(shù)據(jù)量大抠璃,及其不利于后期管理和數(shù)據(jù)的修改
    • 相比第一種有明顯的分離,是一種進(jìn)步
  • 第三種代碼和數(shù)據(jù)分離脱惰,放到外部文件中
    • 徹底代碼和數(shù)據(jù)分離搏嗡,耦合性低,易于擴(kuò)展
    • 數(shù)據(jù)放到文件中拉一、后期添加或者修改數(shù)據(jù)無需改動代碼彻况、更加獨(dú)立
    • 代碼更簡潔直觀,只需關(guān)注功能和布局
    • 適合企業(yè)開發(fā)舅踪、這是一種通用方式(網(wǎng)絡(luò)應(yīng)用更是如此)

plist文件介紹和使用

簡介

  • plist文件全稱:Property List文件纽甘,中文又叫屬性列表文件。
  • 是蘋果平臺上常用的一種資源描述類文件抽碌。
  • 它存儲的屬性一般都是Xcode里面的基本數(shù)據(jù)類型或者OC里面的對應(yīng)類型(NSDictionary悍赢,NSArray,NSString等)
  • Xcode會自動進(jìn)行解析成可以打開和合上的層疊格式
  • 用文本文件打開直接就是XML格式的鍵值對

plist文件的創(chuàng)建

plist的創(chuàng)建一般直接用Xcode創(chuàng)建货徙,然后在里面添加對應(yīng)的key和value左权,(幾乎沒有人會手寫plist文件)

3月-02-2017 15-05-43.gif

plist文件的使用

plist使用就和其他的文件用法一樣,先讀取目標(biāo)文件的路徑在根據(jù)路徑加載到數(shù)組中痴颊。


    // 獲取文件路徑
    NSString *books = [[NSBundle mainBundle] pathForResource:@"bookData" ofType:@"plist"];
    // 加載路徑中內(nèi)容放到數(shù)組中
    _books = [NSMutableArray arrayWithContentsOfFile:books];
    

plist使用注意

我們自己創(chuàng)建plist文件的時候不能使用info/Info.plist命名

由于每次創(chuàng)建工程的時候赏迟,系統(tǒng)會自動生成一個對該項(xiàng)目信息進(jìn)行描述的info.plist,它會記錄項(xiàng)目的一些包名蠢棱、項(xiàng)目名锌杀、開發(fā)工具甩栈、版本和其他項(xiàng)目的基礎(chǔ)信息。

所以我們自己創(chuàng)建plist文件的時候不能使用info/Info.plist

這是為了不和系統(tǒng)的info.plist混淆糕再,實(shí)際上自己創(chuàng)建一個info.plist文件和系統(tǒng)重名之后項(xiàng)目是運(yùn)行不了的量没。

懶加載(lazyLoad) -- 提升性能

懶加載又叫延遲加載,由于項(xiàng)目運(yùn)行時候很多數(shù)據(jù)用不到突想,可以暫時不創(chuàng)建殴蹄,等到用的時候在創(chuàng)建,這樣節(jié)省系統(tǒng)性能猾担。

如以上項(xiàng)目中袭灯,就是在添加書的方法中每次創(chuàng)建書籍?dāng)?shù)組

// 添加書
- (IBAction)addBook:(id)sender {

    self.books = @[
                       @{
                           @"icon":@"0",
                           @"name":@"book1"
                        },
                       
                       @{
                           @"icon":@"1",
                           @"name":@"book2"
                           },
                       @{
                           @"icon":@"2",
                           @"name":@"book3"
                           },
                       @{
                           @"icon":@"3",
                           @"name":@"book4"
                           },
                       ];

    // 設(shè)置列數(shù)為 3
    int clos = 3;
    
    // 設(shè)置書的寬高分別為 W H
    CGFloat W = 60;
    CGFloat H = 70;
    CGFloat iconH = 50;
    
    
    // 0. 創(chuàng)建書
    UIView *book = [UIView new];
    book.backgroundColor = [UIColor redColor];

這樣其實(shí)非常耗性能,每次都要創(chuàng)建一個數(shù)組绑嘹,然后用過一次就沒有用了稽荧,對此可以進(jìn)行一個優(yōu)化,對于該書籍?dāng)?shù)據(jù)其實(shí)就是一個固定數(shù)據(jù)圾叼,每次用一下蛤克,用的時候再創(chuàng)建捺癞,不用的時候就不管了夷蚊,這里正好用懶加載最好了。

懶加載實(shí)際上就是一個get方法


// 懶加載書籍?dāng)?shù)據(jù)
- (NSMutableArray *)books
{
    if (_books == nil) {
        
        // 獲取文件路徑
        NSString *books = [[NSBundle mainBundle] pathForResource:@"bookData" ofType:@"plist"];
    
        // 加載路徑中內(nèi)容放到數(shù)組中
        _books = [NSMutableArray arrayWithContentsOfFile:books];
        
    }
    return _books;
}


// 使用的時候髓介,直接用數(shù)組就行
bookIcon.image = [UIImage imageNamed:self.books[index][@"icon"]];
bookName.text = self.books[index][@"name"];

MVC 思想的介紹和引入

以上的小Demo惕鼓,已經(jīng)告一段落了,可以實(shí)現(xiàn)把文件中書籍?dāng)?shù)據(jù)唐础,按九宮格的布局添加到購物車中箱歧,也可以一一刪除。

思考

還有什么可以改進(jìn)的嗎一膨?
數(shù)據(jù)就這樣存放到數(shù)組中就完美了嗎呀邢?
每次用書的數(shù)據(jù)的時候,直接從數(shù)組總?cè)〕鰜泶_實(shí)方便豹绪,但是這樣真的足夠完美嗎价淌?
現(xiàn)在的所有代碼幾乎都在一個文件中,如果項(xiàng)目大了也這樣寫嗎瞒津?
上面把對應(yīng)的數(shù)據(jù)加載方式分離到文件中了蝉衣,其他的業(yè)務(wù)邏輯能不能也分離一下,能不能讓項(xiàng)目的結(jié)構(gòu)更加清晰巷蚪?

待著這些思考病毡,答案是肯定的,項(xiàng)目的代碼還是非常耦合的屁柏,并且有個致命的缺點(diǎn)啦膜。

  • 每次從數(shù)組中取書的信息時候都自己寫key值有送,self.books[index][@"icon"] 如果這個“icon“手誤寫錯,編輯器一點(diǎn)提示也沒有
  • 如果書有很多屬性功戚,每次手寫key值很頭痛娶眷,并且代碼看起來很糟

所以我們需要一種新的方式:因?yàn)闀且粋€對象,可以把它封裝成對象啸臀,它用有自己的各種屬性和方法届宠。這樣做有幾點(diǎn)好處:

  • 便于管理,在使用的時候直接調(diào)用屬性的get方法就行乘粒。
  • 系統(tǒng)會自動提示get方法豌注,安全性高不會出錯,如果寫錯系統(tǒng)會報錯灯萍。
  • 代碼封裝性好轧铁,書就是書,而不是每次到數(shù)組中去取字典根據(jù)對應(yīng)的key來取值
  • 擴(kuò)展性好旦棉,如果日后需要添加新的屬性和方法齿风,直接在”書“類中加就行

MVC介紹

經(jīng)過上面的分析,可以確定的是書應(yīng)該獨(dú)立封裝起來保存數(shù)據(jù)绑洛,頁面邏輯也應(yīng)該單獨(dú)管理救斑,至于ViewController恰好就是兩者的橋梁。這樣的設(shè)計(jì)模式就是MVC

  • M : (Model)數(shù)據(jù)模型真屯,用來存儲和保存數(shù)據(jù)
  • V : (View)UI視圖脸候,用來展示給用戶看的頁面,一些復(fù)雜的頁面要封裝起來放到里面單獨(dú)管理绑蔫。
  • C: (Controller)控制器运沦,是兩者的橋梁,主要用來處理業(yè)務(wù)邏輯配深。

使用MVC模式可以很好的簡化項(xiàng)目代碼携添,對不同的模塊進(jìn)行封裝,降低耦合性篓叶,擴(kuò)展性也會得到提高烈掠,MVC是企業(yè)開發(fā)常用的設(shè)計(jì)模式。

MVC的分層封裝和使用

經(jīng)過分析可知澜共,在此小項(xiàng)目中向叉,書和展示的書的UI和ViewController對應(yīng)MVC的關(guān)系:

  • 書 -- Model:用來封裝書的各種屬性信息和方法
  • 書UI -- View:封裝書這個小表象,用于展示給用戶看
  • ViewController -- Controller:用來處理整體的業(yè)務(wù)邏輯嗦董,優(yōu)化代碼



廢話不多說了母谎,上各層的代碼

  • 下面是書的代碼封裝:存儲書的數(shù)據(jù)和方法

頭文件 XYBook.h

@interface XYBook : NSObject

// 書圖標(biāo)
@property (nonatomic, copy) NSString *icon;
// 書名字
@property (nonatomic, copy) NSString *name;

// 對象方法,返回自己對象
- (instancetype)initWithDict:(NSDictionary *)dict;
// 類方法京革,返回自己對象
+ (instancetype)bookWithDict:(NSDictionary *)dict;
@end


#import "XYBook.h"

@implementation XYBook


- (instancetype)initWithDict:(NSDictionary *)dict
{
    if (self = [super init]) {
        [self setValuesForKeysWithDictionary:dict];
    }
    return self;
}

+ (instancetype)bookWithDict:(NSDictionary *)dict
{
    return [[self alloc] initWithDict:dict];
}
@end

  • 書的UI的封裝:集中布局奇唤,減少控制器代碼幸斥,優(yōu)化控制器邏輯

XYBookView.h 頭文件

#import <UIKit/UIKit.h>
@class XYBook;

@interface XYBookView : UIView

// 只放一個數(shù)據(jù)屬性用來賦值,內(nèi)部布局咬扇,放到.m 中自己管甲葬,不暴露給外界
@property (nonatomic, strong) XYBook *book;

@end


實(shí)現(xiàn)文件 .m文件
#import "XYBookView.h"
#include "XYBook.h"

@interface XYBookView ()

@property (nonatomic, weak) UIImageView *icon;

@property (nonatomic, weak) UILabel *label;

@end

@implementation XYBookView

- (instancetype)initWithFrame:(CGRect)frame
{
    if (self = [super initWithFrame:frame]) {
        
        // 1. 創(chuàng)建書圖標(biāo)
        UIImageView *icon = [UIImageView new];
        self.icon = icon;
        [self addSubview:self.icon];
        
        // 2.書名
        UILabel *bookName = [UILabel new];
        bookName.textAlignment = NSTextAlignmentCenter;
        self.label = bookName;
        [self addSubview:self.label];
        
    }
    return self;
}

// 重寫布局
- (void)layoutSubviews
{
    [super layoutSubviews];
    CGSize size = self.frame.size;
    self.icon.frame = CGRectMake(0, 0, size.width , size.height * 0.7);
    self.label.frame = CGRectMake(0, size.height * 0.7, size.width, size.height *(1 - 0.7));

}

// 設(shè)置書的屬性
- (void)setBook:(XYBook *)book
{
    _book = book;
    self.icon.image = [UIImage imageNamed:book.icon];
    self.label.text = book.name;
}
@end
  • 控制器:不管細(xì)節(jié),專注處理邏輯

// 懶加載數(shù)據(jù)源
- (NSMutableArray *)books
{
    if (_books == nil) {
        
        _books = [NSMutableArray array];
        
        // 獲取文件路徑
        NSString *books = [[NSBundle mainBundle] pathForResource:@"bookdata" ofType:@"plist"];
    
        // 加載路徑中內(nèi)容放到數(shù)組中
        NSMutableArray *arrayM = [NSMutableArray arrayWithContentsOfFile:books];
        
        for (NSDictionary *dict in arrayM) {
            
            XYBook *book = [XYBook bookWithDict:dict];
            
            [_books addObject:book];
        }
    }
    return _books;
}



// 添加書
- (IBAction)addBook:(id)sender {

    // 設(shè)置列數(shù)為 3
    int clos = 3;
    
    // 設(shè)置書的寬高分別為 W H
    CGFloat W = 60;
    CGFloat H = 70;
    
    // 0. 創(chuàng)建書
    XYBookView *bookView = [XYBookView new];
    bookView.backgroundColor = [UIColor redColor];
    
    
    // 計(jì)算書的位置
    // 獲得索引
    NSUInteger index = [self.shopView.subviews count];
    // 計(jì)算橫間距 margin
    CGFloat margin = (self.shopView.frame.size.width - clos * W) / (clos - 1);
    // 書 frame 的 X
    CGFloat x = (index % clos) * (W + margin);
    // 書 frame 的 Y
    CGFloat y = (index / clos) * (H + margin);
    
    bookView.frame = CGRectMake(x, y, W, H);
    [self.shopView addSubview:bookView];
    
    
    // 給書的UI設(shè)置數(shù)據(jù)
    bookView.book = self.books[index];

    
    [self checkState];
    self.removeBtn.enabled = YES;
}

// 移除書
- (IBAction)removeBook:(id)sender {
    
    
    [[self.shopView.subviews lastObject] removeFromSuperview];
    
    [self checkState];
    self.addBtn.enabled = YES;
}

以上就是對于本Demo的最終MVC封裝版
不同部分各司其職懈贺,負(fù)責(zé)自己的模塊
項(xiàng)目的健壯性和封裝性也也到了對應(yīng)的提高



小記

一個簡單的九宮格購物車的小Demo经窖,真是麻雀雖小五臟俱全。

關(guān)于這個項(xiàng)目的完整代碼梭灿,歡迎私聊或評論找我要画侣,如果文章有任何問題或有其他技術(shù)問題,歡迎隨時和我交流堡妒。

最后放一張項(xiàng)目效果圖

2017-03-02 17.47.23.gif

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末配乱,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子皮迟,更是在濱河造成了極大的恐慌搬泥,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,430評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件伏尼,死亡現(xiàn)場離奇詭異忿檩,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)烦粒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,406評論 3 398
  • 文/潘曉璐 我一進(jìn)店門休溶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來代赁,“玉大人扰她,你說我怎么就攤上這事“虐” “怎么了徒役?”我有些...
    開封第一講書人閱讀 167,834評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長窖壕。 經(jīng)常有香客問我忧勿,道長,這世上最難降的妖魔是什么瞻讽? 我笑而不...
    開封第一講書人閱讀 59,543評論 1 296
  • 正文 為了忘掉前任鸳吸,我火速辦了婚禮,結(jié)果婚禮上速勇,老公的妹妹穿的比我還像新娘晌砾。我一直安慰自己,他們只是感情好烦磁,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,547評論 6 397
  • 文/花漫 我一把揭開白布养匈。 她就那樣靜靜地躺著哼勇,像睡著了一般。 火紅的嫁衣襯著肌膚如雪呕乎。 梳的紋絲不亂的頭發(fā)上积担,一...
    開封第一講書人閱讀 52,196評論 1 308
  • 那天,我揣著相機(jī)與錄音猬仁,去河邊找鬼帝璧。 笑死,一個胖子當(dāng)著我的面吹牛湿刽,可吹牛的內(nèi)容都是我干的聋溜。 我是一名探鬼主播,決...
    沈念sama閱讀 40,776評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼叭爱,長吁一口氣:“原來是場噩夢啊……” “哼撮躁!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起买雾,我...
    開封第一講書人閱讀 39,671評論 0 276
  • 序言:老撾萬榮一對情侶失蹤把曼,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后漓穿,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體嗤军,經(jīng)...
    沈念sama閱讀 46,221評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,303評論 3 340
  • 正文 我和宋清朗相戀三年晃危,在試婚紗的時候發(fā)現(xiàn)自己被綠了叙赚。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,444評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡僚饭,死狀恐怖震叮,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情鳍鸵,我是刑警寧澤苇瓣,帶...
    沈念sama閱讀 36,134評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站偿乖,受9級特大地震影響击罪,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜贪薪,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,810評論 3 333
  • 文/蒙蒙 一媳禁、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧画切,春花似錦竣稽、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,285評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽光涂。三九已至苟跪,卻和暖如春棱貌,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背酿炸。 一陣腳步聲響...
    開封第一講書人閱讀 33,399評論 1 272
  • 我被黑心中介騙來泰國打工恋博, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留齐佳,地道東北人。 一個月前我還...
    沈念sama閱讀 48,837評論 3 376
  • 正文 我出身青樓债沮,卻偏偏與公主長得像炼吴,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子疫衩,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,455評論 2 359

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,275評論 25 707
  • 【0524今日話題】 你了解你的父母嗎闷煤? 比如:他們最想去的地方童芹,最愛吃的東西,最大的遺憾以及他們的專長等等鲤拿。 還...
    Mjinxiu無憂閱讀 328評論 0 0
  • 以前我以為喝酒泡吧滿身紋身假褪,飆車叛逆目光桀驁都是最酷的事。 可是長著長著近顷,發(fā)現(xiàn)這種只要你想做生音,人人都可...
    兔八哥的泡芙閱讀 417評論 0 0
  • 我是瘋了才如此
    動力額閱讀 109評論 0 0