ReactiveCocoa框架下的MVVM模式解读

记录一些MVVM文章中关于ReactiveCocoa的代码:

实例一:带有分页的文章列表,根据文章类别过滤出文章的列表,可以进入文章详细页面

1:YFBlogListViewModel 首先了解关于列表的ViewModel的代码内容:

#import <Foundation/Foundation.h>
#import <ReactiveCocoa.h>

@class YFCategoryArticleListModel;

/**
 *  文章列表的视图模型.
 */
@interface YFBlogListViewModel : NSObject
@property (copy, nonatomic) NSArray * blogListItemViewModels; //!< 文章.内部存储的应为文章列表单元格的视图模型.注意: 刷新操作,存储第一页数据;翻页操作,将存储所有的数据,并按页面排序.

/**
 *  使用一个分类文章列表数据模型来快速初始化.
 *
 *  @param model 文章列表模型.
 *
 *  @return 实例对象.
 */

- (instancetype)initWithCategoryArtilceListModel: (YFCategoryArticleListModel *) model;

/**
 *  获取首页的数据.常用于下拉刷新.
 *
 */
- (void)first;

/**
 *  翻页,获取下一页的数据.常用于上拉加载更多.
 */
- (void)next;

@end
#import "YFBlogListViewModel.h"
#import <ReactiveCocoa.h>
#import <AFNetworking.h>
#import <RACAFNetworking.h>
#import "YFCategoryArticleListModel.h"
#import <MJExtension.h>
#import "YFBlogListItemViewModel.h"
#import "YFArticleModel.h"

@interface YFBlogListViewModel ()
@property (strong, nonatomic) AFHTTPRequestOperationManager * httpClient;
@property (strong, nonatomic) NSNumber * nextPageNumber; //!< 下次要请求第几页的数据.
@property (copy, nonatomic) NSString * category; //!< 文章类别.
@property (copy, nonatomic) NSString * requestPath; //!< 完整接口地址.

@end

@implementation YFBlogListViewModel

- (instancetype)initWithCategoryArtilceListModel:(YFCategoryArticleListModel *)model
{
    self = [super init];

    if (nil != self) {
        // 设置 self.category 与 model.category 的关联.
        [RACObserve(model, category) subscribeNext:^(NSString * categoryName) {
            self.category = categoryName;
        }];

        // 和类型无关的RAC 初始化操作,应该剥离出来.
        [self setup];
    }

    return self;
}

/**
 *  和数据模型无关的初始化设置,放到独立的方法中.
 */
- (void)setup
{
    // 初始化网络请求相关的信息.
    self.httpClient = [AFHTTPRequestOperationManager manager];
    self.httpClient.requestSerializer = [AFJSONRequestSerializer serializer];
    self.httpClient.responseSerializer = [AFJSONResponseSerializer serializer];

    // 设置 self.nextPageNumber 与self.category的关联.
    [RACObserve(self, category) subscribeNext:^(id x) {
        // 只要分类变化,下次请求,都需要重置为请求第零页的数据.
        self.nextPageNumber = @0;
    }];

    // 接口完整地址,肯定是受分类和页面的影响的.但是因为分类的变化最终会通过分页的变化来体现,所以此处仅需监测分页的变化情况即可.
    [RACObserve(self, nextPageNumber)  subscribeNext:^(NSNumber * nextPageNumber) {
        NSString * path = [NSString stringWithFormat: @"http://www.ios122.com/find_php/index.php?viewController=YFPostListViewController&model[category]=%@&model[page]=%@", self.category, nextPageNumber];

        self.requestPath = path;
    }];

    // 每次数据完整接口变化时,必然要同步更新 blogListItemViewModels 的值.
    [[RACObserve(self, requestPath) filter:^BOOL(id value) {
        return value;
    }] subscribeNext:^(NSString * path) {
        /**
         *  分两种情况: 如果是变为0,说明是重置数据;如果是大于0,说明是要加载更多数据;不处理向上翻页的情况.
         */

        NSMutableArray * articls = [NSMutableArray arrayWithCapacity: 42];

        if (YES != [self.nextPageNumber isEqualToNumber: @0]) {
            [articls addObjectsFromArray: self.blogListItemViewModels];
        }

        [[self.httpClient rac_GET:path parameters:nil] subscribeNext:^(RACTuple *JSONAndHeaders) {
            // 使用MJExtension将JSON转换为对应的数据模型.
            NSArray * newArticles = [YFArticleModel objectArrayWithKeyValuesArray: JSONAndHeaders.first];

            // RAC 风格的数组操作.
            RACSequence * newblogViewModels = [newArticles.rac_sequence
                                    map:^(YFArticleModel * model) {
                                        YFBlogListItemViewModel * vm = [[YFBlogListItemViewModel alloc] initWithArticleModel: model];

                                        return vm;
                                    }];

            [articls addObjectsFromArray: newblogViewModels.array];

            self.blogListItemViewModels = articls;
        }];
    }];
}

- (void)first
{
    self.nextPageNumber = @0;
}

- (void)next
{
    self.nextPageNumber  = [NSNumber numberWithInteger: [self.nextPageNumber integerValue] + 1];
}

@end

2:YFCategoryArticleListModel模型的内容

#import <Foundation/Foundation.h>

/**
 *  分类文章列表.
 */
@interface YFCategoryArticleListModel : NSObject
@property (copy, nonatomic) NSString * category; //!< 分类
@property (strong, nonatomic) NSArray * articles; //!< 此分类下的文章列表.

@end

3:ViewController的代码

#import <UIKit/UIKit.h>

@class YFBlogListViewModel;

@interface YFMVVMPostListViewController : UIViewController<UITableViewDelegate, UITableViewDataSource>
@property (nonatomic, strong) UITableView * tableView;
@property (strong, nonatomic) YFBlogListViewModel * viewModel;

@end
#import "YFMVVMPostListViewController.h"
#import "YFBlogListViewModel.h"
#import <ReactiveCocoa.h>
#import "YFCategoryArticleListModel.h"
#import "YFBlogListViewModel.h"
#import "YFBlogListItemViewModel.h"
#import "YFArticleModel.h"
#import "YFBlogDetailViewModel.h"
#import <MJRefresh.h>
#import "YFMVVMPostViewController.h"

@interface YFMVVMPostListViewController ()

@end

@implementation YFMVVMPostListViewController

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

    [RACObserve(self.viewModel, blogListItemViewModels) subscribeNext:^(id x) {
        [self updateView];
    }];
}

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

- (UITableView *)tableView
{
    if (nil == _tableView) {
        _tableView = [[UITableView alloc] init];

        [self.view addSubview: _tableView];

        [_tableView makeConstraints:^(MASConstraintMaker *make) {
            make.edges.equalTo(UIEdgeInsetsMake(0, 0, 0, 0));
        }];

        _tableView.delegate = self;
        _tableView.dataSource = self;

        NSString * cellReuseIdentifier = NSStringFromClass([UITableViewCell class]);

        [_tableView registerClass: NSClassFromString(cellReuseIdentifier) forCellReuseIdentifier:cellReuseIdentifier];

        _tableView.header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{
            [self.viewModel first];
        }];

        _tableView.footer = [MJRefreshBackNormalFooter footerWithRefreshingBlock:^{
            [self.viewModel next];
        }];

    }

    return _tableView;
}

/**
 * 更新视图.
 */
- (void) updateView
{
    [self.tableView.header endRefreshing];
    [self.tableView.footer endRefreshing];

    [self.tableView reloadData];
}

# pragma mark - tabelView代理方法.

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    NSInteger number  = self.viewModel.blogListItemViewModels.count;

    return number;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSString * cellReuseIdentifier = NSStringFromClass([UITableViewCell class]);

    UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier: cellReuseIdentifier forIndexPath:indexPath];

    YFBlogListItemViewModel * vm = self.viewModel.blogListItemViewModels[indexPath.row];

    NSString * content = vm.intro;

    cell.textLabel.text = content;

    cell.selectionStyle = UITableViewCellSelectionStyleNone;

    return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    // 跳转到博客详情.
    YFBlogListItemViewModel * itemVM = self.viewModel.blogListItemViewModels[indexPath.row];

    YFMVVMPostViewController * postVC = [[YFMVVMPostViewController alloc] init];

    YFBlogDetailViewModel * detailVM = [[YFBlogDetailViewModel alloc] init];
    detailVM.blogId = itemVM.blogId;

    postVC.viewModel = detailVM;

    [self.navigationController pushViewController: postVC animated: YES];
}

@end

4:跳转到当前页面的内容

        YFMVVMPostListViewController * mvvmPostVC = [[YFMVVMPostListViewController alloc] init];

        YFCategoryArticleListModel * articleListModel = [[YFCategoryArticleListModel alloc] init];
        articleListModel.category = @"ui";

        YFBlogListViewModel * listVM = [[YFBlogListViewModel alloc] initWithCategoryArtilceListModel: articleListModel];

        mvvmPostVC.viewModel = listVM;

        [self.navigationController pushViewController: mvvmPostVC animated: YES];

5:详细页面的ViewModel代码:

#import <Foundation/Foundation.h>
@class YFArticleModel;

/**
 *  文章详情的视图模型.
 */

@interface YFBlogDetailViewModel : NSObject
@property (copy, nonatomic) NSString * content; // 要显示的内容.
@property (copy, nonatomic) NSString * blogId; //!< 博客ID.

- (instancetype)initWithModel: (YFArticleModel *) model;

@end
#import "YFBlogDetailViewModel.h"
#import <ReactiveCocoa.h>
#import "YFArticleModel.h"
#import <RACAFNetworking.h>
#import <MJExtension.h>

@interface YFBlogDetailViewModel ()
@property (strong, nonatomic) AFHTTPRequestOperationManager * httpClient;
@property (copy, nonatomic) NSString * requestPath; //!< 完整接口地址.

@end
@implementation YFBlogDetailViewModel

- (instancetype)init
{
    self = [self initWithModel: nil];

    return self;
}

- (instancetype)initWithModel:(YFArticleModel *)model
{
    self = [super init];

    if (nil != self) {
        // 设置self.blogId与model.id的相互关系.
        [RACObserve(model, id) subscribeNext:^(id x) {
            self.blogId = x;
        }];

        [self setup];
    }

    return self;
}

/**
 *  公共的与Model无关的初始化.
 */
- (void)setup
{
    // 初始化网络请求相关的信息.
    self.httpClient = [AFHTTPRequestOperationManager manager];
    self.httpClient.requestSerializer = [AFJSONRequestSerializer serializer];
    self.httpClient.responseSerializer = [AFJSONResponseSerializer serializer];

    // 接口完整地址,肯定是受id影响.
    [[RACObserve(self, blogId) filter:^BOOL(id value) {
        return value;
    }] subscribeNext:^(NSString * blogId) {
        NSString * path = [NSString stringWithFormat: @"http://www.ios122.com/find_php/index.php?viewController=YFPostViewController&model[id]=%@", blogId];

        self.requestPath = path;
    }];

    // 每次完整的数据接口变化时,必然要同步更新 self.content 的值.
    [[RACObserve(self, requestPath) filter:^BOOL(id value) {
        return value;
    }] subscribeNext:^(NSString * path) {
        [[self.httpClient rac_GET:path parameters:nil] subscribeNext:^(RACTuple *JSONAndHeaders) {
            // 使用MJExtension将JSON转换为对应的数据模型.
            YFArticleModel * model = [YFArticleModel objectWithKeyValues:JSONAndHeaders.first];

            self.content = model.body;
        }];
    }];
}

@end

6:详细页面的ViewController

#import <UIKit/UIKit.h>

@class YFBlogDetailViewModel;

@interface YFMVVMPostViewController : UIViewController
@property (strong, nonatomic) YFBlogDetailViewModel * viewModel;

@end
#import "YFMVVMPostViewController.h"
#import "YFBlogDetailViewModel.h"
#import <ReactiveCocoa.h>

@interface YFMVVMPostViewController ()
@property (strong, nonatomic) UIWebView * webView;
@end

@implementation YFMVVMPostViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    [RACObserve(self.viewModel, content) subscribeNext:^(id x) {
        [self updateView];
    }];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}
- (UIWebView *)webView
{
    if (nil == _webView) {
        _webView = [[UIWebView alloc] init];

        [self.view addSubview: _webView];

        [_webView makeConstraints:^(MASConstraintMaker *make) {
            make.edges.equalTo(UIEdgeInsetsMake(0, 0, 0, 0));
        }];
    }

    return _webView;
}

/**
 * 更新视图.
 */
- (void) updateView
{
    [self.webView loadHTMLString: self.viewModel.content baseURL:nil];
}

@end

实例二:用户列表实例

1:用户列表的ViewModel代码UsersViewModel

#import <ReactiveViewModel/ReactiveViewModel.h>

@class RACCommand;

#pragma mark -

@interface UsersViewModel : RVMViewModel

/// Array of UserViewModel objects filled by userViewModelsCommand.
@property (nonatomic, readonly) NSArray *userViewModels;

/// Input: nil
@property (nonatomic, readonly) RACCommand *userViewModelsCommand;

/// Input: nil
@property (nonatomic, readonly) RACCommand *clearImageCacheCommand;

@property (nonatomic, readonly, getter=isLoading) BOOL loading;

@end
#import "UsersViewModel.h"

#import "UserViewModel.h"

#import "UserController.h"

#import "User.h"

#import "ImageController.h"

#import <ReactiveCocoa/ReactiveCocoa.h>
#import <ReactiveCocoa/RACEXTScope.h>

#pragma mark -

@implementation UsersViewModel

- (instancetype)init {
    self = [super init];
    if (self) {
        UserController *userController = [[UserController alloc] init];
        ImageController *imageController = [ImageController sharedController];

        _userViewModelsCommand = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id _) {
            return [[[userController fetchRandomUsers:100]
                        subscribeOn:[RACScheduler scheduler]]
                        map:^NSArray *(NSArray *users) {
                            return [[[users rac_sequence]
                                        map:^UserViewModel *(User *user) {
                                            return [[UserViewModel alloc] initWithUser:user imageController:imageController];
                                        }]
                                        array];
                        }];
        }];

        RAC(self, userViewModels) =
            [[[_userViewModelsCommand executionSignals]
                switchToLatest]
                deliverOn:[RACScheduler mainThreadScheduler]];

        RAC(self, loading) =
            [_userViewModelsCommand executing];

        _clearImageCacheCommand = [[RACCommand alloc] initWithEnabled:[RACObserve(self, loading) not] signalBlock:^RACSignal *(id _) {
            return [imageController purgeLocalCaches];
        }];
    }
    return self;
}

@end

2:另外封装UserController的代码:

@class RACSignal;

#pragma mark -

@interface UserController : NSObject

/// Sends an array of fabricated User objects then completes.
- (RACSignal *)fetchRandomUsers:(NSUInteger)numberOfUsers;

@end
#import "UserController.h"

#import "User.h"

#import <ReactiveCocoa/ReactiveCocoa.h>
#import <LoremIpsum/LoremIpsum.h>

#pragma mark -

@implementation UserController

- (RACSignal *)fetchRandomUsers:(NSUInteger)numberOfUsers {
    return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        NSMutableArray *usersArray = [NSMutableArray array];
        for (int i = 0; i < numberOfUsers; i++) {
            NSString *name = [LoremIpsum name];
            NSURL *avatarURL = [[LoremIpsum URLForPlaceholderImageFromService:LIPlaceholderImageServiceHhhhold withSize:CGSizeMake(96, 96)] URLByAppendingPathComponent:[NSString stringWithFormat:@"jpg?test=%i", i]];
            User *user = [[User alloc] initWithName:name avatarURL:avatarURL];
            [usersArray addObject:user];
        }
        [subscriber sendNext:[usersArray copy]];
        [subscriber sendCompleted];
        return nil;
    }];
}

@end

3:Model的代码:

#pragma mark -

@interface User : NSObject

@property (nonatomic, readonly) NSString *name;
@property (nonatomic, readonly) NSURL *avatarURL;

- (instancetype)initWithName:(NSString *)name avatarURL:(NSURL *)avatarURL;

@end
#import "User.h"

#pragma mark -

@implementation User

- (instancetype)initWithName:(NSString *)name avatarURL:(NSURL *)avatarURL {
    self = [super init];
    if (self != nil) {
        _name = name;
        _avatarURL = avatarURL;
    }
    return self;
}

@end

4:ViewController的代码

@class UsersViewModel;

@interface UsersViewController : UITableViewController

- (instancetype)initWithViewModel:(UsersViewModel *)viewModel;

@end
#import "UsersViewController.h"

#import "UsersViewModel.h"
#import "UserViewModel.h"

#import "UserCell.h"

#import <ReactiveCocoa/ReactiveCocoa.h>
#import <ReactiveCocoa/RACEXTScope.h>

#pragma mark -

@interface UsersViewController ()

@property (nonatomic, readonly) UsersViewModel *viewModel;

@end

@implementation UsersViewController

- (instancetype)initWithViewModel:(UsersViewModel *)viewModel {
    self = [super init];
    if (self != nil) {
        _viewModel = viewModel;
    }
    return self;
}

- (void)viewDidLoad {
    [super viewDidLoad];

    self.tableView.rowHeight = 48;
    [self.tableView registerClass:[UserCell class] forCellReuseIdentifier:NSStringFromClass([UserCell class])];

    @weakify(self);

    self.title = NSLocalizedString(@"Random Users", nil);

    UIBarButtonItem *clearImageCacheBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"Clear Cache", nil) style:UIBarButtonItemStylePlain target:nil action:nil];
    clearImageCacheBarButtonItem.rac_command = self.viewModel.clearImageCacheCommand;
    self.navigationItem.rightBarButtonItem = clearImageCacheBarButtonItem;

    self.refreshControl = [[UIRefreshControl alloc] init];
    [[[self.refreshControl rac_signalForControlEvents:UIControlEventValueChanged]
        mapReplace:self.viewModel.userViewModelsCommand]
        subscribeNext:^(RACCommand *userViewModelsCommand) {
            [userViewModelsCommand execute:nil];
        }];

    [RACObserve(self.viewModel, loading)
        subscribeNext:^(NSNumber *loading) {
            @strongify(self);
            if ([loading boolValue]) {
                [self.refreshControl beginRefreshing];
                [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
            } else {
                [self.refreshControl endRefreshing];
                [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
            }
        }];

    [[RACObserve(self.viewModel, userViewModels)
        ignore:nil]
        subscribeNext:^(id _) {
            @strongify(self);
            [self.tableView reloadData];
        }];

    [self.viewModel.userViewModelsCommand execute:nil];
}

#pragma mark UITableViewDataSource

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return [self.viewModel.userViewModels count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UserViewModel *viewModel = self.viewModel.userViewModels[indexPath.row];

    UserCell *cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass([UserCell class]) forIndexPath:indexPath];
    cell.viewModel = viewModel;
    cell.viewModel.active = YES;
    return cell;
}

# pragma mark UITableViewDelegate

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    UserViewModel *userViewModel = self.viewModel.userViewModels[indexPath.row];
    NSLog(@"Selected: %@", userViewModel);
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
}

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {

}

- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
    UserCell *userCell = (UserCell *)cell;
    userCell.viewModel.active = NO;
}

@end

6:UserCell代码:

@class UserViewModel;

#pragma mark -

@interface UserCell : UITableViewCell

@property (nonatomic) UserViewModel *viewModel;

@end
#import "UserCell.h"

#import "ImageView.h"

#import "UserViewModel.h"
#import "ImageViewModel.h"

#import <ReactiveCocoa/ReactiveCocoa.h>

#pragma mark -

@interface UserCell ()

@property (nonatomic, readonly) ImageView *avatarImageView;

@end

@implementation UserCell

- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self != nil) {
        _avatarImageView = [[ImageView alloc] init];
        [self.contentView addSubview:_avatarImageView];
    }
    return self;
}

- (void)setViewModel:(UserViewModel *)viewModel {
    if (_viewModel == viewModel) return;

    _viewModel = viewModel;

    self.avatarImageView.viewModel = _viewModel.imageViewModel;
    self.textLabel.text = _viewModel.name;
}

- (void)layoutSubviews {
    [super layoutSubviews];

    self.avatarImageView.frame = CGRectMake(0, 0, 48, 48);
    self.textLabel.frame = CGRectMake(58, 0, 260, 48);
}

@end

7:调用主控制器跳转

    UsersViewModel *usersViewModel = [[UsersViewModel alloc] init];
    UsersViewController *usersViewController = [[UsersViewController alloc] initWithViewModel:usersViewModel];

另:reactivecocoa afnetworking地交互可以查下面这个实例,地址:https://github.com/octokit/octokit.objc

小项目框架设计(ReactiveCocoa+MVVM+AFNetworking+FMDB) 地址:http://www.tuicool.com/articles/Q3uuQvA

时间: 2024-08-05 15:02:59

ReactiveCocoa框架下的MVVM模式解读的相关文章

【转】ASP.NET MVC框架下使用MVVM模式-KnockOutJS+JQ模板例子

KnockOutJS学习系列----(一) 好几个月没去写博客了,最近也是因为项目紧张,不过这个不是借口,J. 很多时候可能是因为事情一多,然后没法静下来心来去写点东西,学点东西. 也很抱歉,突然看到好多的短消息,真不知道该如何给大家回复... 最近试着晚上抽时间写一些knockoutjs和mvc的文章.这里先写一点knockoutjs的东西. 关于knockoutjs到底是什么,如果你不知道,可以看看几个月前我写的一篇文章介绍它. ASP.NET MVC框架下使用MVVM模式 我也是之前安装了

【工作笔记二】ASP.NET MVC框架下使用MVVM模式

ASP.NET MVC框架下使用MVVM模式 原文:http://www.cnblogs.com/n-pei/archive/2011/07/21/2113022.html 对于asp.net mvc开发人员或爱好者来说,MVVM模式可能你不是很了解.本来这个模式就是针对WPF和Silverlight开发提出的开发模式. 大概一年前,我当时迷恋Silverlight时,学习了MVVM一段时间,没想到现在可以在MVC用到. 我看了下之前有两篇文章介绍MVVM的.希望可以对MVVM不了解的人有点帮助

WPF Prism框架下基于MVVM模式的命令、绑定、事件

原文:WPF Prism框架下基于MVVM模式的命令.绑定.事件 Prism框架下的自定义路由事件和命令绑定 BaseCode XAML代码: <Button x:Class="IM.UI.CommandEx.PrismCommandEx" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/wi

angular中的MVVM模式

在开始介绍angular原理之前,我们有必要先了解下mvvm模式在angular中运用.虽然在angular社区一直将angular统称为前端MVC框架,同时angular团队也称它为MVW(Whatever)框架,但angular框架整体上更接近MVVM模式.下面是Igor Minar发布在Google+ https://plus.google.com/+IgorMinar/posts/DRUAkZmXjNV的文章内容: MVC vs MVVM vs MVP. What a controver

MVVM模式下如何使用ReactiveCocoa响应链式编程&lt;一&gt;

前一阵子公司要求项目从新架构,但又只给不到一个月的时间,这显然是不可能的.但从新架构又是在所难免的,和同事商定后决定一部分交互逻辑比较少的界面先使用MVVM架构,然后慢慢修改.下面整理了一下这次重构的遇到的问题,并希望能给大家一些帮助. 1.ReactiveCocoa的使用 要使用MVVM模式编程收下选择一个框架,当然不仅仅是ReactiveCocoa这一个框架,这里就不多说.当然我也没用过别的,如果哪位看官用过可以多多指教.接下来我就按步骤说了: 第一步:导入ReactiveCocoa框架,建

iOS开发之ReactiveCocoa下的MVVM(干货分享)

最近工作比较忙,但还是出来更新博客了,今天给大家分享一些ReactiveCocoa以及MVVM的一些东西,干活还是比较足的.在之前发表过一篇博文,名字叫做<iOS开发之浅谈MVVM的架构设计与团队协作>,大体上讲的就是使用Block回调的方式实现MVVM的.在写上篇文章时也知道有ReactiveCocoa这个函数响应式编程的框架,并且有许多人用它来更好的实现MVVM.所以在上篇博客发表后,有些同行给评论建议看一下ReactiveCocoa的东西,所以就系统的看了一下ReactiveCocoa的

iOS开发之ReactiveCocoa下的MVVM

最近工作比较忙,但还是出来更新博客了,今天给大家分享一些ReactiveCocoa以及MVVM的一些东西,干活还是比较足的.在之前发表过一篇博文,名字叫做<iOS开发之浅谈MVVM的架构设计与团队协作>,大体上讲的就是使用Block回调的方式实现MVVM的.在写上篇文章时也知道有ReactiveCocoa这个函数响应式编程的框架,并且有许多人用它来更好的实现MVVM.所以在上篇博客发表后,有些同行给评论建议看一下ReactiveCocoa的东西,所以就系统的看了一下ReactiveCocoa的

浅析WPF中MVVM模式下命令与委托的关系

??各位朋友大家好,我是Payne,欢迎大家关注我的博客,我的博客地址是http://qinyuanpei.com.最近因为项目上的原因开始接触WPF,或许这样一个在现在来讲显得过时的东西,我猜大家不会有兴趣去了解,可是你不会明白对某些保守的项目来讲,安全性比先进性更为重要,所以当你发现银行这类机构还在使用各种"复古"的软件系统的时候,你应该相信这类东西的确有它们存在的意义.与此同时,你会更加深刻地明白一个道理:技术是否先进性和其流行程度本身并无直接联系.由此我们可以推论出:一项不流行

js架构设计模式——MVVM模式下,ViewModel和View,Model有什么区别

MVVM模式下,ViewModel和View,Model有什么区别 Model:很简单,就是业务逻辑相关的数据对象,通常从数据库映射而来,我们可以说是与数据库对应的model. View:也很简单,就是展现出来的用户界面. 基本上,绝大多数软件所做的工作无非就是从数据存储中读出数据,展现到用户界面上,然后从用户界面接收输入,写入到数据存储里面去.所以,对于数据 存储(model)和界面(view)这两层,大家基本没什么异议.但是,如何把model展现到view上,以及如何把数据从view写入到m