從零開始搭建iOS項目框架

APP項目搭建

上周個人剛搭建完的項目框架,在這分享一下,主要還是采用MVC設計模式,沒有使用storyboard,純代碼搭的界面。

1.新建工程

1.1 新建項目

刪除文件
  • 刪除無用的文件(Main.storyboard,ViewController)
  • 刪除plist文件中Main storyboard file base name一項
  • appdelegate進行修改
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
     self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    self.window.backgroundColor = [UIColor whiteColor];
    

    [self.window makeKeyAndVisible];

}

1.2 創建不同的target管理工程

有時候我們需要多個版本,開發版、測試版或者線上版,或因渠道不同需要區分企業版,AppStore版等。這個時候使用target來管理就比較方便

1.2.1 生成

多target生成

1.2.2 修改名字

需要修改下名字target、scheme、info.plist三項的名字,主要用來區分下版本

注意:修改了info.plist名字需要修改新建的target的配置信息文件,讓其能找到info.plist文件

1.2.3 修改下工程配置文件


就可以這樣使用了:

#if DEVELOPMENT
    NSLog(@"development");
#else
    NSLog(@"release");
#endif

使用方法可參考:多個Target管理

1.3 導入CocoaPods管理依賴庫

自從CocoaPods升級到1.0.1之后,為多個target導入依賴庫,之前的link_with語法不能用了,使用如下方法:

source 'https://github.com/CocoaPods/Specs.git'
platform :ios, ‘7.0’

# ruby語法
# target數組 如果有新的target直接加入該數組
targetsArray = [‘MyApp’, ‘MyAppTest’]
# 循環
targetsArray.each do |t|
    target t do
        pod 'MJRefresh', '~> 3.1.12'
        pod 'Masonry', '~> 0.6.1'
        pod 'AFNetworking', '~> 3.1.0'
        pod 'MJExtension'
        pod 'MBProgressHUD'
        pod 'SDWebImage'



    end
end

使用方法可參考:CocoaPods安裝教程

1.4 info.plist配置

1.4.1 開啟http的訪問權限

info.plist 中添加以下


http訪問

1.4.2 添加應用白名單

iOS9之后分享等必須添加白名單后才可以打開相關應用。字段值為LSApplicationQueriesSchemes


應用白名單
應用白名單

1.4.3 其他

設置分享到微信、微博啊等URL Types

2.項目模塊化

2.1 分類各模塊

分類具體按照業務需求去歸類,開發前把大體的分類號,主體的文件夾建立真實的文件夾,再把真實的文件夾拖到項目中,這樣的好處是,避免了在項目中創建虛擬文件夾,然后導致各類文件都放在一塊,不方便查找。
大致分類:

項目目錄

2.2 導入需要用的第三方庫

先使用CocoaPods導入項目中一些常用的第三方庫,后續再根據需求導入,有些無法用CocoaPods導入的或者是一些需要修改庫中代碼的拖入到工程中Vender文件夾中

2.3 創建pch文件

這個文件用來包含全局使用的頭文件,例如:
1.第三方頭文件
2.全局宏定義
3.自定義的頭文件包含主題、網絡請求地址、全局方法、key等

使用方法參考: Pch 文件的正確使用

3 全局的宏定義

具體方法大家可下載demo看下

宏定義

3.1 全局配置參數DefineMacro

全局宏定義包含一些屏幕寬高、iOS版本、手機類型等

#define SCREEN_WIDTH   [UIScreen mainScreen].bounds.size.width
#define SCREENH_HEIGHT [UIScreen mainScreen].bounds.size.height
//隨機顏色
#define KRandomColor [UIColor colorWithRed:arc4random_uniform(256)/255.0 green:arc4random_uniform(256)/255.0 blue:arc4random_uniform(256)/255.0 alpha:1.0]

3.2 樣式定義DefineTheme

主要包含樣式上的定義,主題顏色、各類字體大小顏色、控件大小等

//顏色
#define TITLE_COLOR [UIColor blackColor]//標題顏色
#define TEXT_COLOR [UIColor grayColor]//正文顏色
#define TIPTEXT_COLOR UIColorFromRGB(0x888888)//提示語文本顏色
#define MAIN_GROUNDCOLOR UIColorFromRGB(0xF98B1B)//主題景色
#define BACKGROUNDCOLOR UIColorFromRGB(0xF7F7F7)//背景顏色
//字體大小
#define TITLEFONT [UIFont systemFontOfSize:18]
#define TEXTFONT [UIFont systemFontOfSize:16]
#define TIPTEXTFONT [UIFont systemFontOfSize:12]

3.3 API地址DefineRequest

訪問的地址,各個接口的查詢

#if DEVELOPMENT //***************開發版本*************
//****************測試環境***********
//app服務重構測試
//#define BaseURLString   @"http://www-test.baidu.com/rest/post"http://beta
//#define BaseURLString @"http://docker-branch02-web-tomcat.baidu.com:8080/rest/post"http://分之域名
//****************開發環境(個人服務器)************
//后臺XXX
#define BaseURLString  @"http://192.168.1.175:8080/baidu/rest/post"
#else          //**************生產版本**************
#define BaseURLString @"https://www.baidu.com/rest/post"
#endif

//****************接口說明************
//獲取用戶信息
#define Request_type_getUserInfo @"getUserInfo"
//首頁廣告
#define Request_type_queryBannerByType @"queryBannerByType"

4. 初期代碼編寫

公共類

4.1 Category

4.1.1 Method swizzling

為Controller添加一些方法,即可省略繼承baseViewController的麻煩,還可以對各工廠類進行操作

#import "UIViewController+swizzling.h"
#import <objc/runtime.h>

@implementation UIViewController (swizzling)

+ (void)load {
    Method fromMethod = class_getInstanceMethod([self class], @selector(viewDidLoad));
    Method toMethod = class_getInstanceMethod([self class], @selector(swizzlingViewDidLoad));
  
    if (!class_addMethod([self class], @selector(swizzlingViewDidLoad), method_getImplementation(toMethod), method_getTypeEncoding(toMethod))) {
        method_exchangeImplementations(fromMethod, toMethod);
    }
}

// 我們自己實現的方法,也就是和self的viewDidLoad方法進行交換的方法。
- (void)swizzlingViewDidLoad {
    NSString *str = [NSString stringWithFormat:@"%@", self.class];
    if(![str containsString:@"UI"]){
        NSLog(@"統計打點 : %@", self.title);
    }
    [self swizzlingViewDidLoad];
}
@end

4.1.2 appDelegate添加category

用以簡化appDelegate中代碼

AppDelegate+ViewController.h
- (void)setAppWindows
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    self.window.backgroundColor = [UIColor whiteColor];
    
    [[UINavigationBar appearance] setTitleTextAttributes:@{NSForegroundColorAttributeName: [UIColor whiteColor]}];
    
    [self.window makeKeyAndVisible];

}

- (void)setRootViewController
{
    AppDelegate *app = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    app.window.rootViewController = [[RootTabViewController alloc] init];

}
AppDelegate+AppService.h

需要處理的各類服務都可以添加在這

/**
 *  系統配置
 */
- (void)systemConfigration;

/**
 *  友盟注冊
 */
- (void)registerUmeng;
/**
 *  個推注冊
 */

- (void)registerGeiTui;

/**
 *  檢查更新
 */
- (void)checkAppUpDataWithshowOption:(BOOL)showOption;

/**
 *  獲取用戶信息
 */
- (void)getUserData;

4.2 DataMange

  • 存放對文件的處理方法,文件的路徑
  • 數據庫的處理
  • NSUserDefault的處理

4.3 Other

建一個類存放比較雜亂的一些公共方法

/**驗證該字符串是否是6-16位字母和數字組合*/
+ (BOOL)checkIsDigitalAndLetter:(NSString *)string;
/**利用正則表達式驗證手機號碼*/
+ (BOOL)checkTel:(NSString *)str;
/**利用正則表達式驗證郵箱*/
+ (BOOL)checkEmail:(NSString *)email;

4.4 UITools

一些公共控件的封裝,常用的一些控件進行封裝(彈窗、廣告輪播等),方便以后統一修改

4.4.1 NavigationViewController封裝

@interface LWTNavigationViewController ()<UINavigationControllerDelegate>

@property (nonatomic, weak) id popDelegate;

@end

@implementation LWTNavigationViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.popDelegate = self.interactivePopGestureRecognizer.delegate;
    self.delegate = self;

    //navigationBar樣式設置
    self.navigationBar.barTintColor = MAIN_GROUNDCOLOR;
    [self.navigationBar setTitleTextAttributes:@{NSForegroundColorAttributeName : WHITCOLOR, NSFontAttributeName : [UIFont boldSystemFontOfSize:18]}];
    [self.navigationBar setTintColor:WHITCOLOR];    // Do any additional setup after loading the view.
}

//解決手勢失效問題
- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    if (viewController == self.viewControllers[0]) {
        self.interactivePopGestureRecognizer.delegate = self.popDelegate;
    }else{
        self.interactivePopGestureRecognizer.delegate = nil;
    }
}

//push時隱藏tabbar
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    if (self.viewControllers.count > 0) {
        viewController.hidesBottomBarWhenPushed = YES;
    }
    [super pushViewController:viewController animated:animated];
}

//設置樣式
- (UIStatusBarStyle)preferredStatusBarStyle
{
    return UIStatusBarStyleLightContent;
}

//設置返回按鈕樣式
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    
    UIBarButtonItem *backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"返回" style:UIBarButtonItemStylePlain target:self action:@selector(backBarButtonItemAction)];
    viewController.navigationItem.backBarButtonItem = backBarButtonItem;
    
}

- (void)backBarButtonItemAction
{
    [self popViewControllerAnimated:YES];
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}
@end

4.4.2 tabBarController封裝

#import "RootTabViewController.h"
#import "LWTNavigationViewController.h"

# define kTabbarSelectTintColor [UIColor brownColor]
# define kTabbarNormalTintColor [UIColor blackColor]

@interface RootTabViewController ()<UITabBarControllerDelegate>

@end

@implementation RootTabViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self buildUI];
    // Do any additional setup after loading the view.
}

/**構建視圖*/
- (void)buildUI{
    
    self.tabBar.translucent     = NO;
    self.tabBar.backgroundImage = [CommonMethods createImageWithColor:[UIColor clearColor]];
    self.tabBar.shadowImage     = [CommonMethods createImageWithColor:[UIColor grayColor]];
    
    NSArray * normalItems       = @[@"home_gray",@"circle_gray",@"me"];
    NSArray * selectItmes       = @[@"home_blue",@"circle_blue",@"me_blue"];
    
    NSArray * controllClass     = @[@"HomePageViewController",@"MessageViewController",@"MyViewController"];
    self.delegate               = self;
    NSArray * itemTitles        = @[@"首頁",@"信息",@"我"];
    NSMutableArray * controllers = [[NSMutableArray alloc]init];
    for (int i = 0; i < normalItems.count; i++)
    {
        UIViewController * homeview =[[NSClassFromString(controllClass[i]) alloc]init];
        LWTNavigationViewController * navigation =[[LWTNavigationViewController alloc]initWithRootViewController:homeview];
        navigation.tabBarItem.image                     = [[UIImage imageNamed:normalItems[i]] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
        navigation.tabBarItem.selectedImage             = [[UIImage imageNamed:selectItmes[i]] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
        navigation.tabBarItem.titlePositionAdjustment   = UIOffsetMake(0,-3);
        [controllers addObject:navigation];
        
        // 設置文字的樣式
        NSMutableDictionary *textAttrs                  = [NSMutableDictionary dictionary];
        textAttrs[NSForegroundColorAttributeName]       = kTabbarNormalTintColor;
        NSMutableDictionary *selectTextAttrs            = [NSMutableDictionary dictionary];
        selectTextAttrs[NSForegroundColorAttributeName] = kTabbarSelectTintColor;
        [homeview.tabBarItem setTitleTextAttributes:textAttrs forState:UIControlStateNormal];
        [homeview.tabBarItem setTitleTextAttributes:selectTextAttrs forState:UIControlStateSelected];
        // 設置tabbaritem 的title
        navigation.tabBarItem.title                     = itemTitles[i];
    }
    self.viewControllers = controllers;
}
@end

4.5 第三方庫的封裝

4.5.1 網絡框架

//基本參數設置
+ (AFHTTPSessionManager *)httpManager{
    //獲取請求對象
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    // 設置請求格式
    manager.requestSerializer = [AFJSONRequestSerializer serializer];
    // 設置返回格式
    manager.responseSerializer = [AFHTTPResponseSerializer serializer];
    [manager.requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Accept"];
    [manager.requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
    manager.requestSerializer.timeoutInterval = RequestTimeOut;
    return manager;
}

//請求處理
+ (void)postParameters:(id)parameters
               success:(void (^)(NSDictionary *resDict))success
               failure:(void (^)(NSError *error))failure
{
    
    //    if ([[AFNetworkReachabilityManager sharedManager] networkReachabilityStatus] <= 0) {
    //        [MBProgressHUD showMessageInWindow:@"網絡無連接" afterDelayHide:AfterDelayHide];
    //        return;
    //    }
    AFHTTPSessionManager *manager = [self httpManager];
    //開始請求
    [manager POST:BaseURLString
       parameters:parameters
         progress:^(NSProgress * _Nonnull uploadProgress) {
         }
          success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
              NSMutableDictionary *resDict = (NSMutableDictionary *)[responseObject mj_JSONObject];
//              NSDictionary *dict = [HttpManager checkResultVaild:resDict withFunction:parameters[@"function"]];
              
             //這里可以處理數據 針對接口返回的特定參數進行處理,如單點登錄等需求
              NSLog(@"\n接口:%@\n返回數據:%@",parameters[@"function"],[[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding]);
              
              success(resDict);
          }
          failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
              failure(error);
              NSLog(@"\n當前接口:%@\n錯誤信息:%@",parameters[@"function"],error);
          }];
}

4.5.2 其他第三方

UM、HUD等很多第三方框架,都需要進行封裝,針對自己app需求進行配置,使用起來就比較方便。

Demo

有什么建議可以提出來,有更好的歡迎探討,不定期更新
demo下載

參考

文中的內容有參考過以下文章,大家可以參考下
多個Target管理
CocoaPods安裝教程
Pch 文件的正確使用
iOS黑魔法-Method Swizzling
手把手教你iOS項目基本框架

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,619評論 6 539
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,155評論 3 425
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,635評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,539評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,255評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,646評論 1 326
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,655評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,838評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,399評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,146評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,338評論 1 372
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,893評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,565評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,983評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,257評論 1 292
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,059評論 3 397
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,296評論 2 376

推薦閱讀更多精彩內容