使用ReactiveCocoa实现iOS平台响应式编程

2023-11-19

使用ReactiveCocoa实现iOS平台响应式编程

 TIGER | IOS |  10

使用ReactiveCocoa实现iOS平台响应式编程

ReactiveCocoa和响应式编程

在说ReactiveCocoa之前,先要介绍一下FRP(Functional Reactive Programming,响应式编程),在维基百科中有这样一个例子介绍:

在命令式编程环境中,a = b + c 表示将表达式的结果赋给a,而之后改变b或c的值不会影响a。但在响应式编程中,a的值会随着b或c的更新而更新。

Excel就是响应式编程的一个例子。单元格可以包含字面值或类似”=B1+C1″的公式,而包含公式的单元格的值会依据其他单元格的值的变化而变化 。

而ReactiveCocoa简称RAC,就是基于响应式编程思想的Objective-C实践,它是Github的一个开源项目,你可以在这里找到它。

关于FRP和ReactiveCocoa可以去看leezhong的这篇blog,图文并茂,讲的很好。

ReactiveCocoa框架概览

先来看一下leezhong再博文中提到的比喻,让你对有个ReactiveCocoa很好的理解:

可以把信号想象成水龙头,只不过里面不是水,而是玻璃球(value),直径跟水管的内径一样,这样就能保证玻璃球是依次排列,不会出现并排的情况(数据都是线性处理的,不会出现并发情况)。水龙头的开关默认是关的,除非有了接收方(subscriber),才会打开。这样只要有新的玻璃球进来,就会自动传送给接收方。可以在水龙头上加一个过滤嘴(filter),不符合的不让通过,也可以加一个改动装置,把球改变成符合自己的需求(map)。也可以把多个水龙头合并成一个新的水龙头(combineLatest:reduce:),这样只要其中的一个水龙头有玻璃球出来,这个新合并的水龙头就会得到这个球。

下面我来逐一介绍ReactiveCocoa框架的每个组件

Streams

Streams 表现为RACStream类,可以看做是水管里面流动的一系列玻璃球,它们有顺序的依次通过,在第一个玻璃球没有到达之前,你没法获得第二个玻璃球。
RACStream描述的就是这种线性流动玻璃球的形态,比较抽象,它本身的使用意义并不很大,一般会以signals或者sequences等这些更高层次的表现形态代替。

Signals

Signals 表现为RACSignal类,就是前面提到水龙头,ReactiveCocoa的核心概念就是Signal,它一般表示未来要到达的值,想象玻璃球一个个从水龙头里出来,只有了接收方(subscriber)才能获取到这些玻璃球(value)。

Signal会发送下面三种事件给它的接受方(subscriber),想象成水龙头有个指示灯来汇报它的工作状态,接受方通过-subscribeNext:error:completed:对不同事件作出相应反应

  • next 从水龙头里流出的新玻璃球(value)
  • error 获取新的玻璃球发生了错误,一般要发送一个NSError对象,表明哪里错了
  • completed 全部玻璃球已经顺利抵达,没有更多的玻璃球加入了

一个生命周期的Signal可以发送任意多个“next”事件,和一个“error”或者“completed”事件(当然“error”和“completed”只可能出现一种)

Subjects

subjects 表现为RACSubject类,可以认为是“可变的(mutable)”信号/自定义信号,它是嫁接非RAC代码到Signals世界的桥梁,很有用。嗯。。。 这样讲还是很抽象,举个例子吧:

1
2
3
RACSubject * letters = [ RACSubject subject ] ;
RACSignal * signal = [ letters sendNext : @ "a" ] ;
 

可以看到@"a"只是一个NSString对象,要想在水管里顺利流动,就要借RACSubject的力。

Commands

command 表现为RACCommand类,偷个懒直接举个例子吧,比如一个简单的注册界面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
     RACSignal * formValid = [ RACSignal
         combineLatest : @ [
             self . userNameField . rac_textSignal ,
             self . emailField . rac_textSignal ,
         ]
         reduce : ^ ( NSString * userName , NSString * email ) {
             return @ ( userName . length & gt ; 0
                     & amp ; & amp ; email . length & gt ; 0 ) ;
         } ] ;
 
   RACCommand * createAccountCommand = [ RACCommand commandWithCanExecuteSignal : formValid ] ;
   RACSignal * networkResults = [ [ [ createAccountCommand
       addSignalBlock : ^ RACSignal * ( id value ) {
           //... 网络交互代码
       } ]
       switchToLatest ]
       deliverOn : [ RACScheduler mainThreadScheduler ] ] ;
 
   // 绑定创建按钮的 UI state 和点击事件
     [ [ self . createButton rac_signalForControlEvents : UIControlEventTouchUpInside ] executeCommand : createAccountCommand ] ;
 

Sequences

sequence 表现为RACSequence类,可以简单看做是RAC世界的NSArray,RAC增加了-rac_sequence方法,可以使诸如NSArray这些集合类(collection classes)直接转换为RACSequence来使用。

Schedulers

scheduler 表现为RACScheduler类,类似于GCD,but schedulers support cancellationbut schedulers support cancellation, and always execute serially.

ReactiveCocoa的简单使用

实践出真知,下面就举一些简单的例子,一起看看RAC的使用

Subscription

接收 -subscribeNext: -subscribeError: -subscribeCompleted:

1
2
3
4
5
6
7
RACSignal * letters = [ @ "A B C D E F G H I" componentsSeparatedByString : @ " " ] . rac_sequence . signal ;
 
// 依次输出 A B C D…
[ letters subscribeNext : ^ ( NSString * x ) {
     NSLog ( @ "%@" , x ) ;
} ] ;
 

Injecting effects

注入效果 -doNext: -doError: -doCompleted:,看下面注释应该就明白了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
__block unsigned subscriptions = 0 ;
 
RACSignal * loggingSignal = [ RACSignal createSignal : ^ RACDisposable * ( id & lt ; RACSubscriber & gt ; subscriber ) {
     subscriptions ++ ;
     [ subscriber sendCompleted ] ;
     return nil ;
} ] ;
 
// 不会输出任何东西
loggingSignal = [ loggingSignal doCompleted : ^ {
     NSLog ( @ "about to complete subscription %u" , subscriptions ) ;
} ] ;
 
// 输出:
// about to complete subscription 1
// subscription 1
[ loggingSignal subscribeCompleted : ^ {
     NSLog ( @ "subscription %u" , subscriptions ) ;
} ] ;
 

Mapping

-map: 映射,可以看做对玻璃球的变换、重新组装

1
2
3
4
5
6
7
RACSequence * letters = [ @ "A B C D E F G H I" componentsSeparatedByString : @ " " ] . rac_sequence ;
 
// Contains: AA BB CC DD EE FF GG HH II
RACSequence * mapped = [ letters map : ^ ( NSString * value ) {
     return [ value stringByAppendingString : value ] ;
} ] ;
 

Filtering

-filter: 过滤,不符合要求的玻璃球不允许通过

1
2
3
4
5
6
7
RACSequence * numbers = [ @ "1 2 3 4 5 6 7 8 9" componentsSeparatedByString : @ " " ] . rac_sequence ;
 
// Contains: 2 4 6 8
RACSequence * filtered = [ numbers filter : ^ BOOL ( NSString * value ) {
     return ( value . intValue % 2 ) == 0 ;
} ] ;
 

Concatenating

-concat: 把一个水管拼接到另一个水管之后

1
2
3
4
5
6
RACSequence * letters = [ @ "A B C D E F G H I" componentsSeparatedByString : @ " " ] . rac_sequence ;
RACSequence * numbers = [ @ "1 2 3 4 5 6 7 8 9" componentsSeparatedByString : @ " " ] . rac_sequence ;
 
// Contains: A B C D E F G H I 1 2 3 4 5 6 7 8 9
RACSequence * concatenated = [ letters concat : numbers ] ;
 

Flattening

-flatten:

Sequences are concatenated

1
2
3
4
5
6
7
RACSequence * letters = [ @ "A B C D E F G H I" componentsSeparatedByString : @ " " ] . rac_sequence ;
RACSequence * numbers = [ @ "1 2 3 4 5 6 7 8 9" componentsSeparatedByString : @ " " ] . rac_sequence ;
RACSequence * sequenceOfSequences = @ [ letters , numbers ] . rac_sequence ;
 
// Contains: A B C D E F G H I 1 2 3 4 5 6 7 8 9
RACSequence * flattened = [ sequenceOfSequences flatten ] ;
 

Signals are merged (merge可以理解成把几个水管的龙头合并成一个,哪个水管中的玻璃球哪个先到先吐哪个玻璃球)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
RACSubject * letters = [ RACSubject subject ] ;
RACSubject * numbers = [ RACSubject subject ] ;
RACSignal * signalOfSignals = [ RACSignal createSignal : ^ RACDisposable * ( id & lt ; RACSubscriber & gt ; subscriber ) {
     [ subscriber sendNext : letters ] ;
     [ subscriber sendNext : numbers ] ;
     [ subscriber sendCompleted ] ;
     return nil ;
} ] ;
 
RACSignal * flattened = [ signalOfSignals flatten ] ;
 
// Outputs: A 1 B C 2
[ flattened subscribeNext : ^ ( NSString * x ) {
     NSLog ( @ "%@" , x ) ;
} ] ;
 
[ letters sendNext : @ "A" ] ;
[ numbers sendNext : @ "1" ] ;
[ letters sendNext : @ "B" ] ;
[ letters sendNext : @ "C" ] ;
[ numbers sendNext : @ "2" ] ;
 

Mapping and flattening

-flattenMap: 先 map 再 flatten

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
RACSequence * numbers = [ @ "1 2 3 4 5 6 7 8 9" componentsSeparatedByString : @ " " ] . rac_sequence ;
 
// Contains: 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9
RACSequence * extended = [ numbers flattenMap : ^ ( NSString * num ) {
     return @ [ num , num ] . rac_sequence ;
} ] ;
 
// Contains: 1_ 3_ 5_ 7_ 9_
RACSequence * edited = [ numbers flattenMap : ^ ( NSString * num ) {
     if ( num . intValue % 2 == 0 ) {
         return [ RACSequence empty ] ;
     } else {
         NSString * newNum = [ num stringByAppendingString : @ "_" ] ;
         return [ RACSequence return : newNum ] ;
     }
} ] ;
 
 
 
 
RACSignal * letters = [ @ "A B C D E F G H I" componentsSeparatedByString : @ " " ] . rac_sequence . signal ;
 
[ [ letters
     flattenMap : ^ ( NSString * letter ) {
         return [ database saveEntriesForLetter : letter ] ;
     } ]
     subscribeCompleted : ^ {
         NSLog ( @ "All database entries saved successfully." ) ;
     } ] ;
 

Sequencing

-then:

1
2
3
4
5
6
7
8
9
10
11
12
13
RACSignal * letters = [ @ "A B C D E F G H I" componentsSeparatedByString : @ " " ] . rac_sequence . signal ;
 
// 新水龙头只包含: 1 2 3 4 5 6 7 8 9
//
// 但当有接收时,仍会执行旧水龙头doNext的内容,所以也会输出 A B C D E F G H I
RACSignal * sequenced = [ [ letters
     doNext : ^ ( NSString * letter ) {
         NSLog ( @ "%@" , letter ) ;
     } ]
     then : ^ {
         return [ @ "1 2 3 4 5 6 7 8 9" componentsSeparatedByString : @ " " ] . rac_sequence . signal ;
     } ] ;
 

Merging

+merge: 前面在flatten中提到的水龙头的合并

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
RACSubject * letters = [ RACSubject subject ] ;
RACSubject * numbers = [ RACSubject subject ] ;
RACSignal * merged = [ RACSignal merge : @ [ letters , numbers ] ] ;
 
// Outputs: A 1 B C 2
[ merged subscribeNext : ^ ( NSString * x ) {
     NSLog ( @ "%@" , x ) ;
} ] ;
 
[ letters sendNext : @ "A" ] ;
[ numbers sendNext : @ "1" ] ;
[ letters sendNext : @ "B" ] ;
[ letters sendNext : @ "C" ] ;
[ numbers sendNext : @ "2" ] ;
 

Combining latest values

+combineLatest: 任何时刻取每个水龙头吐出的最新的那个玻璃球

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
RACSubject * letters = [ RACSubject subject ] ;
RACSubject * numbers = [ RACSubject subject ] ;
RACSignal * combined = [ RACSignal
     combineLatest : @ [ letters , numbers ]
     reduce : ^ ( NSString * letter , NSString * number ) {
         return [ letter stringByAppendingString : number ] ;
     } ] ;
 
// Outputs: B1 B2 C2 C3
[ combined subscribeNext : ^ ( id x ) {
     NSLog ( @ "%@" , x ) ;
} ] ;
 
[ letters sendNext : @ "A" ] ;
[ letters sendNext : @ "B" ] ;
[ numbers sendNext : @ "1" ] ;
[ numbers sendNext : @ "2" ] ;
[ letters sendNext : @ "C" ] ;
[ numbers sendNext : @ "3" ] ;
 

Switching

-switchToLatest: 取指定的那个水龙头的吐出的最新玻璃球

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
RACSubject * letters = [ RACSubject subject ] ;
RACSubject * numbers = [ RACSubject subject ] ;
RACSubject * signalOfSignals = [ RACSubject subject ] ;
 
RACSignal * switched = [ signalOfSignals switchToLatest ] ;
 
// Outputs: A B 1 D
[ switched subscribeNext : ^ ( NSString * x ) {
     NSLog ( @ "%@" , x ) ;
} ] ;
 
[ signalOfSignals sendNext : letters ] ;
[ letters sendNext : @ "A" ] ;
[ letters sendNext : @ "B" ] ;
 
[ signalOfSignals sendNext : numbers ] ;
[ letters sendNext : @ "C" ] ;
[ numbers sendNext : @ "1" ] ;
 
[ signalOfSignals sendNext : letters ] ;
[ numbers sendNext : @ "2" ] ;
[ letters sendNext : @ "D" ] ;
 

常用宏
RAC 可以看作某个属性的值与一些信号的联动

1
2
3
4
RAC ( self . submitButton . enabled ) = [ RACSignal combineLatest : @ [ self . usernameField . rac_textSignal , self . passwordField . rac_textSignal ] reduce : ^ id ( NSString * userName , NSString * password ) {
     return @ ( userName . length & gt ; = 6 & amp ; & amp ; password . length & gt ; = 6 ) ;
} ] ;
 

RACObserve 监听属性的改变,使用block的KVO

1
2
3
4
[ RACObserve ( self . textField , text ) subscribeNext : ^ ( NSString * newName ) {
     NSLog ( @ "%@" , newName ) ;
} ] ;
 

UI Event

RAC为系统UI提供了很多category,非常棒,比如UITextView、UITextField文本框的改动rac_textSignal,UIButton的的按下rac_command等等。

最后

有了RAC,可以不用去操心值什么时候到达什么时候改变,只需要简单的进行数据来了之后的步骤就可以了。

说了这么多,在回过头去看leezhong的比喻该文最后总结的关系图,再好好梳理一下吧。我也是初学者,诚惶诚恐的呈上这篇博文,欢迎讨论,如有不正之处欢迎批评指正。

参考

https://github.com/ReactiveCocoa/ReactiveCocoa/blob/master/Documentation/FrameworkOverview.mdhttps://github.com/ReactiveCocoa/ReactiveCocoa/blob/master/Documentation/BasicOperators.md
http://vimeo.com/65637501
http://iiiyu.com/2013/09/11/learning-ios-notes-twenty-eight/
http://blog.leezhong.com/ios/2013/06/19/frp-reactivecocoa.html http://nshipster.com/reactivecocoa/

iOSReactiveCocoa

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用ReactiveCocoa实现iOS平台响应式编程 的相关文章

  • 是否可以使用 Firebase 安排推送通知? [复制]

    这个问题在这里已经有答案了 我已经阅读了我能找到的所有文档 但仍然不知道这是否可行 如果我是用户 我可以安排特定时间的推送通知吗 Example 1 我是用户并打开应用程序 2 我允许通知并转到 pickerView 或其他任何内容 并设置
  • 在 Xcode 5 中重命名 iOS 项目[重复]

    这个问题在这里已经有答案了 我需要重命名一个 iOS 项目 有没有办法在不开始一个全新项目的情况下做到这一点 我发现的所有其他信息都与 Xcode 4 或旧版本相关 这些方法似乎使项目崩溃 我在尝试任何名称更改之前创建了一个快照 在 Xco
  • 如何使用 Swift 使用 TouchID?

    Apple 为 iOS 8 的 TouchID 实现提供的文档采用 Objective C 语言 有 Swift 版本吗 Objective C IBAction touchIDAvailable UIButton touchIDAvail
  • Firebase 身份验证问题 - 通过电子邮件地址检查用户是否存在

    我在 Firebase 上创建了一个帐户 它有效 但现在我想阻止人们使用已存在的电子邮件地址创建帐户 这是代码 DatabaseManager shared userExists with email completion weak sel
  • 减少 CoreData 的调试输出?

    我正在开发一个使用 CoreData 的 iOS macOS 项目 它工作正常 但它会向控制台输出大量调试信息 这使得控制台无法使用 因为我的打印语句隐藏在所有与 CoreData 相关的内容中 我有一个非常简单的 CoreData 设置
  • ios水平居中约束问题?

    I am having hard time in learning constraints auto layout in iOS I have used any width any height I have a storyboard sc
  • 根据 iOS 版本使用不同的类实现?

    iOS 11 最近添加了一个我想使用的新功能 但我仍然需要支持旧版本的 iOS 有没有一种方法可以将同一个类编写两次 并让较新版本的 iOS 使用该类的一个版本 而旧版本的 iOS 使用另一个版本 注 最初我用的是if available
  • UIView晃动动画

    我试图在按下按钮时使 UIView 摇动 我正在调整我找到的代码http www cimgf com 2008 02 27 core animation tutorial window shake effect http www cimgf
  • 将 UIToolBar 添加到所有键盘(swift)

    我正在尝试以尽可能少的重复次数将自定义 UIToolBar 添加到我的所有键盘中 我目前的做法要求我将代码添加到所有 viewDidLoads 中 并将每个文本字段的委托分配给我正在使用的 viewController 我尝试创建自己的 U
  • 如何使用 CNContacts 快速获取手机号码?

    我有一些代码可以检索用户联系人中的所有电话号码 但只想过滤掉手机号码 目前 我只是通过将第一个数字为 或第二个数字为 7 的数字添加到数组中来实现此目的 如下所示 func findContacts gt CNContact let key
  • 错误消息:您输入的捆绑包 ID 已被使用

    我正在尝试发布一个 iPhone 应用程序 这不是第一个 我过去已经发表过其他的 因此 我在第一个和第二个表单中输入了所需的信息 然后填写了第三个大表单 您还可以在其中上传图标和屏幕截图 好吧 我在上传屏幕截图之前按下了 保存 按钮 因为我
  • BigQuery 未显示链接的 Firebase Analytics 事件日志的任何数据集

    我将我的帐户链接到 Big Query 但 Firebase Analytics 事件不会自动加载到 BigQuery 中 显示 未找到数据集 警告 我的工作进度附在下面 请查收 I have getting firebase Analyt
  • Swift:长按手势识别器 - 检测轻击和长按

    我想连接一个动作 如果手势是点击 它会以特定的方式为对象设置动画 但如果按下持续时间超过 0 5 秒 它会执行其他操作 现在 我刚刚连接了动画 我不知道如何区分长按和点击 如何访问新闻持续时间以实现上述目的 IBAction func ta
  • 在 WKWebView 中禁用缩放?

    有谁知道在 WKWebView 中禁用双击和捏缩放的简单方法 我尝试过的任何方法都不起作用 Webview scrollView allowsMagnification false Error value of type WKWebView
  • 未知异常和崩溃

    当我尝试快速滚动表格视图或从远程重新加载数据时 我的应用程序崩溃了 当我先进行远程获取然后滚动表格视图时 一切似乎都工作正常 我不知道下面的崩溃日志意味着什么 它只是有时工作正常 有时崩溃 Incident Identifier 710A1
  • AVAudioPlayer 无法从网站播放 m4a 或 mp3 文件类型

    我试图在我的应用程序中找到一个仅纯 m4a 声音的 URL 我有音频的 URL 理论上可以下载它 然后 使用下载的文件URL到声音 我尝试使用AVAudioPlayer播放它 但它不播放任何声音 这是我的代码 在 URL 检索函数中 我调用
  • 无法以编程方式快速设置 NSLayoutConstraint 乘数...“无法分配给此表达式的结果

    我试图以编程方式快速设置乘法器的约束 当我设置该值时 它只会给我错误 无法分配给该表达式的结果 我用 IBOutlet 声明了 NSLayoutConstraint 然后设置乘数 就像我对另一个常量所做的那样 效果很好 但这个不会接受它 I
  • 防止 iOS 键盘在 cordova 3.5 中滚动页面

    我正在使用 Cordova 3 5 和 jQuery mobile 构建 iOS 应用程序 我在大部分应用程序中禁用了滚动功能 但是 当我选择输入字段时 iOS 键盘会打开并向上滚动页面 我不想要这个功能 由于输入足够高 键盘不会覆盖它 我
  • Mac 上的 Delphi - 可能吗? [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我负责一个 Delphi Win32 项目管理应用程序 我刚刚完成了向 Delphi 2009 的迁移
  • 所有 RestKit 项目在归档时都无法构建

    这个问题涉及RESTKIT 0 9 x 如果您是 Restkit 新手 请考虑使用较新的版本0 10 x https github com RestKit RestKit tree v0 10 1 branch 我最近继承了一个项目 使用r

随机推荐

  • VSCode关闭vue语法检查

    今天碰到一个这样的错误 Component name School should always be multi word 意思是组件名称 School 应该总是多个单词 解决办法 在vue config js中添加这样一句代码 lintO
  • QT实现动态翻译和语言切换

    QT GUI提供语言动态转换机制并辅以相应的工具方便programmer实现界面的多语言实时动态切换功能 实现语言动态切换的方法 一个注意 五个步骤 一个注意 实现QT工程的语言切换功能的一个关键点是所有的字符串都需要tr修饰符 例如 m
  • 【数据结构初阶】第七节.树和二叉树的基本操作

    作者简介 大家好 我是未央 博客首页 未央 303 系列专栏 Java初阶数据结构 每日一句 人的一生 可以有所作为的时机只有一次 那就是现在 文章目录 前言 一 二叉树的快速构建 二 二叉树的遍历 2 1 前序遍历 2 2 中序遍历 2
  • 从计数器到分频电路

    一 计数器 1 计数器代码 计数器 顾名思义就是在时钟的节拍下进行计数 一个简单的N位计数器的代码如下所示 这个计数器从0计数到2 N 1 共计数了2 N个数 也就是N位计数器 1 module count parameter N 8 2
  • 微信小程序登录弹框问题

    1 getUserInfo 相信刚接触微信小程序开发的人都在想 官方给出的这个是什么意思 我来解释一下吧 还记得我们在最开始使用微信小程序的时候吗 第一次进一个微信小程序的时候会直接弹出来个框 询问我们是否允许哟用户获取信息 微信官方觉得这
  • C++11 之 std::function & std::bind & lambda 表达式

    文章目录 std function std bind lambda 表达式 总结 c 11新增了 std function std bind lambda 表达式等封装使函数调用更加方便 std function 讲 std functio
  • 生活之你为什么不学习

    最近在别人的空间 我看到了八句话 你有什么理由不学习 感觉说得挺有鸡血的 1 你不能把这个世界让给你所鄙视的人 2 成功的速度一定要超过父母老去的速度 3 可怕的不是别人比你优秀 而是比你优秀的人比你还努力 4 我努力的目的是让我的妈妈买东
  • 【华为OD机试python】按身高和体重排队【2023 B卷

    华为OD机试 真题 点这里 华为OD机试 真题考点分类 点这里 题目描述 某学校举行运动会 学生们按编号 1 2 3 n 进行标识 现需要按照身高由低到高排列 对身高相同的人 按体重由轻到重排列 对于身高体重都相同的人 维持原有的编号顺序关
  • 最全的交叉编译Makefile讲解

    最近正在搞交叉编译 参考很多博客 学习了一下Makefile的编写 记录一下Makefile内代码是什么意思 代码如下 简单的hello ko的makefile ifneq KERNELRELEASE obj m hello o else
  • [CUDA] 快速入门CUDA(1)-基本了解和HelloWorld

    CUDA基础 文章目录 CUDA基础 1 CUDA简介 2 GPU和CPU架构的不同之处 3 查看GPU硬件信息 4 需要建立的基本概念 5 总结 1 CUDA简介 CUDA的全程是Computer Unified Device Archi
  • 树莓派4B(buster)的源更换为北外(清华)国内源

    树莓派4B buster 的源更换为北外 清华 国内源 1 登陆到树莓派 ssh pi your raspi IP 2 备份源文件 sudo cp etc apt sources list etc apt sources list bak
  • GoogLeNet论文详解

    GoogLeNet 1 Introduction 得益于深度学习的优势和更强大的卷积神经网络的出现 图像分类和目标检测的准确率发生了令人意想不到的进步 在2014年的ILSVRC比赛中 GoogLeNet取得了第一名的成绩 所用模型参数不足
  • 详解如何修改Linux文件权限

    参考 详解如何修改Linux文件权限 Linux文件权限详解 在Linux系统中 可以使用chmod命令来修改文件的权限 该命令用于更改文件或目录的读取 r 写入 w 和执行 x 权限 以下是一些详细的说明和示例 使用数字表示权限 r 读取
  • Golang教程:(十六)结构体

    原文 https golangbot com structs 欢迎来到Golang系列教程的第十六篇 什么是结构体 结构体 struct 是用户自定义的类型 它代表若干字段的集合 有些时候将多个数据看做一个整体要比单独使用这些数据更有意义
  • element el-table render-header自定义复选框

    项目中需要对列表数据进行批量处理 表头增加复选框 并关联列表数据 el table提供解决方法 实现多选非常简单 手动添加一个el table column 设type属性为selection即可 尝试后在我的项目中不适用 于是找到另一种r
  • Redis缓存与数据库双写一致性解决方案

    目录 1 冤孽的诞生 1 1 需求起因 1 2 策略之争 2 标准解决方案 2 1 延时双删策略 2 2 异步更新缓存 基于订阅binlog的同步机制 3 基于binlog订阅实现步骤 3 1 准备材料 3 2 代码实现 1 冤孽的诞生 1
  • python两个二维数组加法_python中利用numpy.array()实现俩个数值列表的对应相加方法...

    python中利用numpy array 实现俩个数值列表的对应相加方法 小编想把用python将列表 1 1 1 1 1 1 1 1 1 1 和 列表 2 2 2 2 2 2 2 2 2 2 对应相加成 3 3 3 3 3 3 3 3 3
  • [嵌入式linux]PCIe 热拔插(rescan)

    linux下可通过 sys bus pci devices 0000 bus number device number function number 目录下的节点进行热拔插操作 板子上电前PCIe插槽有一块NVME的固态硬盘 0 1985
  • SDIO接口协议(MMC SD WIFI GPS 以太网)

    一文搞懂SDIO 曼巴精神传承人的博客 CSDN博客 sdio SDIO协议 觅食小鱼的博客 CSDN博客 sdio协议 传统的SD存储卡只有一排引脚 包括一个3 3V电源VDD 用于默认速度
  • 使用ReactiveCocoa实现iOS平台响应式编程

    使用ReactiveCocoa实现iOS平台响应式编程 TIGER IOS 10 使用ReactiveCocoa实现iOS平台响应式编程 ReactiveCocoa和响应式编程 在说ReactiveCocoa之前 先要介绍一下FRP Fun