iOS開發之有趣的UI —— 數據轉模型及MVC設計模式

本分享是iOS開發中有趣的UI模塊的相關內容技術點分享。如果您是一位已經有C基礎了的iOS愛好者,但還未接觸Objectiov C語言,您需要學習我之前分享的 iOS開發核心語言Objective C 系列
如果您是零基礎,建議您從我之前分享的iOS開發分分鐘搞定C語言 系列開始學習。另外將無償分享自己整理出來的大概400G iOS學習視頻及學習資料,都是乾貨哦!可以新浪微博私信➕關注 極客James,期待與您的共同學習和探討!!由於時間有限,每天在工作之餘整理的學習分享,難免有不足之處,也希望各路大神指正!

在上一篇iOS開發之有趣的UI —— 基礎控件與經典案例中已經對基本控件進行了詳細的介紹並且簡單的做了一個購物車的項目,但是這個項目還有待完善,裏面還有很多非常實用技術點和設計思想,所以本次分享將從以下幾個方面進行分享。

made by 極客James

這裏寫圖片描述

一、plist文件

1.在學習UI控件的時候要時刻掌握這三個基本要素:
(1)創建對象
(2)給對象設置屬性,大小,顏色,尺寸等
(3)給對象加數據
上面兩點在上一篇的分享中都已經做了詳細的分享,今天主要是對第三點給對象加數據進行分享。

2.數據存取
在iOS開發中通常數據存取有兩種方式:一種是本地數據,一種是網絡數據,本地數據是存取在plist中,而網絡數據是存儲在服務器需要通過json進行解析獲取,今天主要分享本地數據的存取。

3.plist數據
(1)創建一個plist文件

這裏寫圖片描述

(2)在plist中寫數據

這裏寫圖片描述

(3)將建好的的plist數據通過以下代碼導入到文件中

NSArray *dictArray =[NSArray arrayWithContentsOfFile:[[NSBundle mainBundle]pathForResource:@"shops" ofType:@"plist"]];
// 僅僅是加載plist文件的代碼塊

二、數據轉模型

通過自己創建一個plist文件進行了本地數據的存取才是第一步,要想讓對象拿到數據最好的辦法是將數據轉換成模型進行使用,這樣不僅效率高還不容易出錯。

數據轉模型思路:
1.建立一個主要來處理數據的模型文件
2.在創建好的模型文件.h中拿到plist裏面所有的元素,並且提供一種自定義對象方法,一種構造類方法來初始化字典。
3.在模型文件的.m中進行自定義對象方法和構造類方法的方法實現,主要目的是將字典裏面的數據取出來給模型,把數據封裝爲對象的方式供用戶使用。
4.在viewController文件中懶加載數據,並且將plist數據通過已構造好的方法進行轉化爲模型。
5.在需要用到的地方,直接用對象方法或者類方法進行調用。

數據轉模型代碼實現:
1.創建了模型文件ZJShopModel
2.在ZJShopModel.h文件中拿到plist中的元素並且自定義初始化

// 注意:plist中有多少個屬性,這裏就要寫多少個
// 商品名稱
@property (nonatomic,strong)NSString *name;
// 商品圖標
@property (nonatomic,strong)NSString *icon;

// 自定義對象方法的初始化
- (instancetype)initWithDict:(NSDictionary *)dict;

// 自定義構造類方法的初始化
+ (instancetype)shopWithDict:(NSDictionary *)dict;

3.在ZJShopModel.m文件中進行聲明的實現

// 自定義對象方法的實現
- (instancetype)initWithDict:(NSDictionary *)dict{
    if (self = [super init]) {
    // 可以通過KVC的方式直接賦值
   // KVC方法 [self setValuesForKeysWithDictionary:dict];
        self.name = dict[@"name"];
        self.icon = dict[@"icon"];
    }

    return self;
}

// 自定義構造類方法的實現
+ (instancetype)shopWithDict:(NSDictionary *)dict{
    return  [[self alloc] initWithDict:dict];
}

4.在viewController文件中進行數據的懶加載
(1)首先要聲明一個數組

@property (strong,nonatomic)NSArray *shop;

(2)對數組進行懶加載和plist數據的模型轉化需要導入模型頭文件

- (NSArray *)shop{
    if (_shop == nil) {
// 加載plist文件
 NSArray *dictArray =[NSArray arrayWithContentsOfFile:[[NSBundle mainBundle]pathForResource:@"shops" ofType:@"plist"]];
// 創建一個可變的空數組
NSMutableArray *shopArray = [NSMutableArray array];
// 遍歷字典
 for (NSDictionary *dict in dictArray) {
 // 取出字典內容給模型
 ZJShopModel *shop = [ZJShopModel shopWithDict:dict];
 // 將轉換好的數據賦給可變數組
 [shopArray addObject:shop];
        }
        _shop = shopArray;
    }
    return _shop;
}

5.在需要的地方進行調用

// 獲得index位置對應的商品數據
ZJShopModel *shops = self.shop[index];

以上是plist數據轉模型的最好方法,可以達到數據的獨立管理和方便調用,在iOS開發中非常重要。

三、抽取和封裝思想

在iOS開發中,封裝和抽取思想無處不在,掌握這種思想有利用高效開發,有利於團隊合作,有利於程序擴展,所以重要性我不在闡述,直接上代碼。

在編寫代碼的時候,總會遇到重複代碼的情況,那麼做好的辦法就是將相同的代碼進行抽取,然後在分析不同之處,用傳參數的方法來解決不同,下面就來以購物車爲例來分析抽取和封裝思想。

這裏寫圖片描述

分析:
1.增加按鈕需要的相關屬性:
(1)圖片顯示狀態:Normal Highlighted Disabled
(2)按鈕的位置
(3)點擊事件
2.刪除按鈕需要的相關屬性
(1)圖片顯示狀態:Normal Highlighted Disabled
(2)按鈕的位置
(3)點擊事件
3.顯示圖片和描述的相關屬性
(1)圖片
(2)文字
(3)位置
通過分析我們可以得出刪除按鈕和增加按鈕具有一樣的屬性,只不過屬性間的內容不同,所以我們要把他們公共擁有的屬性繼續抽取並給不同的屬性進行傳值操作。

刪除按鈕和增加按鈕的方法封裝:

//將增加和刪除按鈕相同共同屬性進行抽取和封裝 
- (UIButton *)addButtonWithImage:(NSString *)image hightImage:(NSString *)hightImage disableImage:(NSString *)disableImage frame:(CGRect)frame action:(SEL)action{

// 初始化創建按鈕對象
    UIButton *btn = [[UIButton alloc]init];
// 設置按鈕背景圖片 Normal狀態
     [btn setBackgroundImage:[UIImage imageNamed:image] forState:UIControlStateNormal];
// 設置按鈕背景圖片 Highlighted狀態  
    [btn setBackgroundImage:[UIImage imageNamed:hightImage] forState:UIControlStateHighlighted]; 
// 設置按鈕背景圖片 Disabled狀態
    [btn setBackgroundImage:[UIImage imageNamed:disableImage] forState:UIControlStateDisabled];
// 設置尺寸
    btn.frame = frame;
// 監聽按鈕點擊
    [btn addTarget:self action:action forControlEvents:UIControlEventTouchUpInside];
// 將按鈕增加到視圖上
    [self.view addSubview:btn];
    return btn;  
}

抽取和封裝了增加按鈕和刪除按鈕的方法,在用的時候直接調用即可。

- (void)viewDidLoad {
[super viewDidLoad];
// 增加按鈕
self.addBtn = [self addButtonWithImage:@"add" hightImage:@"add_highlighted"disableImage:@"add_disabled" frame:CGRectMake(30, 30, 50, 50) action:@selector(add)];

// 刪除按鈕
    self.removeBtn = [self addButtonWithImage:@"remove" hightImage:@"remove_highlighted"
disableImage:@"remove_disabled" frame:CGRectMake(270, 30, 50, 50) action:@selector(remove)];
}

四、自定義控件

顯示物品模塊的分析和封裝
物品的顯示模塊是一個九宮格顯示模式,有關九宮格顯示計算可以翻閱我的上一篇分享。那麼下面就來分享下顯示物品模塊的相關內容。

(1)shopView用來存放物品的視圖

這裏寫圖片描述



(2)在shopView上顯示的九宮格

這裏寫圖片描述


(3)在九宮格上添加數據
這裏寫圖片描述

以上就是購物車物品顯示模塊的完整過程,從中我們可以顯而易見的看出,每個格子大小寬度都一樣,就是內容不同而已,所以我們可以採用封裝的思想進行編碼。

代碼實現過程分析:
(1)通過九宮格算法先佈局好界面
(2)創建一個ZJshopView文件專門管理九宮格顯示的視圖內容
(3)在ZJshopView中創建一個九宮格顯示的UIImageView以及UILabel和相關屬性,最好是通過對象方法或類方法在創建的時候就讓它顯示,也就是要自定義View重寫init方法等。
(4)將plist轉換的模型數據導入到視圖中
(5)在需要的地方進行調用

代碼實現過程:
1.九宮格算法佈局界面

    // 設置每個商品的尺寸
    CGFloat shopW = 80;
    CGFloat shopH = 90;
    // 設置顯示的列數
    int cols = 3;
    // 設置每一列之間的間距
    CGFloat colMargin = (self.shopView.frame.size.width - cols * shopW) / (cols -1);
    // 設置每一行之間的間距
    CGFloat rowMargin = 10;
    // 創建一個父控件(用來存放圖片和文字)
    UIView *shopView = [[UIView alloc]init];
    shopView.backgroundColor = [UIColor redColor];
    // 商品的索引
    NSUInteger index = self.shopView.subviews.count;
    // 商品的x值(取餘運算,將算出商品在第幾列)
    NSUInteger col = index % cols;
    CGFloat shopX = col * (shopW + colMargin);
    // 商品的y值(除法運算,將算出商品在第幾行)
    NSUInteger row = index / cols;
    CGFloat shopY = row * (shopH + rowMargin);
    shopView.frame = CGRectMake(shopX, shopY, shopW, shopH);
    // 將九宮格添加到視圖上
    [self.shopView addSubview:shopView];

2.創建ZJshopView來專門管九宮格視圖內容
ZJshopView.h文件中

注意:在自定義初始化init方法之前系統會自動調用initWithFrame方法,所以爲了嚴謹起見最好自定義初始化initWithFrame,達到初始化時第一個就調用且只調用一次的效果。

@interface ZJshopView ()

@property (nonatomic,weak) UIImageView *iconView;
@property (nonatomic , weak)UILabel *label;

@end

@implementation ZJShopView

// 自定義view  初始化initWithFrame
- (instancetype)initWithFrame:(CGRect)frame{
    if (self = [super initWithFrame:frame]){

 UIImageView *iconView = [[UIImageView alloc]init];
 [self addSubview:iconView];

 // 添加文字
    UILabel *label = [[UILabel alloc]init];
    label.font = [UIFont systemFontOfSize:11];
    label.textAlignment = NSTextAlignmentCenter;
    [self addSubview:label];
    }
    return self;
}

3.設置九宮格里面顯示圖片和文字的位置
注意:在重寫layoutSubviews方法時一定要先調用父類也就是[super layoutSubviews];

- (void)layoutSubviews{

    [super layoutSubviews];
    CGFloat showH = self.frame.size.height;
    CGFloat showW = self.frame.size.width;

    self.iconView.frame = CGRectMake(0, 0, showW, showH);
    self.label.frame = CGRectMake(0, showW, showW, showH - showW);

}

4.模型數據導入到九宮格內容的視圖中
實現思路:
九宮格的視圖現在獨立在ZJshopView中,而數據我也已經通過數據轉模型的方式獨立到一個ZJShopModel文件中了,那麼現在要給視圖給數據,顯而易見就是要讓模型中的數據賦給視圖的相應位置中。要想讓數據模型的數據給視圖那麼就要用到set方法。

代碼實現過程:
(1)將ZJShopModel.h導入到ZJshopView.m中,然後在ZJshopView.h中拿到ZJShopModel中的屬性也就是要@class ZJShopModel;

(2)在ZJshopView.m中聲明視圖需要用到的屬性,並且賦給視圖所用到的屬性,兩個屬性名字最好相同

// 類擴展以下兩個對象
@property (nonatomic , weak)UILabel *label;
@property (nonatomic , weak)UIImageView *iconView;
// 將聲明的對象賦給視圖的中的對象
 self.iconView = iconView;
 self.label =label;

(3)重寫set方法:將模型中的數據賦給視圖中的屬性

- (void)setShop:(ZJShopModel *)shop{
    _shop = shop;
    self.iconView.image = [UIImage imageNamed:shop.icon];
    self.label.text = shop.name;
}

5.在需要的時候直接創建對象,在初始化的時候獲得所需要的所有屬性,達到封裝的目的,一切OK.

// 在適當的位置掉用以下方法就會創建九宮格的位置以及屬性
ZJShopModel *shopView = [[ZJShopModel alloc]init];

// 在適當的位置掉用以下方法就會將數據給九宮格中的視圖
shopView.shop = self.shop[index];

五、xib自定義控件

xib是一種輕量級UI可視化設計工具,適用場景爲在項目中需要將好多UI控件顯示到同一個視圖上或者相同的視圖具有同樣的屬性只是位置不同。

上面分析的購物車符合用xib方式來創建的應用場景,下面就來分析下如何採用xib的方式來實現純代碼實現的效果。

1.創建xib
這裏寫圖片描述


2.給xib命名爲ZJShopView
這裏寫圖片描述


3.創建ZJShopView工程文件並繼承UIView
這裏寫圖片描述

4.讓xib繼承ZJShopView,並且給xib設置視圖屬性

這裏寫圖片描述

5.將xib中的控件和ZJShopView建立關係

這裏寫圖片描述

6.在ZJShopView.h中導入數據模型通過set方法進行數據的傳遞

@class ZJShopmodel;
@interface ZJShopView : UIView

// 商品模型 
@property (nonatomic, strong) ZJShopmodel *shop;

+ (instancetype)shopViewWithShop:(ZJShopmodel *)shop;

7.在ZJShopView.m中進行xib視圖的加載和set方法實現

+ (instancetype)shopViewWithShop:(ZJShopmodel *)shop
{
// 加載xib
ZJShopView *shopView = [[[NSBundle mainBundle] loadNibNamed:NSStringFromClass(self) owner:nil options:nil] lastObject];
    shopView.shop = shop;
    return shopView;
}

set方法的實現

- (void)setShop:(ZJShopmodel *)shop
{
    _shop = shop;
    self.iconView.image = [UIImage imageNamed:shop.icon];
    self.nameLabel.text = shop.name;
}

通過xib的方法會很快捷的創建出九宮格顯示視圖的內容,不用在設置九宮格內容的尺寸等屬性。

六、MVC設計模式

以下是蘋果官方對MVC的定義和解釋

這裏寫圖片描述

翻譯:
對於任何 iOS 應用程序而言,模型-視圖-控制器 (MVC) 都是一個優秀設計的關鍵所在。MVC 會將應用程序中的對象分配給以下三種角色中的一種:模型、視圖或者控制器。在這種模式中,模型會記錄應用程序的數據,視圖會顯示用戶界面並構成應用程序的內容,而控制器則會管理您的視圖。通過響應用戶的操作並使用內容填充視圖,控制器充當了模型和視圖二者之間通信的通道。

通過官方的翻譯想必您已經領悟了其中的精髓所在,本篇分享中也同樣用到了MVC的設計模式和思想,例如本次分享的購物車案例。

M:ZJShopModel 數據模型
V:ZJShopView 視圖模型
C:viewController 大管家 視圖控制器

通過這種設計模式能夠很明顯的感受到開發效率的提升,分模塊進行編碼,然後通過視圖控制器來進行調度,有利於程序的擴展性和易讀性。

這裏寫圖片描述

在開發中也提倡通過MVC的設計模式去開發。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章