iOS學習筆記39-ReactiveCocoa入門

FRP,全稱為Functional Reactive Programming,是一種響應變化的編程范式,最近幾年比較火,大概的理解就像這樣:

?


當a的值或者b的值發生變化時,c的值會自動響應a的值或b的值變化的信號,自動更正自己的值,類似這種編程思想就稱為FRP。

FRP提供了一種信號機制來實現這樣的效果,通過信號來記錄值的變化。信號可以被疊加、分割或合并。通過對信號的組合,就不需要去監聽某個值或事件。

二、ReactiveCocoa介紹

ReactiveCocoa是github開源的一個第三方框架,是在iOS平臺上對FRP的實現。
FRP的核心是信號,信號在ReactiveCocoa(以下簡稱RAC)中是通過RACSignal來表示的,信號是數據流,可以被綁定和傳遞。

下面簡單介紹下RAC的幾個概念:
  1. Signal:信號管,可以想象成水龍頭
  2. Value:信號值,可以想象成玻璃球
    可以把信號管(Signal)想象成水龍頭,只不過里面不是水,而是玻璃球(Value),直徑跟水管的內徑一樣,這樣就能保證玻璃球是依次排列,不會出現并排的情況(數據都是線性處理的,不會出現并發情況)
  3. Subscriber:接受方,可以想象成水龍頭出水口
    水龍頭的開關默認是關的,除非有了接收方(Subscriber),才會打開。這樣只要有新的玻璃球進來,就會自動傳送給接收方。
  4. Filter:過濾器
    可以在水龍頭上加一個過濾嘴(Filter),不符合的不讓通過
  5. Map:改動器
    可以在水龍頭上加一個改動裝置(Map),把球改變成符合自己的需求

三、ReactiveCocoa框架各組件

1. RACStream類

水管里面流動的一系列玻璃球,它們有順序的依次通過,在第一個玻璃球沒有到達之前,你沒法獲得第二個玻璃球,RACStream描述的就是這種線性流動玻璃球的形態,比較抽象,是作為描述抽象的父類,它本身的使用意義并不很大,一般會以RACSignal或者RACSequence等這些更高層次的表現形態代替。

RACStream的功能總結看下圖:

?

2. RACSignal類

RAC的核心概念就是Signal,它一般表示未來要到達的值,想象玻璃球一個個從水龍頭里出來,只有了接收方才能獲取到這些玻璃球。
RACSignal會發送下面三種事件給它的接受方,想象成水龍頭有個指示燈來匯報它的工作狀態,接受方通過-subscribeNext:error:completed:對不同事件作出相應反應:

  1. Next:從水龍頭里流出的新玻璃球
  2. Error:獲取新的玻璃球發生了錯誤,一般要發送一個NSError對象,表明哪里錯了
  3. Completed:全部玻璃球已經順利抵達,沒有更多的玻璃球加入了

RACSignal可以發送任意多個Next事件,和一個Error或者Completed事件

?

3. RACSubject類

RACSubject類,可以認為是“可變的(Mutable)”信號/自定義信號,它是嫁接非RAC代碼到Signal世界的橋梁

?

4. RACCommand類

RACCommand類,可以認為是回應某些動作的信號,通常觸發該信號的動作都是UI控件

?

5. RACSequence類

RACSequence類,可以簡單看做是RAC世界的NSArray,RAC增加了-rac_sequence方法,可以使諸如NSArray這些集合類直接轉換為RACSequence來使用。

?

6. RACScheduler類

RACScheduler類,類似于GCD,但RACScheduler類支持撤銷,并且總是運行安全的。
RACScheduler是RAC里面對線程的簡單封裝,事件可以在指定的RACScheduler上分發和執行,不特殊指定的話,事件的分發和執行都在一個默認的后臺線程里面做,大多數情況也就不用動了。
有一些特殊的Signal必須在主線程調用,使用-deliverOn:可以切換調用的線程。

?

四、ReactiveCocoa簡單使用20例

1. 觀察值變化
你別動,你一動我就知道。
//當self.value的值變化時調用Block,這是用KVO的機制,RAC封裝了KVO
@weakify(self);
[RACObserve(self, value) subscribeNext:^(NSString* x) { @strongify(self); NSLog(@"你動了"); }];
2. 單邊響應
你唱歌,我就跳舞。
//創建一個信號
RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id subscriber) {//這個信號里面有一個Next事件的玻璃球和一個Complete事件的玻璃球[subscriber sendNext:@"唱歌"]; [subscriber sendCompleted]; return nil; }]; //對信號進行改進,當信號里面流的是”唱歌”,就改成”跳舞”返還給self.value RAC(self, value) = [signalA map:^id(NSString *value) { if ([value isEqualToString:@"唱歌"]) { return @"跳舞"; } return @""; }];
3. 雙邊響應
你向西,他就向東,他向左,你就向右。
//創建2個通道,一個從A流出的通道A和一個從B流出的通道B
RACChannelTerminal *channelA = RACChannelTo(self, valueA);
RACChannelTerminal *channelB = RACChannelTo(self, valueB);
//改造通道A,使通過通道A的值,如果等于"西",就改為"東"傳出去 [[channelA map:^id(NSString *value) { if ([value isEqualToString:@"西"]) { return @"東"; } return value; }] subscribe:channelB];//通道A流向B //改造通道B,使通過通道B的值,如果等于"左",就改為"右"傳出去 [[channelB map:^id(NSString *value) { if ([value isEqualToString:@"左"]) { return @"右"; } return value; }] subscribe:channelA];//通道B流向A //KVO監聽valueA的值得改變,過濾valueA的值,返回YES表示通過 [[RACObserve(self, valueA) filter:^BOOL(id value) { return value ? YES : NO; }] subscribeNext:^(NSString* x) { NSLog(@"你向%@", x); }]; //KVO監聽valueB的值得改變,過濾valueB的值,返回YES表示通過 [[RACObserve(self, valueB) filter:^BOOL(id value) { return value ? YES : NO; }] subscribeNext:^(NSString* x) { NSLog(@"他向%@", x); }]; //下面使valueA的值和valueB的值發生改變 self.valueA = @"西"; self.valueB = @"左";
幫助理解,我做了下面這個圖,①②③④是打印順序:

?

4. 代理
你是程序員,你幫我寫個app吧。
//代理定義
@protocol ProgrammerDelegate - (void)makeAnApp; @end /****************************************/ //為self添加一個信號,表示代理ProgrammerDelegate的makeAnApp方法信號 RACSignal *programmerSignal = [self rac_signalForSelector:@selector(makeAnApp) fromProtocol:@protocol(ProgrammerDelegate)]; //設置代理方法makeAnApp的實現 [programmerSignal subscribeNext:^(RACTuple* x) { //這里可以理解為makeAnApp的方法要的執行代碼 NSLog(@"花了一個月,app寫好了"); }]; //調用代理方法 [self makeAnApp];
5. 廣播
知道你的頻道,我就能聽到你了。
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
//注冊廣播通知
RACSignal *signal = [center rac_addObserverForName:@"代碼之道頻道" object:nil]; //設置接收到通知的回調處理 [signal subscribeNext:^(NSNotification* x) { NSLog(@"技巧:%@", x.userInfo[@"技巧"]); }]; //發送廣播通知 [center postNotificationName:@"代碼之道頻道" object:nil userInfo:@{@"技巧":@"用心寫"}];
6. 串聯

兩個管串聯,一個管處理完自己的東西,下一個管才開始處理自己的東西

生活是一個故事接一個故事。
//創建一個信號管A
RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id subscriber) {//發送一個Next玻璃球和一個Complete玻璃球[subscriber sendNext:@"我戀愛啦"]; [subscriber sendCompleted]; return nil; }]; //創建一個信號管B RACSignal *signalB = [RACSignal createSignal:^RACDisposable *(id subscriber) { //發送一個Next玻璃球和一個Complete玻璃球 [subscriber sendNext:@"我結婚啦"]; [subscriber sendCompleted]; return nil; }]; //串聯管A和管B RACSignal *concatSignal = [signalA concat:signalB]; //串聯后的接收端處理 [concatSignal subscribeNext:^(id x) { NSLog(@"%@",x); }]; //打印:我戀愛啦 我結婚啦
7. 并聯

兩個管并聯,只要有一個管有東西,就拿出來處理它。

污水都應該流入污水處理廠被處理。
//創建信號A
RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id subscriber) {[subscriber sendNext:@"紙廠污水"];return nil; }]; //創建信號B RACSignal *signalB = [RACSignal createSignal:^RACDisposable *(id subscriber) { [subscriber sendNext:@"電鍍廠污水"]; return nil; }]; //并聯2個信號 RACSignal *mergeSignal = [RACSignal merge:@[signalA, signalB]]; [mergeSignal subscribeNext:^(id x) { NSLog(@"處理%@",x); }];
8. 組合
//定義2個自定義信號
RACSubject *letters = [RACSubject subject];
RACSubject *numbers = [RACSubject subject];
//組合信號
[[RACSignal combineLatest:@[letters, numbers] reduce:^(NSString *letter, NSString *number){ //把2個信號的信號值進行字符串拼接 return [letter stringByAppendingString:number]; }] subscribeNext:^(NSString * x) { NSLog(@"%@", x); }]; //自己控制發送信號值 [letters sendNext:@"A"]; [letters sendNext:@"B"]; [numbers sendNext:@"1"];//打印B1 [letters sendNext:@"C"];//打印C1 [numbers sendNext:@"2"];//打印C2

?

9. 合流壓縮
我們是紅白的
//創建信號A
RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id subscriber) {[subscriber sendNext:@"紅"];[subscriber sendNext:@"白"]; return nil; }]; //創建信號B RACSignal *signalB = [RACSignal createSignal:^RACDisposable *(id subscriber) { [subscriber sendNext:@"白"]; return nil; }]; //合流后出來的是壓縮包,需要解壓才能取到里面的值 [[signalA zipWith:signalB] subscribeNext:^(RACTuple* x) { //解壓縮 RACTupleUnpack(NSString *stringA, NSString *stringB) = x; NSLog(@"我們是%@%@的", stringA, stringB); }]; //打印:我們是紅白的
10. 映射
我可以點石成金。
//創建信號,發送"石"玻璃球
RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id subscriber) {[subscriber sendNext:@"石"];return nil; }]; //對信號進行改造,改造"石"為"金" signal = [signal map:^id(NSString *value) { if ([value isEqualToString:@"石"]) { return @"金"; } return value; }]; //打印 [signal subscribeNext:^(id x) { NSLog(@"%@", x);//金 }];
11. 過濾
未滿十八歲,禁止進入。
//創建信號
RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id subscriber) {[subscriber sendNext:@(15)];[subscriber sendNext:@(17)]; [subscriber sendNext:@(21)]; [subscriber sendNext:@(14)]; [subscriber sendNext:@(30)]; return nil; }] //過濾信號,并打印 [[signal filter:^BOOL(NSNumber* value) { //值大于等于18的才能通過過濾網 return value.integerValue >= 18; }] subscribeNext:^(id x) { NSLog(@"%@", x); }]; //打印:21 30
12. 秩序(flattenMap方法也可以換成then方法,效果一樣)
打蛋液,煎雞蛋,上盤。
//創建一個信號
RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id subscriber) {NSLog(@"打蛋液"); [subscriber sendNext:@"蛋液"]; [subscriber sendCompleted]; return nil; }] //對信號進行秩序執行第一步 signal = [signal flattenMap:^RACStream *(NSString* value) { //處理上一步的RACSignal的信號值value,這里value = @"蛋液" NSLog(@"把%@倒進鍋里面煎",value); //返回下一步的RACSignal信號 return [RACSignal createSignal:^RACDisposable *(id subscriber) { [subscriber sendNext:@"煎蛋"]; [subscriber sendCompleted]; return nil; }]; }]; //對信號進行秩序執行第二步 signal = [signal flattenMap:^RACStream *(NSString* value) { //處理上一步的RACSignal的信號值value,這里value = @"煎蛋" NSLog(@"把%@裝到盤里", value); //返回下一步的RACSignal信號 return [RACSignal createSignal:^RACDisposable *(id subscriber) { [subscriber sendNext:@"上菜"]; [subscriber sendCompleted]; return nil; }]; }]; //最后打印 [signal subscribeNext:^(id x) { NSLog(@"%@", x); }]; /* 打印: 打蛋液 把蛋液倒進鍋里面煎 把煎蛋裝到盤里 上菜 */
13. 命令
我命令你馬上投降。
//創建命令
RACCommand *aCommand = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(NSString *input) {//命令執行代碼NSLog(@"%@我投降了",input); //返回一個RACSignal信號 return [RACSignal createSignal:^RACDisposable *(id subscriber) { [subscriber sendCompleted]; return nil; }]; }]; //執行命令 [aCommand execute:@"今天"]; //打印:今天我投降了
14. 延遲
等等我,我還有10秒鐘就到了。
//創建一個信號
RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id subscriber) {NSLog(@"等等我,我還有10秒鐘就到了"); [subscriber sendNext:@"車陂南"]; [subscriber sendCompleted]; return nil; }]; //延時10秒接受Next玻璃球 [[RACSignal delay:10] subscribeNext:^(NSString *x) { NSLog(@"我到了%@",x); }]; /* [2016-04-21 13:20:10]等等我,我還有10秒鐘就到了 [2016-04-21 13:20:20]我到了車陂南 */
15. 重放
一次制作,多次觀看。
//創建一個普通信號
RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id subscriber) {NSLog(@"大導演拍了一部電影《我的男票是程序員》"); [subscriber sendNext:@"《我的男票是程序員》"]; return nil; }]; //創建該普通信號的重復信號 RACSignal *replaySignal = [signal replay]; //重復接受信號 [replaySignal subscribeNext:^(NSString *x) { NSLog(@"小明看了%@", x); }]; [replaySignal subscribeNext:^(NSString *x) { NSLog(@"小紅也看了%@", x); }]; /* 大導演拍了一部電影《我的男票是程序員》 小明看了《我的男票是程序員》 小紅也看了《我的男票是程序員》 */
16. 定時
每隔8個小時服一次藥。
//創建定時器信號,定時8個小時
RACSignal *signal = [RACSignal interval:60*60*8 onScheduler:[RACScheduler mainThreadScheduler]]; //定時執行代碼 [signal subscribeNext:^(id x) { NSLog(@"吃藥"); }];
17. 超時
等了你一個小時了,你還沒來,我走了。
RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id subscriber) {//創建發送信息信號NSLog(@"我快到了"); RACSignal *sendSignal = [RACSignal createSignal:^RACDisposable *(id sendSubscriber) { [sendSubscriber sendNext:nil]; [sendSubscriber sendCompleted]; return nil; }]; //發送信息要1個小時10分鐘才到 [[sendSignal delay:60*70] subscribeNext:^(id x) { //這里才發送Next玻璃球到signal [subscriber sendNext:@"我到了"]; [subscriber sendCompleted]; }]; return nil; }] //這里對signal進行超時接受處理,如果1個小時都沒收到玻璃球,超時錯誤 [[signal timeout:60*60 onScheduler:[RACScheduler mainThreadScheduler]] subscribeError:^(NSError *error) { //超時錯誤處理 NSLog(@"等了你一個小時了,你還沒來,我走了"); }];
18. 重試
成功之前可能需要數百次失敗。
__block int failedCount = 0;
//創建信號
RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id subscriber) { if (failedCount < 100) { failedCount++; NSLog(@"我失敗了"); //發送錯誤,才會要重試 [subscriber sendError:nil]; } else { NSLog(@"經歷了數百次失敗后"); [subscriber sendNext:nil]; } return nil; }]; //重試 RACSignal *retrySignal = [signal retry]; //直到發送了Next玻璃球 [retrySignal subscribeNext:^(id x) { NSLog(@"終于成功了"); }];
19. 節流
不好意思,這里一秒鐘只能通過一個人。
RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id subscriber) {//即時發送一個Next玻璃球[subscriber sendNext:@"旅客A"];//下面是GCD延時發送Next玻璃球 dispatch_queue_t mainQueue = dispatch_get_main_queue(); dispatch_after(dispatch_time(DISPATCH_TIME_NOW,(int64_t)(1 * NSEC_PER_SEC)),mainQueue, ^{ [subscriber sendNext:@"旅客B"]; }); dispatch_after(dispatch_time(DISPATCH_TIME_NOW,(int64_t)(2 * NSEC_PER_SEC)),mainQueue, ^{ //發送多個Next,如果節流了,接收最新發送的 [subscriber sendNext:@"旅客C"]; [subscriber sendNext:@"旅客D"]; [subscriber sendNext:@"旅客E"]; }); dispatch_after(dispatch_time(DISPATCH_TIME_NOW,(int64_t)(3 * NSEC_PER_SEC)),mainQueue, ^{ [subscriber sendNext:@"旅客F"]; }); return nil; }]; //對信號進行節流,限制短時間內一次只能接收一個Next玻璃球 [[signal throttle:1] subscribeNext:^(id x) { NSLog(@"%@通過了",x); }]; /* [2015-08-16 22:08:45.677]旅客A [2015-08-16 22:08:46.737]旅客B [2015-08-16 22:08:47.822]旅客E [2015-08-16 22:08:48.920]旅客F */
20. 條件(takeUntil方法:當給定的signal完成前一直取值)
直到世界的盡頭才能把我們分開。
//創建取值信號
RACSignal *takeSignal = [RACSignal createSignal:^RACDisposable *(id subscriber) {//創建一個定時器信號,每隔1秒觸發一次RACSignal *signal = [RACSignal interval:1 onScheduler:[RACScheduler mainThreadScheduler]]; //定時接收 [signal subscribeNext:^(id x) { //在這里定時發送Next玻璃球 [subscriber sendNext:@"直到世界的盡頭才能把我們分開"]; }]; return nil; }]; //創建條件信號 RACSignal *conditionSignal = [RACSignal createSignal:^RACDisposable *(id subscriber) { //設置5秒后發生Complete玻璃球 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ NSLog(@"世界的盡頭到了"); [subscriber sendCompleted]; }); return nil; }] //設置條件,takeSignal信號在conditionSignal信號接收完成前,不斷地取值 [[takeSignal takeUntil:conditionSignal] subscribeNext:^(id x) { NSLog(@"%@", x); }]; /* [2015-08-16 22:17:22.648]直到世界的盡頭才能把我們分開 [2015-08-16 22:17:23.648]直到世界的盡頭才能把我們分開 [2015-08-16 22:17:24.645]直到世界的盡頭才能把我們分開 [2015-08-16 22:17:25.648]直到世界的盡頭才能把我們分開 [2015-08-16 22:17:26.644]直到世界的盡頭才能把我們分開 [2015-08-16 22:17:26.645]世界的盡頭到了 */

RAC還有更多的使用,目前就學習到這些,大部分功能基本已經符合我們的開發要求了,就整理分享出來。

?

轉載于:https://www.cnblogs.com/ming1025/p/6072544.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/372013.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/372013.shtml
英文地址,請注明出處:http://en.pswp.cn/news/372013.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

使用密碼摘要生成器擴展JMeter

最近&#xff0c;我不得不處理一個帶有50,000條用戶記錄的OpenLDAP實例&#xff0c;并進行一些壓力測試。 JMeter是填充LDAP的最佳選擇。 但是&#xff0c;在我的情況下&#xff0c;OpenLDAP配置為不接受任何明文密碼。 因此&#xff0c;我無法使用通過JMeter LDAP Request采…

制造業數字化轉型核心不止是技術

一、制造業的數字化轉型意味著什么&#xff1f; 在當今的制造業領域&#xff0c;數字化轉型意味著通過集成數字技術來增強傳統的制造方法、產品和勞動力的過程。這些技術包括一系列創新&#xff0c;如自動化軟件、電子商務系統、傳感器、工業機器人等。 二、制造業數字化轉型的…

分類測試以減少構建時間

在繼續本文的主要內容之前&#xff0c;讓我們先進行一些定義。 單元測試 單元測試是小型的&#xff08;測試一種用例或單元&#xff09;&#xff0c;在內存中運行&#xff08;不與數據庫&#xff0c;消息隊列等交互&#xff09;&#xff0c;可重復且快速的測試。 對于我們的對…

android橫向展示狀態,【報Bug】Android橫屏狀態下啟動App,即使在App.vue中鎖定豎屏,但是首頁nvue中的rpx單位是按照啟動的橫豎屏狀態顯示的!...

詳細問題描述(DCloud產品不會有明顯的bug&#xff0c;所以你遇到的問題大都是在特定環境下才能重現的問題&#xff0c;請仔細描述你的環境和重現方式&#xff0c;否則DCloud很難排查解決你的問題)[內容]重現步驟[步驟][結果][期望]nvue首頁rpx單位能夠根據App.vue鎖定的屏幕方向…

property修飾關鍵字

修飾符按作用區分&#xff1a;線程安全相關&#xff0c;內存相關&#xff0c;讀寫權限相關&#xff0c;set和get,是否可為空, class 一.默認值 property NSArray *dataArray; 默認的是&#xff1a;atomic&#xff0c;strong&#xff08;有的文章寫的居然是assign,我認為還是str…

高精度相關模板.

1 2 /*3 高精度加法.4 */5 #include<cstring>6 #include<cstdio>7 #include<iostream>8 #define MAXN 100019 using namespace std;10 int a[MAXN],b[MAXN],c[MAXN],l1,l2,l3;11 char m[MAXN],n[MAXN];12 void slove()13 {14 l3max(l1,l2);15 for(in…

5分鐘內Google App Engine上的Vaadin App

在本教程中&#xff0c;您將學習如何創建第一個Vaadin Web應用程序&#xff0c;如何在本地AppEngine開發服務器上運行它以及如何將其部署到Google App Engine基礎結構。 所有這些大約需要5到10分鐘。 是的&#xff0c;如果您安裝了必要的先決條件&#xff0c;則可以立即開始運行…

linux系統調用的封裝格式,ARM Linux系統調用的原理

ARM Linux系統調用的原理ARM Linux系統調用的原理操作系統為在用戶態運行的進程與硬件設備進行交互提供了一組接口。在應用程序和硬件之間設置一個額外層具有很多優點。首先&#xff0c;這使得編程更加容易&#xff0c;把用戶從學習硬件設備的低級編程特性中解放出來。其次&…

(延遲兩秒,跳轉相應頁面)(返回到上一個頁面并刷新)

1.setTimeout("window.location.href /moment/reason",2000);2.返回到上一個頁面并刷新 self.location document.referrer;2.1常見的幾種刷新方式 a.history.go(-1) 返回上一頁 b.location.reload() 刷新當前頁面 c.history.back() 返回上一頁2.2當…

檢索字符創 php

strstr()可以返回匹配的值 echo strstr("localhost", "os");返回ost echo substr_count("gggggs", "g"); 返回檢索匹配字符創次數 substr_replace 字串替換函數轉載于:https://www.cnblogs.com/lidepeng/p/6078064.html

android8強制將app移到sd卡,小內存手機?APP強制轉移至SD卡教程

雖然近兩年手機的機身內存越做越大&#xff0c;但是身邊總還是有些朋友在使用幾年前的手機。而面對如今海量的豐富應用&#xff0c;早年的手機中內置的存儲空間已經開始捉襟見肘。雖說對于這類機型系統通常都提供了將APP轉移至外置內存卡的功能&#xff0c;可是依然有一些頑固的…

在沒有XML的情況下測試Spring和Hibernate

我非常熱衷于Spring 3中的改進&#xff0c;這些改進最終使您能夠在IDE和編譯器的適當支持下從XML遷移到純Java配置。 它并沒有改變Spring是一個龐大的套件這一事實&#xff0c;并且有時發現您需要的東西可能需要一段時間。 圍繞Hibernate的無XML單元測試就是這樣一回事。 我知道…

Observer觀察者設計模式

Observer設計模式主要包括以下兩種對象: (1)被觀察對象:Subject,它往往包含其他對象感興趣的東西,上面例子中熱水器中就是Subject(被監視對象); (2)觀察對象:Observer,它觀察著Subject,當Subject中的某件事發生后,會告知Observer,Obersver會采取相應的行動。上面例子中顯示器和…

最小生成樹 prime zoj1586

題意&#xff1a;在n個星球&#xff0c;每2個星球之間的聯通需要依靠一個網絡適配器&#xff0c;每個星球喜歡的網絡適配器的價錢不同&#xff0c;先給你一個n&#xff0c;然后n個數&#xff0c;代表第i個星球喜愛的網絡適配器的價錢&#xff0c;然后給出一個矩陣M[i][j]代表第…

android 書架菜單,Android入門3--做一個書架

修改名稱創建項目的時候&#xff0c;APP的名字取為英文或者拼音&#xff0c;是為了簡便&#xff0c;但是顯示在界面上&#xff0c;我們當然希望它是中文的。taoguanstring>我們要做的很簡單&#xff0c;就是在string.xml中&#xff0c;將app_name的內容修改為我們希望的名字…

第一節:整體介紹

Python版本3.5.2&#xff0c;Django版本1.10 創建一個Django工程&#xff0c;并且生成一個名字為mainsite的app django-admin.py startproject myblog python3 manage.py startapp mainsite 文件結構如下&#xff1a; x-powerxpower-CW65S:~/chen/myblog$ tree ./ ./ ├── ma…

Spring @Configuration和FactoryBean

考慮使用FactoryBean通過Spring配置文件定義緩存&#xff1a; <cache:annotation-driven /><context:component-scan base-packageorg.bk.samples.cachexml></context:component-scan><bean idcacheManager classorg.springframework.cache.support.Simpl…

cookie解決 未登錄加入購物車 第一次訪問彈出新手引導頁面

瀏覽器攜帶cookie到服務器, 點擊加入購物車-->后臺檢查-->是否登錄(有沒有sessionid) 沒有登錄--->secookie()返回給瀏覽器,把傳遞過來的商品id, 屬性(多個屬性逗號拼接),數量存起來,(序列號成字符串_不同屬性用下劃線拼接) 轉載于:https://www.cnblogs.com/bj-tony/p…

REST + Spring Security會話問題

REST &#xff0c; 會話 ..等待。 REST應用程序中沒有會話&#xff0c;對嗎&#xff1f; 好吧&#xff0c;那是真的。 如果我們可以避免會議&#xff0c;我們應該這樣做。 REST是無狀態的 。 有關無狀態性的主要問題是身份驗證。 在通常的Web應用程序中&#xff0c;我們習慣于在…

程序猿果真有前端后端client嗎

前端 后端 client DBA OP 程序猿有分這么細的嗎?入行時候有區別. 殊途同歸 吾道一以貫之, 假設作為程序猿不能領悟一貫, 則永遠不清楚.轉載于:https://www.cnblogs.com/blfbuaa/p/6970139.html