淺談 : iOS工程中哪些需要建立基類(MVC)

weixin_34082695發表於2016-07-15
什麼是基類

首先我們來看一下基類的定義:通過繼承機制,能夠利用已有的資料型別來定義新的資料型別。所定義的新的資料型別不僅擁有新定義的成員,並且還同一時候擁有舊的成員。

基類的好處

首先在程式碼上面肯定是減少了程式碼量, 讓程式瘦身,其次能夠使程式碼的邏輯更加清晰等。不過,切記基類不能濫用,否則需求改變, 就可能面臨程式的很多地方都需要修改。個人覺得建立基類的原則之一應該有: 確定了這個程式碼肯定肯定不會隨著需求的改變而改變或者改動非常小。事實上,有時候在專案的功能已經實現了之後,再來進行很多程式碼的整理也是個不錯的選擇,這樣也能夠提升自己的經驗。貌似這就會涉及到重構的理念了。

哪些需要建立基類

以下我將列舉基本每個專案都需要建立的基類,可能不夠全面,希望您能給予補充。

一、Controller

1. UITabBarController

a.設定tabBar樣式;
b.初始化tabBarController控制的 controllers;
c.簽訂UITabBarControllerDelegate,實現協議方法,例如在使用者第二次點選tabItem的時候,需要重新整理介面的情況。
d.註冊tabItem切換時候的訊息等

- (void)initControllers
{
    NSArray *tabControllerNames = @[@"HomePageViewController",
                                    @"SearchViewController",
                                    @"UserViewController"];
    NSMutableArray *tabControllers = @[].mutableCopy;
    [tabControllerNames enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        NSString *controllerName = obj;
        Class class = NSClassFromString(controllerName);
        if (class) {
            [tabControllers addObject:[class new]];
        }
    }];
    self.viewControllers = tabControllers;
}
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController
{ 
   if ([viewController isKindOfClass:[RefreshViewController class]]) {
             RefreshViewController *contrller = (RefreshViewController *)viewController;
            [contrller startRefresh];
           }
       return YES;
}
2. UINavigationController

a.設定navigationBar樣式;
如果我們在整個工程中建立的是多個UINavigationController, 那麼在自定義的tabBar中, 就會初始化多個UINavigationController。 如果我們把設定樣式寫在了自定義的NC的viewDidLoad 裡面, 雖然我們設定的樣式是一樣的, 卻會走這個方法好幾次, 所以, 建議大家在NC中使用+ (void)initialize 這個類方法, 在這個方法裡面訂製樣式。這個類方法在整個app 的執行中, 不管你呼叫當前這個類多少次, 都會只走一次, 能夠提高程式的效率。appearanceWhenContainedIn這個方法裡面的class就是指定你想統一樣式的那些類。但是需要注意的是 , 如果你建立了ABNavigationController這個的子類, 那麼這個initialize方法就會走多次。 所以 記得進行判斷:

+ (void)initialize {
if (self == [ABNavigationController class]) {
    UINavigationBar *bar = [UINavigationBar appearanceWhenContainedIn:[ABNavigationController class], nil];
    
    [bar setBackgroundImage:[UIImage imageNamed:@"1"] forBarMetrics:UIBarMetricsDefault];
    [bar setTitleTextAttributes:@{NSFontAttributeName : [UIFont systemFontOfSize:20],
                                  NSForegroundColorAttributeName : [UIColor greenColor]}];
   }
}

如果在專案中有遇到不同的樣式, 那麼可以在初始化UINavigationController的地方判斷。例如我的ABAreaViewController不想用上面那種樣式, 就可以像下面這樣寫了。

   // 獲取nv
    UINavigationController *nv = [[ABNavigationController alloc] initWithRootViewController:vc];
    
    if ([vc isKindOfClass:[ABSpecialViewController class]]) {
        
        nv = [[UINavigationController alloc] initWithRootViewController:vc];
        return nv;
    }

b. 設定返回手勢

- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
        self.interactivePopGestureRecognizer.enabled = YES;
    }
    NSLog(@"%@ did show", [viewController.class description]);
}
3. UIViewController

a. 介面的背景色;
b. 訊息提示的方法: 載入成功\失敗,提交成功\失敗,網路異常等
c. push controller的封裝等

4. 需要重新整理|資料請求的UIViewController

這個需要繼承?的UIViewController,顧名思義, 需要在這裡面寫新增addRefresh\startRefresh等。

5. 帶有tableView/collectionView佈局的

這個需要繼承? 。可以先通過懶載入或者一個方法初始化了tableView/collectionView,設定了基本引數和實現了基本的協議方法。子類作修改的時候只要重寫父類的方法就可以了。建立基類的時候 如果是tableview的style或者collectionview的flowlayout這種 可以寫一個方法 返回tableview 或者是返回flowlayout, 像下面這種:

- (UIScrollView *)refreshScrollView
{
    UITableView *tableView = [self tableView];
    tableView.delegate = self;
    tableView.dataSource = self;
    tableView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
    [tableView registerClass:[self tableViewCellClass] forCellReuseIdentifier:@"cell"];
    return tableView;
}

- (UITableView *)tableView
{
    return [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
}

- (Class)tableViewCellClass
{
    return [UITableViewCell class];
}

不過對於collectionView的flowLayout, 可以通過重寫它的UICollectionViewDelegateFlowLayout的方法來設定引數,這個就依照個人喜好吧。但是切記:如果重寫了協議方法,那麼直接通過flowLayout.itemSize等這樣來設定的引數就會失效了。同tableview

在controller裡面的某些邏輯,我這裡可能不全面,可以借鑑這裡

二、UIView

1. UITableViewCell/UICollectionViewCell

a. 寫一個傳值的方法,子類繼承的時候, 直接實現傳值的方法就好。

- (void)configureWithItem:(id)item;

b. 不同的頁面可能會重複的利用一種cell 或者變化甚微, 這個時候,就再建立第二個基類, 可以將控制元件暴露在.h檔案中,如果是傳值的話, 就在.m中重寫父類方法;更改frame的話, 可以在layoutSubviews裡面更改,別忘了[super layoutSubviews ]

2. 自定義的檢視

對於tableView/collectionView頭檢視、輪播圖、時間選擇器等, 需要自定義的檢視, 需要傳值的, 可以像cell一樣,至少先寫一個傳值的方法備著。其他的視情況而定。還有帶有tableView/collectionView佈局的,也可以先實現協議方法,等待子類重寫。

3. 系統控制元件

對於label\button等, 做夜間模式的話,需要寫基類。如果你想程式碼更加簡潔,不妨向下面一樣,把原有方法再封裝一下,使用起來更簡單。

- (void)setNormalImage:(UIImage *)image
{
    [self setImage:image forState:UIControlStateNormal];
}
[button setNormalImage:ImageNamed(@"icon_back")];

三、NSObject

1. API

除了某些引數不同之外, 其他需要提供給伺服器的引數很多都一致,
POST請求的話, 設定字典的引數;GET請求的話,設定拼接的字串。在API基類裡面寫資料請求的方法, 快取, 清理快取的方法。

2. model類

資料解析的時候,如果需要建立model類,這個時候, 如果剛好有些屬性以及容錯方法都是重複率比較高的,這個時候也可以建立一個基類。但是最好確定每個model都有這個屬性再建立基類,否則我建議就寫容錯方法吧。借鑑這裡

琪一可原創

相關文章