iOS-项目设计-项目架构设计

210 阅读4分钟

架构设计

一、 架构设计原则

  1. 架构设计我们需要遵循上层依赖底层、下层不能依赖上层;
  2. 同层之间交互可通过,中间件进行解耦;

二、分层

由下到上我们可以将整个应用程序分为四层分别是:

  1. 与业务无关的基础层

例如数据库FMDB、AFNetworking、UIView等的一些系统类分类等。

  1. 与项目业务相关的通用层

存放一些与业务相关的通用类。

  1. 中间层

业务层通过中间层,来调用基础层以及通用业务层;各个业务层之间可通过向中间层进行依赖注入进行交互,实现各个业务层之间的解耦。

三、项目中各个模块解耦

  1. 使用OpenURL的方式;
  2. 向中间层进行依赖注入;假设A业务模块需要调用B业务模块,我们可以将B注入到之间层(中间层持有B,同时实现B定义好的交互协议方法),A通过调用中间层实现好的B协议方法来间接与B交互;
  3. 在A与B之间通过中间件进行交互。

四、中间层解藕示例

假设我们现在有三个页面 InfoEditVC页面用编辑用户信息、CountryVC 选择用户所属国家、CityVC 选择用户号码区号,用户在InfoEditVC页面需要先通过CountryVC页面选择国家返回给InfoEditVC页面,在将选择的国家传递给CityVC进行城市的选择返回给InfoEditVC页面,所以我们可以简单来模拟这个几个页面的交互。



#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN
// 通过VCCenter来访问VC时VCCenter需要实现的协议
@protocol VCCenterPro <NSObject>
// Country协议方法
+(UIViewController *)getCountryVCWithBlock:(void(^)(NSDictionary * param))black;
// CityVC协议方法
+(UIViewController *)getCityVCWithCountry:(NSString *)country andBlock:(void(^)(NSDictionary * param))black;
@end

NS_ASSUME_NONNULL_END

#import <Foundation/Foundation.h>
#import "VCCenterPro.h"
NS_ASSUME_NONNULL_BEGIN

//VCCenter作为VC交互的中间层,一个VC访问另外一个VC需要通过VCCenter来访问
@interface VCCenter : NSObject<VCCenterPro>

@end

NS_ASSUME_NONNULL_END

#import "VCCenter.h"
#import "CountryVC.h"
#import "CityVC.h"
@implementation VCCenter
+(UIViewController *)getCityVCWithCountry:(NSString *)country andBlock:(void (^)(NSDictionary *))black{
    CityVC *vc = [[CityVC alloc] init];
    vc.black = black;
    vc.country = country;
    return vc;
}
+(UIViewController *)getCountryVCWithBlock:(void (^)(NSDictionary *))black{
    CountryVC *vc = [[CountryVC alloc] init];
    vc.black = black;
    return vc;
}
@end


#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface InfoEditVC : UIViewController

@end

NS_ASSUME_NONNULL_END

#import "InfoEditVC.h"
#import "VCCenter.h"
@interface InfoEditVC ()
@property(nonatomic,strong)UIButton *countryBut;
@property(nonatomic,strong)UIButton *cityBut;
@end

@implementation InfoEditVC

- (void)viewDidLoad {
    [super viewDidLoad];
    
    UIButton *countryBut = [[UIButton alloc] initWithFrame:CGRectMake(20, 100, 100, 40)];
    [countryBut setTitle:@"选择国家" forState:UIControlStateNormal];
    [countryBut setTitleColor:UIColor.redColor forState:UIControlStateNormal];
    [countryBut addTarget:self action:@selector(countryButAction:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:countryBut];
    _countryBut = countryBut;
    
    UIButton *cityBut = [[UIButton alloc] initWithFrame:CGRectMake(20, 100+60, 100, 40)];
    [cityBut setTitle:@"选择城市" forState:UIControlStateNormal];
    [cityBut setTitleColor:UIColor.redColor forState:UIControlStateNormal];
    [cityBut addTarget:self action:@selector(cityButAction:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:cityBut];
    _cityBut = cityBut;
    
    
    
    // Do any additional setup after loading the view.
}

-(void)countryButAction:(UIButton *)sender{
    // InfoEditVC 通过VCCenter 访问CountryVC 不依赖CountryVC
    UIViewController *vc = [VCCenter getCountryVCWithBlock:^(NSDictionary * _Nonnull param) {
        [self.countryBut setTitle:param[@"country"] forState:UIControlStateNormal];
    }];
    [self.navigationController pushViewController:vc animated:YES];
    
}
-(void)cityButAction:(UIButton *)sender{
    // InfoEditVC 通过VCCenter 访问CityVC 不依赖CityVC
    UIViewController *vc = [VCCenter getCityVCWithCountry:self.countryBut.titleLabel.text andBlock:^(NSDictionary * _Nonnull param) {
        [self.cityBut setTitle:param[@"city"] forState:UIControlStateNormal];
    }];
    [self.navigationController pushViewController:vc animated:YES];
}

/*
#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    // Get the new view controller using [segue destinationViewController].
    // Pass the selected object to the new view controller.
}
*/

@end



#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface CountryVC : UIViewController
@property(nonatomic,copy)void (^black)(NSDictionary *param);
@end

NS_ASSUME_NONNULL_END


#import "CountryVC.h"
@interface CountryVC ()
@property(nonatomic,strong)UIButton *countryBut;
@end

@implementation CountryVC

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    UIButton *countryBut = [[UIButton alloc] initWithFrame:CGRectMake(20, 100, 100, 40)];
    [countryBut setTitle:@"中国" forState:UIControlStateNormal];
    [countryBut setTitleColor:UIColor.redColor forState:UIControlStateNormal];
    [countryBut addTarget:self action:@selector(countryButAction:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:countryBut];
    _countryBut = countryBut;
}
-(void)countryButAction:(UIButton *)sender{
    [self.navigationController popViewControllerAnimated:YES];
    if (_black) {
        _black(@{@"country":_countryBut.titleLabel.text});
    }
}
/*
#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    // Get the new view controller using [segue destinationViewController].
    // Pass the selected object to the new view controller.
}
*/

@end

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN
@interface CityVC : UIViewController
@property(nonatomic,copy)void (^black)(NSDictionary *param);
@property(nonatomic,copy)NSString *country;
@end

NS_ASSUME_NONNULL_END
 
#import "CityVC.h"

@interface CityVC ()
@property(nonatomic,strong)UIButton *cityBut;
@end

@implementation CityVC

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    UIButton *countryBut = [[UIButton alloc] initWithFrame:CGRectMake(20, 100, 100, 40)];
    [countryBut setTitle:_country forState:UIControlStateNormal];
    [countryBut setTitleColor:UIColor.redColor forState:UIControlStateNormal];
    [self.view addSubview:countryBut];
    
    UIButton *cityBut = [[UIButton alloc] initWithFrame:CGRectMake(20, 100+60, 100, 40)];
    [cityBut setTitle:@"深圳" forState:UIControlStateNormal];
    [cityBut setTitleColor:UIColor.redColor forState:UIControlStateNormal];
    [cityBut addTarget:self action:@selector(cityButAction:) forControlEvents:UIControlEventTouchUpInside];
    _cityBut = cityBut;
    [self.view addSubview:cityBut];
}
-(void)cityButAction:(UIButton *)sender{
    [self.navigationController popViewControllerAnimated:YES];
    if (_black) {
        _black(@{@"city":_cityBut.titleLabel.text});
    }
}
/*
#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    // Get the new view controller using [segue destinationViewController].
    // Pass the selected object to the new view controller.
}
*/

@end

由此我们在编写代码时,可以通过中间件(中间层)的方式来避免对其他具体对象的依赖,而是依赖其抽象实现开闭原则