RAC + MVVM 2

MVVM+RAC简单使用教程 MVVM+RAC简单使用教程既然是简单使用那就不讲那些概念了。什么是MVC、MVP、MVVM这些就忽略啦!很多大神写了很多,有关他们的优缺点都写的非常的好,我就没必要再写一遍了。 直接开始写怎么开始一个 MVVM+RAC 的教程了。 我喜欢在写代码的时候先写思路,这样就顺便把注释也写了。 写Demo和下厨是一样一样的,得有先材料。 那么写这个也要准备一下材料:1. 导入ReactiveCoc 阅读详情

尝试新的架构当然不会从老的项目中直接修改,这样风险太大,所以我决定单独写一个小的Demo,这个本来是封装好的网络库,Demo就直接放到这里面了。用小Demo来尝试新的架构设计,然后再在原工程上逐渐引入新的架构。
Demo是实现一个豆瓣用户的搜索功能,Demo的最终效果图是这样的:

Demo的完整架构如下:


橙色表示操作、绿色虚线表示数据的流动

1. 定义Model

根据豆瓣API里关于User的定义,定义了这边的Model

@interface UserItemModel : MTLModel <MTLJSONSerializing>
@property (nonatomic, copy) NSString *locId;
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *createdTime;
@property (nonatomic, copy) NSString *locName;
@property (nonatomic, copy) NSString *avatarURLString;
@property (nonatomic, copy) NSString *signature;
@property (nonatomic, copy) NSString *uid;
@property (nonatomic, assign) BOOL isBanned;
@property (nonatomic, assign) BOOL isSuicide;
@end

项目引入了Mantle,方便从JSON到Model的转化。

2. 定义ViewModel

这里需要定义两个ViewModel,第一个UserListViewModel是为我们的Controller提供网络访问、列表数据管理等,第二个UserItemViewModel是用来配置Cell的,每个Cell绑定一个userItemViewModel。

2.1 UserListViewModel

UserListViewModel公开给Controller的内容很少,如下:

//  UserListViewModel.h
@interface UserListViewModel : NSObject<YLNetworkingListRACProtocol>
@property (nonatomic, copy) NSString *keywords;
@property (nonatomic, readonly) BOOL hasNextPage;
@property (nonatomic, copy) NSArray<UserItemViewModel *> *userItemViewModels;
@end
  • keywords即是要搜索的关键字,需要由Controller告诉ViewModel。
  • hasNextPage是告诉Controller什么时候标记已无数据
  • userItemViewModels即tableView的数据源
  • 实现YLNetworkingListRACProtocol协议,是将对网络请求的RAC封装开放出去而避免直接对外公开APIManager,这点在第一篇文章中已经解释过了。

由于把关于网络请求部分的RAC操作也单独的抽离出去,所以ViewModel显得更简洁一些,

//  UserListViewModel.m
#import "UserListViewModel.h"
#import "UserAPIManager.h"
@interface UserListViewModel()<YLAPIManagerDataSource>
@property (nonatomic, strong) UserAPIManager *userAPIManager;
@end
@implementation UserListViewModel

- (instancetype)init {
    self = [super init];
    if (self) {
        [self setupRAC];
    }
    return self;
}

- (void)setupRAC {
    @weakify(self);
    [self.networkingRAC.executionSignal subscribeNext:^(id x) {
        @strongify(self);
        if ([x boolValue]) {
            self.userItemViewModels = nil;
        }
        NSMutableArray *userItemViewModels = [NSMutableArray arrayWithArray:self.userItemViewModels];
        NSArray *userModels = [self.userAPIManager fetchDataFromModel];
        RACSequence *userViewModelSeq = [userModels.rac_sequence map:^id(UserItemModel *model) {
            return [[UserItemViewModel alloc] initWithModel:model];
        }];
        [userItemViewModels addObjectsFromArray:userViewModelSeq.array];
        self.userItemViewModels = userItemViewModels;
    }];
}

- (NSDictionary *)paramsForAPI:(YLBaseAPIManager *)manager {
    NSDictionary *params = @{};
    if (manager == self.userAPIManager) {
        params = @{
                   kUserAPIManagerParamsKeySearchKeywords:self.keywords?:@"",
                   };
    }
    return params;
}

#pragma mark - getter && setter

- (UserAPIManager *)userAPIManager {
    if (_userAPIManager == nil) {
        _userAPIManager = [[UserAPIManager alloc] initWithPageSize:20];
        _userAPIManager.dataSource = self;
    }
    return _userAPIManager;
}

- (BOOL)hasNextPage {
    return self.userAPIManager.hasNextPage;
}

- (id<YLNetworkingListRACOperationProtocol>)networkingRAC {
    return self.userAPIManager;
}
@end

重点在setupRAC方法,在这里订阅了Command执行完成的信号(注意我在NetworkingRAC封装的时候直接将executionSignals进行了switchToLatest),所以这里得到的就是Command执行完成的信号,首先判定传进来的参数的bool值(实在NetworkingRAC封装时进行的map),来确定是否需要重置数据列表。这里直接通过[self.userAPIManager fetchDataFromModel]来获取请求得到的models,然后将其转换为userItemViewModels,最后进行赋值,此处的赋值会引发ViewController的刷新,后面讲ViewController的时候在来具体说明。

请求的参数是由paramsForAPI提供出去的。

2.2 UserItemViewModel

这个ViewModel就比较简单,直接简单的将model转变为ViewModel,这里只保留了当前需要的几个参数

//  UserItemViewModel.h
@interface UserItemViewModel : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *locName;
@property (nonatomic, copy) NSString *signature;
@property (nonatomic, copy) NSURL *avatarURL;

- (instancetype)initWithModel:(UserItemModel *)model;
@end

initWithModel定义如下

//  UserItemViewModel.m

- (instancetype)initWithModel:(UserItemModel *)model {
    self = [super init];
    if (self) {
        RAC(self, name) = RACObserve(model, name);
        RAC(self, locName) = RACObserve(model, locName);
        RAC(self, signature) = RACObserve(model, signature);
        RAC(self, avatarURL) = [RACObserve(model, avatarURLString) map:^id(NSString *value) {
            if (value == nil) {
                return nil;
            }
            return [[NSURL alloc] initWithString:value];
        }];
    }
    return self;
}

其实这里完全可以不用RAC,由于这里的单个model并不会发生改变,所以这里直接进行赋值也是可以的,但是当model有可能会发生变化时,还是采用RAC绑定比较好。就比如说我们通常会针对App登陆用户建立一个单例的User类,我们在展示这个User的时候建立起的ViewModel就使用RAC绑定就很方便了,一旦用户改变了User的一些信息,ViewModel将自动更新数据并进一步引发View层的视图更新。

3. TableViewCell

在看Controller之前,我们先看一下Cell的定义,Cell布局比较简单,头像+昵称+地点+签名。我这里使用了xib,那么就直接在awakeFromNib里进行数据绑定。

- (void)awakeFromNib {
    self.avatarImageView.image = nil; //prevent dirty data
    @weakify(self);
    [RACObserve(self, viewModel) subscribeNext:^(UserItemViewModel *viewModel) {
        @strongify(self);
        self.nameLabel.text = viewModel.name;
        self.localeLabel.text = viewModel.locName;
        self.signatureLabel.text = viewModel.signature;
        [self.avatarImageView setImageWithURL:viewModel.avatarURL];
    }];    
}

在这里,当Cell的ViewModel发生变化的时候,View会立即更新数据,注意这里是针对整个viewModel发生赋值变化替换成另外一个viewModel,而没有分别检测viewModel的每一项,因为通常针对Cell的赋值,是整个通过viewModel进行配置。
这里有一个小小的违背MVVM模式的一点,就是设置头像,我在view里直接调用了AFNetworking的一个扩展发起网络访问。但是我觉得这样做也是合理的,毕竟模式也只是用来参考,并不绝对,过度的封装会导致代码可读性更差,反倒得不偿失。前面将image置为nil是为了防止重用Cell时脏数据造成的影响。
这里RAC起到的作用是对应的是第一篇文章中作用于View和ViewModel之间,当ViewModel变化时,变化的信号传递到View这里,然后View针对新的数据进行更新。

4. ViewController

做了那么多准备工作,终于到Controller了,ViewModel将网络访问、数据处理承接之后,Cotroller就变得很轻,只剩下数据的绑定工作和跳转、展示等逻辑处理。

4.1 数据绑定与错误处理
    @weakify(self);
    RAC(self.viewModel,keywords) = self.searchTextField.rac_textSignal;

    [[[RACObserve(self.viewModel, userItemViewModels) skip:1]
     deliverOn:[RACScheduler mainThreadScheduler]]
     subscribeNext:^(id x) {
         @strongify(self);
         [self.tableView reloadData];
         [self.tableView.header endRefreshing];
         if (self.viewModel.hasNextPage) {
             [self.tableView.footer endRefreshing];
         } else {
             [self.tableView.footer endRefreshingWithNoMoreData];
         }
     }];

    [self.viewModel.networkingRAC.requestErrorSignal
     subscribeNext:^(NSError *error) {
         @strongify(self);
         self.title = error.localizedDescription;
         [self.tableView.header endRefreshing];
         [self.tableView.footer endRefreshing];
    }];

首先,我们先将textField的内容与viewModel的keywords进行绑定,这样当textField发生改变时,viewModel的keywords也随之改变,下次搜索请求发出去的时候的参数也就自然更新成用户最新输入的内容了。

这里进行观测viewModel的userItemViewModels,如果其发生了赋值改变,则进行reloadData,并关闭header和footer的刷新状态(这里下拉刷新和上拉加载更多采用MJRefresh),注意在更新UI之前需要先切换到主线程,RAC提供给了一个方便的方式deliverOn:[RACScheduler mainThreadScheduler]。绑定工作放在viewDidLoad里即可。
网络错误的信号是之前封装好的了,拿来直接用即可,封装的时候已经切换到主线程了,所以这里就不需要再管线程的事情了。

4.2 请求逻辑

我这里采用了xib,所以配置tableView单独写了一个方法,viewDidLoad中进行调用,如果使用代码初始化的话,直接把这些配置内容放到getter里就好了。

- (void)setupTableView {
    UINib *userNib = [UINib nibWithNibName:@"UserItemViewCell" bundle:nil];
    [self.tableView registerNib:userNib forCellReuseIdentifier:UserItemViewCellIdentifier];
    @weakify(self);
    self.tableView.header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{
        @strongify(self);
        [self.networkingRAC.refreshingCommand execute:nil];
}];
    self.tableView.footer = [MJRefreshAutoNormalFooter footerWithRefreshingBlock:^{
        @strongify(self);
        [self.networkingRAC.requestNextPageCommand execute:nil];
}];
}

我们将网络请求的RAC操作进行了抽离,viewModel也实现了YLNetworkingListRACProtocol协议,所以这里调起网络请求就是这个样子[self.networkingRAC.refreshingCommand execute:nil];,Controller是无权直接使用APIManager的,防止逻辑发生混乱,职责分明。

另外我们也需要在viewDidLoad里,将Button的点击事件与搜索关联起来
self.operationButton.rac_command = self.viewModel.networkingRAC.refreshCommand;

MJRefresh本身是不支持RACCommand的,它只支持Target-Action或者Block,每次都要写成上面那么多行,而且每次都一样。算了,自己动手稍微封装一下,用起来方便一些。

//  MJRefresh+ReactiveExtension.h
#import "MJRefresh.h"
#import <ReactiveCocoa/ReactiveCocoa.h>
@interface MJRefreshHeader (ReactiveExtension)
+ (instancetype)headerWithRefreshingCommand:(RACCommand *)refreshingCommand;

@end

@interface MJRefreshFooter(ReactiveExtension)
+ (instancetype)footerWithRefreshingCommand:(RACCommand *)refreshingCommand;
@end
//  MJRefresh+ReactiveExtension.m
#import "MJRefresh+ReactiveExtension.h"
@implementation MJRefreshHeader (ReactiveExtension)
+ (instancetype)headerWithRefreshingCommand:(RACCommand *)refreshingCommand {
    @weakify(refreshingCommand);
    return [self headerWithRefreshingBlock:^{
        @strongify(refreshingCommand);
        [refreshingCommand execute:nil];
    }];
}
@end

@implementation MJRefreshFooter(ReactiveExtension)
+ (instancetype)footerWithRefreshingCommand:(RACCommand *)refreshingCommand {
    @weakify(refreshingCommand);
    return [self footerWithRefreshingBlock:^{
        @strongify(refreshingCommand);
        [refreshingCommand execute:nil];
    }];
}
@end

这样封装一来,setupTableView就变成了这个样子,

- (void)setupTableView {
    UINib *userNib = [UINib nibWithNibName:@"UserItemViewCell" bundle:nil];
    [self.tableView registerNib:userNib forCellReuseIdentifier:UserItemViewCellIdentifier];
    self.tableView.header = [MJRefreshNormalHeader headerWithRefreshingCommand:self.viewModel.networkingRAC.refreshCommand];
    self.tableView.footer = [MJRefreshAutoNormalFooter footerWithRefreshingCommand:self.viewModel.networkingRAC.requestNextPageCommand];
}

嗯,这下子看起来舒服多了。

4.3 Delegate && DataSource

由于viewModel把数据处理都抢走了,所以这里的逻辑被削减的尤为简单。

#pragma mark - UITableViewDelegate && UITableViewDataSource

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UserItemViewCell *cell = [tableView dequeueReusableCellWithIdentifier:UserItemViewCellIdentifier
                                                            forIndexPath:indexPath];
    cell.viewModel = self.viewModel.userItemViewModels[indexPath.row];
    return cell;
}

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

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
    // 跳转页面逻辑
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return UserItemViewCellHeight;
}

至此,实践的Demo到此结束,完整的Demo在这里。
MVVM让各个模块权责分明,很容易理解,对于稍微复杂的项目明显更易于维护一些。但是RAC就显得不那么直白,刚学RAC会看起来很复杂,需要区分热信号和冷信号,而且还经常需要考虑带来的副作用。
RAC坑很深,MVVM的路还远,任重而道远!

iOS MVVM+RAC:从框架到实战 通过合理运用MVVM+RAC,我们可以更好地组织代码、简化数据绑定和响应式编程,并提高应用程序的可读性、可维护性和可测试性。MVVM+RAC能够提高代码的可读性、可维护性和可测试性,使开发者能够更好地处理用户界面和数据的交互。在View中创建相应的控件,并通过RAC提供的方法将控件和ViewModel中的属性进行绑定。在View中,我们将控件和ViewModel的属性进行绑定,实现了数据的自动更新和事件的处理。通过良好的架构设计和合理的代码组织,我们可以实现可扩展、可维护和高效的iOS应用程序。 阅读详情

相关推荐

iOS MVVM(Model-View-ViewModel) 1、 数据绑定的实现方式(KVO、block、Delegate、Notification、RAC)2、RAC的信号机制

前言前期知识贮备 数据绑定的实现方式(KVO、block、Delegate、Notification、RAC) 如何下载和安装CocoaPods 编程思想 ReactiveCocoa RAC主要解决了三个问题: 传统iOS开发过程中,状态以及状态之间依赖过多的问题 传统MVC架构的问题:Controller比较复杂,可测试性差 提供统一的消息传递机制。参考资料: MVVMReactiveCocoa

专注于计算机研发知识和资讯分享 1万+

MVVM+RAC总结

目录 一、什么是MVVM 二、为什么使用MVVM 三、RAC 3.1 RAC的用法 四、RAC与MVVM架构设计的优点 五、MVVM + RAC 5.1 MVVM使用指南 5.2 RAC坑 一、什么是MVVM MVVM(Model - View/ViewController - ViewModel)是对MVC的一种变形设计模式,解决ViewController代码臃肿、View...

ivolcano的博客 3000

RAC+MVVM项目实践Demo(添加购物车)

里面包含两个项目,具体查看readme文件,需要在运行时切换当前项目

通俗易懂图解MVVM和RAC双向绑定介绍(附Demo)

前言 一个前辈的MVVM介绍 其实MVVM就是MVC的进化版本,相对于臃肿的Controller,代码越来越多之后,有一部分人就用了新的设计模式,其实看久了也没什么,通俗点讲,其实就是把之前Controller里面的代码逻辑全部移植到了ViewModel里面,相对于以前而言,控制器也被归属于View一类,那么他和View一样都会有自己的ViewModel去处理逻辑,而且ViewModel必然拥...

Deft_MKJing的博客 1万+

MVVM + RAC框架

MVVM + RAC框架ViewModel: 相比较于MVC新引入的视图模型。是视图显示逻辑、验证逻辑、网络请求等代码存放的地方,唯一要注意的是,任何视图本身的引用都不应该放在VM中,换句话说就是VM中不要引入UIKit.h (对于image这个,也有人将其看做数据来处理,这就看个人想法了,并不影响整体的架构)。 这样,首先解决了VC臃肿的问题,将逻辑代码、网络请求等都写入了VM中,然后又由于VM中包含了所有的展示逻辑而且不会引用V,所以它是可以通过编程充分测试的。

MVVM+RAC Demo

一个MVVM+RAC开发的Demo,里面注视清晰,代码比较整齐,很适合初学者或者有一定工作经验的iOS程序员,在平时工作中也可以参照这种模式写出高质量代码

ReactiveCocoa (RAC) 函数响应式编程框架的原理以及配合MVVM设计模式的使用

ReactiveCocoa是一个基于响应式编程思想的库,它允许开发者通过使用信号(Signal)和订阅(Subscription)的方式来处理异步事件和数据流。它的核心概念包括信号、操作符、订阅和调度器,这些组合在一起使开发者能够更容易地处理异步操作和事件处理。

good7ob的博客 1281

RAC+MVVM+路由

MVVM+Objection路由框架

iOS MVVM+RAC 从框架到实战

https://www.jianshu.com/p/3beb21d5def2

humiaor的博客 2080

MVVM+rac简单实现

作者sallenhandong,源码MVVM-RACDemo,MVVM+rac简单的学习 框架以MVVM为基础 RAC正在循序渐进的运用进来,MVVM+rac简单的学习 框架以MVVM为基础 RAC正在循序渐进的运用进来 后面学到的 会慢慢加进来 项目框架 如图所示 。

apm软件仿真+QGC地面站 环境搭建

本教程使用场景:apm软件仿真运行于虚拟机 ubuntu环境。qgc地面站位于windows 系统。两个环境在同一台电脑上。 一.apm仿真环境搭建 1.安装vm虚拟机及ubuntu 18。 2.ubuntu下 下载Ardupilot 飞控源码 并配置环境。 下载源码: git clone https://github.com/ArduPilot/ardupilot cd ardupilot git submodule update --init --recursive 配置所需运行的环境:

qthello 6110

PIC18F87J11与PJ85718DM的嵌入式HVAC双点测温方案

温度监测是嵌入式系统与HVAC领域的核心功能,常需同时检测本地板温和远端风道、机柜温度。利用8位单片机内置12位ADC与I2C接口,搭配数字温度传感器和远程NTC探头,可构建双点测温架构。数字传感器出厂校准、I2C传输抗干扰较强,NTC分压结合B值公式换算灵活,两者互补满足不同线长和精度要求。该方案成本低、开发周期短,适用于温控器、机柜监控、设备状态监测等场景。围绕PIC18F87J11与PJ85718DM,文章完整覆盖选型、硬件设计、软件换算到现场联调排错,为工程实践提供直接参考。

weixin_34326429的博客 501

卡诺图化简法注意事项+竞争冒险知识点总结

今天反思以下卡诺图化简法中的注意事项。 卡诺图看起来简单,但如果不熟悉的话很容易出错,因此要对画圈的规则比较熟悉。

weixin_42415266的博客 1万+

干货集中营 ReactiveCocoa+RXSwift+MVVM

原文地址: 传送门简书只做同步更新功能 学习函数响应式编程已经接近两个月的时间。说实话坚持下来实在不易。两个月的时间看过近150篇博文,算下来啃下来一本千页的技术书籍也差不多。不过随着知识面的拓广,学习起来也更加顺利。本篇文章主要整理下自己收集的学习路线。其中包括了函数式编程的思想,ReactiveCocoa2.x(主要是Objective-C部分的函数响应式编程框架),ReactiveCoc...

weixin_33910137的博客 286

波束管理 Beam Management

Beam Management in 5G NR   波束管理,是5G NR中基于信道质量来动态选择每个UE和gNB之间以什么方向和频率的波束beam来进行通信。   背景   5G NR(New Radio)支持非常高的数据速率和更低的延迟。5G NR支持FR1和FR2频段,FR1为亚6 GHz(450至6000 MHz);FR2为毫米波段(24.25 GHz至52.6 GHz)。   由于毫米波频带使用非常高的频率,因此会导致传播损耗和其他损耗。为了补偿损失,在这种频率下定向通信是必不可少的。

最忆是江南的博客 5826

基于Simulink的IEEE33节点配电网仿真实战:从建模到分布式能源集成

本文详细介绍了基于Simulink的IEEE33节点配电网仿真实战,从基础建模到分布式能源集成。通过MATLAB脚本管理参数、搭建Simulink模块,并集成风机和光伏系统,实现高效配电网仿真。文章还涵盖潮流计算、故障分析及性能优化技巧,为电力系统仿真提供实用指导。

git9versioner的博客 990

ios mvvm框架的封装_iOS MVVM+RAC 从框架到实战

一、前言很早之前就想写写自己在架构模式方面的心得,但是一直感觉自己是井底之蛙,毕竟在iOS领域越深入越感到自己的无知,心中有着敬畏之心,就更没有自信去写这个东西(你也可以理解是没时间(>﹏<),请原谅我的装逼,嘿嘿).对于架构模式这个让人又爱又恨的玩意,说来其实简单,但一千个人眼中就有一千种哈姆雷特,说他千变万化确实是事实,而且当你深入其中的时候你真的会上瘾,并乐此不疲!前几天自己写的一篇《iOS...

weixin_42220853的博客 1082

《AgentScope-Java 深入浅出教程》第8章 工具高级特性

掌握工具组、预设参数、执行上下文等高级特性。

步子哥的博客 265

【亲测免费】 iOS开发中的新星:MVVM + RAC 框架应用 —— MVVM-RAC-DEMO

iOS开发中的新星:MVVM + RAC 框架应用 —— MVVM-RAC-DEMO 1、项目介绍 在iOS开发中,我们不断寻求更加高效和灵活的设计模式。MVVM-RAC-DEMO是一个开放源码的项目,它展示了如何使用现代编程实践,如Model-View-ViewModel (MVVM) 结合 ReactiveCocoa (RAC) 来构建一个功能完备的应用程序。这个项目不仅实现了常见的上拉加载与...

gitblog_00084的博客 617

『杭电1199』Color the Ball

Problem Description There are infinite balls in a line (numbered 1 2 3 ....), and initially all of them are paint black. Now Jim use a brush paint the balls, every time give two integers a b and follow by a char 'w' or 'b', 'w' denotes the ball from a to

漠宸离若的博客 497

大模型风电功率预测:短期,超短期,中长期的完整实现与代码详解

本文全面介绍了基于深度学习大模型的风电功率预测方法,涵盖超短期(15分钟-1小时)、短期(1-6小时)和中长期(1天-1周)三种时间尺度。文章详细阐述了数据准备与特征工程,包括数据收集、预处理和可视化分析。针对不同时间尺度,分别介绍了Temporal Fusion Transformer (TFT)、Informer和N-BEATS模型的构建、训练与评估方法,并提供了完整的开源代码实现。此外,文章还探讨了模型部署与生产环境集成,包括模型保存与加载、实时预测API以及模型监控与再训练。最后,文章总结了关键创新

专注AI大模型,软件混淆,授权 1888

MVVM和RAC介绍

一、ReactiveCocoa RAC完全颠覆了传统的开发模式,使消息传递回调等机制复杂问题简单化,初始化与回调放在一起,使整个逻辑很具条理化。ReactiveCocoa结合了一些编程模式: 1.函数式编程:利用高阶函数,即将函数作为其它函数的参数。 2.响应式编程:关注于数据流及变化的传播。 基于以上两点,ReactiveCocoa被当成是函数响应编程(Functional Reactiv

621

LVGL hal disp(porting display)

LVGL本身是没有对接最终的显示框架的,所以到具体的某个平台上,需要自行porting。

Bigan(安)的博客 2097

RAC + MVVM原理及实例详解

尝试新的架构当然不会从老的项目中直接修改,这样风险太大,所以我决定单独写一个小的Demo,这个本来是封装好的网络库,Demo就直接放到这里面了。用小Demo来尝试新的架构设计,然后再在原工程上逐渐引入新的架构。 Demo是实现一个豆瓣用户的搜索功能,Demo的最终效果图是这样的: Demo的完整架构如下: 橙色表示操作、绿色虚线表示数据的流动 1. 定义Model 根

csdn_wangxh的博客 1144

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

上一篇: ApplicationLoader登录失败
下一篇: RAC + MVVM 1
「已注销」
博客等级 码龄11年 10粉丝 12原创
评论 4
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值