關於iOS的一些總結

來源:互聯網
上載者:User

標籤:

 

1??字典轉模型

 

一)有一個模型的情況

    1、看plist檔案的根節點是否是NSArray類型的;

    2、如果是:根據檔案中的字典元素,建立一個對應的模型類,類中的屬性就是字典中每一個key值,類型是索引值對應的類型(模型類的屬性一定要跟字典中的key值一致,否則使用KVC會出錯)。

    3、自訂一個類的init方法,該方法是對象方法,

eg:- (instancetype)initWithDict:(NSDictionary *)dict

    {

        if (self = [super init])

        {

            [self 調用KVC的方法];

        }

        return self;

    }

 

    定義一個類方法,用來把字典轉為模型對象

eg: + (instancetype)類名WithDict:(NSDictionary *)dict

    {

        return [[self alloc] initWithDict:dict];

    }

 

到此為止,模型對像建立成功。

 

 

☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆懶載入模式(重點,必須掌握)☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆

 

    1、在控制器中,建立一個屬性,類型為NSArray或者NSMutableArray類型的(視情況而定,如果在後面需要在該數組中增加模型對象,就建立可變的數組,如果不需要往數組中增加模型,就建立不可變數組),用來存放模型資料。(下文中稱該數組為【資料數組】)

    2、用懶載入的方式載入資料

            載入資料的實質就是,重寫資料數組的getter方法,getter方法中寫的內容就是:

            ①先判斷資料數組中是否有資料,如果沒有資料就載入資料,如果有資料就不用載入資料,直接返回資料數組。

            ②載入資料的過程:

                i)先載入plist檔案,用一個數組 【NSArray *dictArray】 接收載入完成plist檔案返回的資料(為甚麼用數組接收?因為plist檔案的根節點是數群組類型的);此時dictArray數組中存放的對象是字典對象。

 

                ii)用for-in迴圈遍曆【dictArray】遍曆到的對象是一個個的字典,此時在迴圈中用建立的【字典模型類】把字典轉換為模型對象;

 

                iii)字典轉換後的模型對象需要用一個可變數組來儲存,這時候再拐回頭來建立一個可變數組【NSMutableArray *ModelArray】,然後再for-in迴圈中把轉變後的模型添加到可變數組【modelArray】中。(不需要一開始就建立可變數組,當你需要的時候,發現沒有一個可以使用的可變數組,才去建立可變數組,這就是我給說的需要什麼再去建立什麼的思想,不要跟著老師的代碼從頭寫到尾,那樣沒有自己的思想在程式中,這個程式就不是你的)。

 

                iiii)把【ModelArray】賦值給【資料數組】

 

                iiiii)返回【資料數組】

 

懶載入資料執行個體程式:

- (NSArray *)modelArray

{

    if (_modelArray == nil)

    {

        NSArray *dictArray =  [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:fileName ofType:nil]];

        NSMutableArray *modelArray = [NSMutableArray array];

        

        for (NSDictionary *dict in dictArray)

        {

            模型類 *model = [模型類 模型類WithDict:dict];

            [modelArray addObject:model];

        }

        _modelArray = modelArray

    }

    return _modelArray;

}

 

 

 

 

二)有兩個模型的情況(plist檔案中一個字典中嵌套字典的情況)【可以查看第六天汽車展示模型嵌套】

    【注意】遇到這樣的情況,不要慌張,這個更加簡單。一步一步來就能輕鬆搞定它。

            1、首先先查看嵌套在最裡面的字典,然後根據一個模型的情況,建立一個類來描述最裡面的字典對象,這裡暫且稱這個嵌套最裡面的模型稱為【小模型】;

            2、然後同樣的道理,根據一個模型的方式,再建立一個模型,類型跟外層字典的索引值的類型一致,這裡就稱外層模型為【大模型】;

            3、到此為止,嵌套的兩個模型建立成功了,簡單吧。

            4【注意】,在建立模型的時候,一定要從【小模型】開始建立,因為在【大模型】中要用到【小模型】,還需要【注意】的一點就是,【小模型】所描述的字典需要在【大模型】的初始化方法中轉換為【小模型】

 

具體請看以下【樣本程式】:

【小模型】

聲明檔案

#import <Foundation/Foundation.h>

 

@interface LXLCarsModel : NSObject

@property (nonatomic, copy) NSString *name;

@property (nonatomic, copy) NSString *icon;

 

- (instancetype)initWithDict:(NSDictionary *)dict;

+ (instancetype)carModelWithDict:(NSDictionary *)dict;

 

@end

 

實現檔案

#import "LXLCarsModel.h"

 

@implementation LXLCarsModel

- (instancetype)initWithDict:(NSDictionary *)dict {

    if (self = [super init]) {

        [self setValuesForKeysWithDictionary:dict];

    }

    return self;

}

 

+ (instancetype)carModelWithDict:(NSDictionary *)dict {

    return [[self alloc] initWithDict:dict];

}

@end

 

【大模型】

聲明檔案

#import <Foundation/Foundation.h>

#import "LXLCarsModel.h"

 

@interface LXLGroupsModel : NSObject

@property (nonatomic, strong) NSArray *cars;

@property (nonatomic, copy) NSString *title;

 

- (instancetype)initWithDict:(NSDictionary *)dict;

+ (instancetype)groupWithDict:(NSDictionary *)dict;

@end

 

實現檔案

#import "LXLGroupsModel.h"

 

@implementation LXLGroupsModel

- (instancetype)initWithDict:(NSDictionary *)dict {

    if (self = [super init]) {

        [self setValuesForKeysWithDictionary:dict];

        

        NSMutableArray *cars = [NSMutableArray array];

        for (NSDictionary *dict in self.cars) {

            LXLCarsModel *car = [LXLCarsModel carModelWithDict:dict];

            [cars addObject:car];

        }

        self.cars = cars;

        

    }

    return self;

}

 

+ (instancetype)groupWithDict:(NSDictionary *)dict {

    return [[self alloc] initWithDict:dict];

}

@end

 

【注意】【注意】【注意】(重要的事情說三遍??)注意理解大模型中初始化方法的寫法,【為什麼要這樣寫?】【因為在控制器中不會去直接使用小模型,他使用的是大模型,如果需要使用小模型也是使用大模型間接的去使用,(這就是我給你說過的誰的事情誰去做,或者讓誰去做)】

 

請再觀察以下此時的懶載入的寫法:

 

- (NSArray *)groupArray {

    if (_groupArray == nil) {

        NSArray *array = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"cars_total.plist" ofType:nil]];

        

        NSMutableArray *tempArray = [NSMutableArray array];

        for (NSDictionary *dict in array) {

            LXLGroupsModel *group = [LXLGroupsModel groupWithDict:dict];

            [tempArray addObject:group];

        }

        _groupArray = tempArray;

        

    }

    return _groupArray;

}

 

可以發現懶載入的寫法和一個模型的懶載入的寫法完全的一樣,【為什麼會這樣?因為小模型在大模型中被處理了,根本不需要外界再對它進行處理,也是說內層嵌套的那個字典在大模型內部初始化的時候就自動轉換為模型了,外界懶載入的時候只需要把大模型對應的字典轉換為大模型就可以了】。

 

 

 

關於字典轉模型和懶載入的討論,到此就可以告一段落了,如果有說錯的或者可以補充的歡迎批評指正。

 

 

 

2??代理模式

    代理存在的條件,①被代理的對象②代理對象③被代理對象規定的協議

 

    被代理對象做的三件事:①規定協議

                      ②包含一個代理屬性(需要是id類型的,並且遵循代理協議)

                      ③有一個事件可以觸發協議中的代理事件(就是在一個方法中調用代理屬性的代理方法)

 

    代理對象做的三件事:①遵循協議

                     ②設定代理對象

                    ③實現協議中 的方法

 

【注意】以上如果有說的不正確的地方,趕緊指正

 

 

我們學過的內容中用到代理的地方有:①UIScrollView

                            ②UITableView

                            ③UIAlertview

                            ④UITextfiled

                        【我暫時就想起來這四個,如果還有就給我說說,共同學習】

 

補充:一般在控制器中都會把代理對象設定為控制器本身,也是就self,

例如:self.tableView.delegate = self;

        這句話的意思就是:設定當前控制器中tableview控制項的代理對象是當前的控制器(self)

 

還要補充一點(不要說我囉嗦):在寫協議的時候,一般要把被代理對象當做一個參數傳入,如果方法還需要其他的參數,就再方法的後面繼續聲明參數。【不要問我為甚麼非要把被代理對象當做參數,因為這是規範,蘋果官方就是這樣寫的,你可以回憶一下你所實現的所有的代理方法,都有把被代理對象作為參數的情況。】【雖然我不想給你說為什麼,但是我還是忍不住想給你說說我的理解,因為這樣可以在需要的時候調用被代理對象的方法,或者可以拿到被代理對象的屬性】。

 

 

 

 

【最後補充一點】,在什麼時候我們需要用到代理去做事情?當在自己的類中很難去實現一件事情,或者說可以實現的事情不是當前類的【職責】範圍內,這時候就可以使用代理,至於選擇誰去做我的代理,這個時候就需要考慮,誰來做這件事請比較方便,或者說這件事是誰的【職責】所在,這時候就可以找它來做代理,這時候就需要在自己類中聲明協議,增加代理屬性即可。

 

 

【請原諒我的囉嗦吧,我還要再補充一點】再聲明協議的時候,協議名一般是【類名後跟上delegate】的形式,

聲明的代理屬性是@property (nonatomic, weak) id<遵循的協議> delegate;

 

【注意】【注意】【注意】【重要的事情說三遍??】 delegate屬性一定要用【weak】來修飾,不能用【strong】,否則會引起循環參考的問題。

 

 

【最後再說一點,真的是最後一點】 代理一般是一對一的關係,而後面需要討論的通知是多對多的關係。

 

 

好了,說道這裡關於代理模式的淺淺討論就到此結束吧,是不是有種想踢死我的衝動。

 

如果有說錯的或者說說的不合適的地方,歡迎批評指正,如果有需要補充的地方,也希望能夠指出來,我們共同來學習。

 

 

 

3?? 關於UItableView的資料來源的簡單討論

    1、想要控制器成為tableview的資料來源,要先讓控制器遵循tableview 的資料來源協議

        <UITableViewDataSource>

        然後在- (void)viewDidLoad方法中設定tableview的資料來源:self.tableView.dataSource = self;

        (當然也可以使用脫線的方法設定資料來源,也可以設定代理,在這裡不再贅述)。

    2、是時候實現資料來源協議中的方法來為tableview設定資料了。必須實現的方法有:

@required

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;

 

// Row display. Implementers should *always* try to reuse cells by setting each cell‘s reuseIdentifier and querying for available reusable cells with dequeueReusableCellWithIdentifier:

// Cell gets various attributes set automatically based on table (separators) and data source (accessory views, editing controls)

 

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;

可選實現的方法比較多,目前我們用到的就是:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView;              // Default is 1 if not implemented

 

 

tableview的資料設定非常簡單,只要按照正確的文法和操作,就能程成功讓tableview顯示你所要想顯示的資料。

 

其他 的一些屬性的設定,在這裡就不再贅述了,如果有遺忘的話,可以翻閱老師的代碼,或者自己查閱相關的資料。

 

 

【我再囉嗦一句】//實現設定行高的代理方法

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath

{

    

    LXLQQChatCellFrameModel *QQChatCellFrameModel = self.frameArray[indexPath.row];

    

    return QQChatCellFrameModel.rowHeight;

}

以上的代理方法,是設定tableview的行高的,想要實現這個方法,就需要讓控制器遵循<UITableViewDelegate>的代理協議,我在這裡還想說一句,就是<UITableViewDelegate>協議遵循了<UIScrollViewDelegate>協議,想要實現一些tableview的拖拽方法,就需要去<UIScrollViewDelegate>協議中查詢。

 

 

【最後再補充一點】為每行增加cell的時候需要用到cell的重用方法。不太好描述,直接上代碼

 

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    static NSString *ID = @"tg";

    

    LXLTgCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];

    if (cell == nil) {

        cell = [LXLTgCell getCell];

    }

    

    //    獲得一個模型

    LXLTgsModel *model = self.modelArray[indexPath.row];

    

    cell.model = model;

    return cell;

    

}

 

①首先聲明一個重用的標誌,他時靜態類型的,目的是為了不重複為這個變數分配記憶體,延長了該變數的聲明周期。【為什麼要這麼做?因為以上方法為被重複調用很多次,不需要每次都為聲明的重用標誌分配記憶體】

②調用[tableView dequeueReusableCellWithIdentifier:ID]方法,去重用緩衝池中查看手否有可以重用的cell,如果有就返回,沒有就返回nil;

③判斷cell是否為空白,如果為空白就重新初始化一個cell;

④為cell中的各個控制項賦值

⑤返回cell

 

為cell設定值的五部曲就此誕生了??

 

 

 

到這裡,關於UITableView的資料來源的一些簡單討論就到此結束了。

還是那句話,如果說的不合適或者不對的地方,請批評指正,有需要補充的地方也非常歡迎提出,共同學習。

 

 

 

4??關於自訂cell的簡單討論

   這部分的關於自訂cell的討論,是我覺得最有意思的一部分了,也是老師所謂的最難的一部分了,我覺得這部分只要掌握了方法,其實他還是很簡單的。為什麼說自訂cell很有意思呢,因為我們可以根據我們的需要想讓cell中顯示什麼內容就顯示什麼內容。   好了,不裝逼了,請原諒我吧。接下來我們進入正題。

 

一)通過xib檔案自訂cell

    當cell的樣式是固定的,但是系統提供的無法滿足我們的要求的時候,我們就可以選擇通過xib的方法自訂cell。

 

    步驟:1、建立一個空得xib檔案,然後拖入一個UITableViewCell控制項;

         2、根據需求在UITableViewCell中拖入需要得控制項,然後設定相關的屬性即可;在這裡需要著重強調設定cell的重用標誌。

         3、建立一個類來描述我們剛才建立的UITableViewCell,【注意】建立的類需要繼承UITableViewCell這個類

         4、讓描述類和剛才自訂的cell相關聯,怎麼讓他們關聯在一起?【在xib檔案中選中UITableViewCell,然後在屬性檢測器視窗中把class修改為剛才建立的UITableViewCell的描述類即可】

         5、在描述類中增加一個模型對象的屬性,然後重寫模型對象的setter方法,在setter方法中為自訂的cell中的各個控制項進行賦值。

         6、如果能力可以達到的話,就把獲得自訂cell的步驟直接封裝在與描述類同名的類方法中,看代碼

+ (instancetype)getCell {

    //    載入自訂的xib檔案,並且返回

    LXLTgCell *cell = [[[NSBundle mainBundle] loadNibNamed:@"LXLTgCell" owner:nil options:nil] lastObject];

    return cell;

}

         7、然後就是簡單的為tableview設定資料來源和實現資料來源協議的幾個簡單的方法了。詳情 請看以上關於UITableView的資料來源的討論一節

 

 

關於通過xib檔案自訂cell的方法,就暫時討論到這裡了,如果有需要補充和指正的請指出,我們共同學習。

 

 

二)通過純手寫代碼的方式自訂cell

    使用純程式碼方法自訂cell的情況就是,UITableView中的每個cell顯示的資料可能不統一,這是就需要用純程式碼的方式來自訂cell了。

 

    關於用純程式碼的方法實現自訂的cell的方法,其實也很簡單,跟用xib實現自訂cell的區別就是,xib使用拖控制項的方式來布局自訂的cell的,而純程式碼的方式是用代碼的方式來布局自訂的cell的。思路都是一樣的。

 

    1、用純程式碼方式實現自訂的cell最少要有兩個模型。①資料模型②frame模型

            i)資料模型使用來把字典轉換為模型的,這就是簡單的字典轉模型。

            ii)frame模型就是為自訂的cell中自訂的控制項設定frame的,還有獲得行高的。

    2、還需要建立一個類,讓這個類來繼承UITableViewCell,這個類所描述的就是我們要自訂的cell。

        在類中要重寫UITableViewCell的 - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier的方法,具體重寫init方法的寫法我就不再這裡贅述了,我想說的是,我們初始化這個方法的目的是做什麼的。目的①建立我們自訂的cell中可能會出現的所有的控制項,並設定一些可以一次性設定的屬性;②把我們建立的控制項添加到self.contentView中。這兩個目的就是相當於在xib檔案拖控制項一樣,只是在這裡我們是用代碼“拖”而已。

 

【注意】【接下來我們要先屢清楚四個對象之間的關係】哪四個對象呢?

        ①資料模型   ②frame模型    ③自訂的cell類  ④控制器

 

        從左至右開始說,①資料模型最苦逼,他誰也管不了,只有一個作用,那就是把字典轉換為一個模型;

        ②接下來是frame模型,他就比資料模型牛逼,因為在它的內部會引用一個資料模型,【只要引用一個模型就要重寫模型這個屬性的setter方法】。那麼在frame模型中我們都需要做什麼事情呢,首先我們要聲明一個資料模型的屬性,因為我們需要資料模型中的資料;然後我們要聲明跟控制項數量一樣多得CGRect類型的屬性,因為我們要計算各個控制項的frame,儲存在對應的屬性中,最後要複製給相對應的控制項的frame。

            最後要聲明一個CGFloat類型的屬性,這個用來記錄cell的行高。【注意】,我們在外部是不允許隨便修改控制項的frame的,所以,在frame模型中,除了那個資料模型的屬性外,其他的屬性都要聲明為readonly。

            最後再frame中做的事情就非常簡單了,就是在資料模型的setter方法中分別計算相應控制項的frame,並且記錄;

 

        ③自訂cell類就更加的牛逼了,他可以直接或者間接的訪問frame模型和資料模型。

            在自訂的cell類中,同樣也需要引入一個frame模型類型的屬性,並且需要重寫他得setter方法。

            那麼重寫setter方法中需要做什麼事情呢?

            i)為cell中定義的控制項進行frame值的設定;

            ii)為cell中定義的控制項進行賦值;

        最後我不得不重申一遍,一定要重寫- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier這個方法。

 

        ④最後終於到壓軸的出場了,那就是控制器,他控制了各種邏輯的實現,包括懶載入資料、作為tableview的資料來源、作為tableview的代理等等,所有他是整個程式的控制者。

 

 

        所以通過觀察以上的分析步驟,所有的東西都很簡單,只要一步一步來,所有的東西都可以變的很簡單。

 

 

 

好吧,太困了,明天還要上課,那關於自訂cell就暫時討論到這吧,如果有說錯和需要補充的還希望能夠指正出來,我們共同學習。

 

關於iOS的一些總結

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.