Äú¿ÉÒÔ¾èÖú£¬Ö§³ÖÎÒÃǵĹ«ÒæÊÂÒµ¡£

1Ôª 10Ôª 50Ôª





ÈÏÖ¤Â룺  ÑéÖ¤Âë,¿´²»Çå³þ?Çëµã»÷Ë¢ÐÂÑéÖ¤Âë ±ØÌî



  ÇóÖª ÎÄÕ ÎÄ¿â Lib ÊÓÆµ iPerson ¿Î³Ì ÈÏÖ¤ ×Éѯ ¹¤¾ß ½²×ù Modeler   Code  
»áÔ±   
 
   
 
 
     
   
 ¶©ÔÄ
  ¾èÖú
ÈçºÎ½¨Á¢»ùÓÚCocoaPodsµÄReactiveCocoa¹¤³Ì
 
×÷Õߣº°¢·åµÄ¼¼ÊõÎÑÎÑ À´×ÔÓÚ£ºÍÆ¿á ·¢²¼ÓÚ 2015-10-12
  2820  次浏览      28
 

ReactiveCocoa ºÍ CocoaPods Ò»ÑùÒ²ÊÇĿǰºÜÁ÷ÐÐµÄ ÄÜ·½±ãºÍÌá¸ßЧÂʵĿò¼Ü.

Æäʵ²»¹âios ѧϰÈκÎÒ»ÃÅÓïÒô×î¿ì×îÖ±½ÓµÄ·½·¨¾ÍÊÇÉÏÊÖ. Èç¹ûµ¥µ¥ÊÇ¿´¿´ÎĵµÖ»ÄÜÊÇ×ßÂí¹Û»¨µÃµ½Ò»¸ö¸ÐÐÔÈÏʶ°ÕÁË.ǰÁ½Ìì֮ǰһ¸ö¹«Ë¾µÄ²âÊÔÈËÔ±¸úÎÒÁªÏµËµÈçºÎѧϰJAVA,ÎÒÎÊËûÊÇÔõôѧµÄ,Ëû˵´ÓÍøÉÏÏÂÁ˺öàÊÓÆµ½Ì³Ì,Ò»Ö±ÔÚ¿´ÊÓÆµ½Ì³Ì,Ò²ÂòÁËһЩÊé. ÎÒÎÊËûÇÃÁ˶àÉÙ´úÂë,Ëû˵ºÜÉÙ. Æäʵ¸úËûÒ»ÑùµÄÈ˲»ÉÙ. ÎÒ¾õµÃÈκÎÊÂÇé¶¼²»¼òµ¥,ÒòΪ¿´ÆðÀ´¼òµ¥µÄÊÂÇé×Ô¼ºÃ»ÓÐʵ¼Ê×ö¹ýµÄ»° ÍùÍù»áÓöµ½¸÷ÖÖ¸÷ÑùµÄÎÊÌâ. ÕâÒ²ÊÇΪʲôÔÚ¹¤×÷ÖÐÖÆ¶¨ÏîÄ¿½ø¶È¼Æ»®µÄʱºò ÎÒ¾¡Á¿¸ø×Ô¼ººÍÍŶÓÖеÄÈ˶àÕùȡʱ¼äµÄ×îÖ÷ÒªµÄÒ»¸öÒòËØ.

ºÃÁË,×Ô¼ºÒ»Ð©†ªàº͸ÐÎò. ÏÂÃæ¿ªÊ¼Õýʽ.

What is Reactive Cocoa?

RAV is an Object-C framework for Functional Reavtive Programming;

Á½¸ö¹Ø¼üµã:

1:framework ¼ÈÈ»ÊÇframework ÄǾ͸úÄãÓÃµÄÆäËûframeworkÃ»Ê²Ã´Çø±ð Î޷ǾÍÊǼӵ½¹¤³ÌÖÐÒýÓðÕÁË.²»×ö¶àÓà½âÊÍ

2:Functional Reavtive Programming ʵʱÏìӦʽ±à³Ì

ϺÃ×ÒýÓñ»°¢ÀïÊÕ¹ººóÏÖÔÚÏÈÉϵÄmac°æ±¾µÄϺÃ×ÒôÀÖ¾ÍÊÇÓÃReactive Cocoa¿ª·¢µÄ.Óð¢ÀïÈË×Ô¼ºµÄ»°À´Ëµ¾ÍÊÇ

ºÃ¶«Î÷°¡£¬ÒÔǰÎÒÃÇÓà KVO »ò Notification À´×Ô¶¯°ó¶¨Êý¾Ý£¬¸ÄÓà ReactiveCocoa дÒԺ󣬴úÂë½á¹¹¸ü¼Ñ¼òµ¥ÇåÎú£¬Í¬Ê±´úÂëÐÐÊýÖ±½Ó¼õÉÙ 60% ÒÔÉÏ

À´µãÖ±¹ÛµÄ¶Ô±È°É,±ÈÈçÎÒÃÇÏëҪʵÏÖÒ»¸öÐèÇó:µ±±äÁ¿ÖеÄ×Ö·û´®¸Ä±äºó¼´Ê±×ö³öÏàÓ¦µÄ·´À¡ ÎÒÃÇÓÃKVO ÐèÒªÈçÏÂÕâÑù×ö

ÕâÀïÓеãÒªÌØ±ð˵Ã÷µÄµØ·½

ÉÏÃæÒ»Ûç´úÂë ÔÚÓ¦ÓÃReactive Cocoaºó Ö»Óж̶ÌÒ»ÐÐ

// In your viewDidLoad/awakeFromNib/init
[self addObserver:self
forKeyPath:@"someString"
options:NSKeyValueObservingOptionNew
context:&someStringChangeContext];

// In dealloc
[self removeObserver:self
forKeyPath:@"someString"
context:&someStringChangeContext];

// Elsewhere in your class
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
if (context == &someStringChangeContext) {
if ([keyPath isEqualToString:@"someString"]) {
// Do a bunch of stuff here
}
}
}

ÉÏÃæÒ»Ûç´úÂë ÔÚÓ¦ÓÃReactive Cocoaºó Ö»Óж̶ÌÒ»ÐÐ

[RACObserve(self, someString) distinctUntilChanged] subscribeNext:^(NSString *string) {
// Do a bunch of things here, just like you would with KVO
}];

¿ªÊ¼¶¯ÊÖ

ÒòΪÎÒ֮ǰ°²×°ÁË CocoaPods ,ËùÒÔÎÒÕâ´ÎдµÄReactiveCocoaDemo ÊÇ»ùÓÚCocoaPodsµÄ.Èç¹ûûÓа²×°µÄ¿ÉÒÔͯЬ,¿ÉÒÔÖ±½Ó´ÓgithubÉÏÏÂÔØ ReactiveCocoa

ǰÆÚ¹¤×÷:

1.´ò¿ªxcode ´´½¨Ò»¸ö¹¤³Ì,ÎÒÃüÃûµÄ¹¤³ÌÃûΪReactiveCocoaDemo,

2.Öն˵½¹¤³Ì·¾¶ÏÂ

cd ReactiveCocoaDemo/
pod search ReactiveCocoa

3.ÅäÖÃÒÀÀµÎļþ

vi Podfile
platform :ios,'5.0'
pod 'ReactiveCocoa'
wq

4.ÏÂÔØÎļþ

pod install /update

5:´ò¿ª¡°Build Phases¡± Ñ¡ÖÐÏàÓ¦µÄtarget, Ìí¼Ó RAC µ½ ¡°Link Binary With Libraries¡±.¼ÓÉÏlibReactiveCocoa-iOS.a

6:ÔÚHeader Search Paths ÖÐÌí¼Ó$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts/include"

7:ÔÚ ¡°Other Linker Flags¡± Ìí¼Ó -ObjC

8:ÔÚReactiveCocoaDemo-Prefix.pch ½«RACµÄÍ·Îļþ¼Ó½øÈ¥

#import "ReactiveCocoa.h"

ÏÖÔÚҪʵÏÖÈçϹ¦ÄÜ

Á½¸öÊäÈë¿ò Ò»¸öÌáʾµÄLable Ò»¸ö°´Å¥,

1.µ±Á½¸öÊäÈë¿òµÄÄÚÈÝÏàͬʱ ÌáʾÎÄ×ÖÏÔʾ¡°³É¹¦¡± °´Å¥¿ÉÒÔµã»÷

2.µ±ÈÎÒâÒ»¸öÊäÈë¿òûÓÐÊäÈëÄÚÈÝʱ ÌáʾÎÄ×ÖÏÔʾ¡°ÇëÊäÈ롱 °´Å¥²»¿Éµã»÷

3.µ±ÊäÈë¿ò·Ç¿ÕÇÒÁ½¸öÊäÈëÄÚÈݲ»Í¬Ê± Ìáʾ¡°ÇëÖØÐÂÊäÈ롱 °´Å¥²»¿Éµã»÷

ÏÂÃæÊDz¿·ÖʵÏÖ´úÂë:

@weakify(self);
[[RACObserve(self, warningText)
filter:^(NSString *newString) {
self.resultLabel.text = newString;
return YES;
// return [newString hasPrefix:@"Success"];
}]
subscribeNext:^(NSString *newString) {
@strongify(self);
self.bt.enabled = [newString hasPrefix:@"Success"];
}];


RAC(self,self.warningText) = [RACSignal combineLatest:@[
RACObserve(self,self.input.text),RACObserve(self, self.verifyInput.text)]
reduce:^(NSString *password, NSString *passwordConfirm)
{
if ([passwordConfirm isEqualToString:password])
{
return @"Success";
}
else if([password length] == 0 || [passwordConfirm length] ==0 )
{
return @"Please Input";
}
else
return @"Input Error";
}
];

¶ÔÓ¦¹ØÏµÈçÏÂͼËùʾ

ѧ¹ýC++ µÄÓ¦¸Ã¾õµÃÕâ¸öºÜÀàËÆÓÚQtÖеÄÐźŲۻúÖÆ

ÐèҪ˵Ã÷µÄÊÇ ÒòΪRACºÜ´ó³Ì¶ÈÉÏÊÇÒÀÀµÓÚBlockµÄ.ËùÒÔÔÚRACÇ°ÃæÎÒÃǼÓÉÏ@weakify(my_variable) ±ÜÃâÑ­»·ÒýÓÃ,È»ºóÔÚÿһ¸öRAC¿éÖÐΪÁË·ÀÖ¹ÌáǰÊÍ·ÅÎÒÃÇÐèÒªÓÃ@strongify(my_variable)À´¶Ô¶ÔÏó½øÐгÖÓÐ. ÏêÇéµã»÷

ÔËÐÐЧ¹ûÈçÏÂ

Îĵµ¸½Â¼

Subscription

The [-subscribe¡­][RACSignal] methods give you access to the current and future values in a signal:

RACSignal *letters = [@"A B C D E F G H I" componentsSeparatedByString:@" "].rac_sequence.signal;

// Outputs: A B C D
[letters subscribeNext:^(NSString *x) {
NSLog(@"%@", x);
}];

For a cold signal, side effects will be performed once per subscription :

__block unsigned subscriptions = 0;

RACSignal *loggingSignal = [RACSignal createSignal:^ RACDisposable * (id<RACSubscriber> subscriber) {
subscriptions++;
[subscriber sendCompleted];
return nil;
}];

// Outputs:
// subscription 1
[loggingSignal subscribeCompleted:^{
NSLog(@"subscription %u", subscriptions);
}];

// Outputs:
// subscription 2
[loggingSignal subscribeCompleted:^{
NSLog(@"subscription %u", subscriptions);
}];

This behavior can be changed using a [connection][Connections].

Injecting effects

The [-do¡­][RACSignal+Operations] methods add side effects to a signal without actually subscribing to it:

__block unsigned subscriptions = 0;

RACSignal *loggingSignal = [RACSignal createSignal:^ RACDisposable * (id<RACSubscriber> subscriber) {
subscriptions++;
[subscriber sendCompleted];
return nil;
}];

// Does not output anything yet
loggingSignal = [loggingSignal doCompleted:^{
NSLog(@"about to complete subscription %u", subscriptions);
}];

// Outputs:
// about to complete subscription 1
// subscription 1
[loggingSignal subscribeCompleted:^{
NSLog(@"subscription %u", subscriptions);
}];

Transforming streams

These operators transform a single stream into a new stream.

Mapping

The [-map:][RACStream] method is used to transform the values in a stream, and create a new stream with the results:

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

The [-filter:][RACStream] method uses a block to test each value, including it into the resulting stream only if the test passes:

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;
}];

Combining streams

These operators combine multiple streams into a single new stream.

Concatenating

The [-concat:][RACStream] method appends one stream's values to another:

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

The [-flatten][RACStream] operator is applied to a stream-of-streams, and combines their values into a single new stream.

Sequences are concatenated :

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 :

RACSubject *letters = [RACSubject subject];
RACSubject *numbers = [RACSubject subject];
RACSignal *signalOfSignals = [RACSignal createSignal:^ RACDisposable * (id<RACSubscriber> 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

Flattening isn't that interesting on its own, but understanding how it works is important for [-flattenMap:][RACStream].

-flattenMap: is used to transform each of a stream's values into a new stream . Then, all of the streams returned will be flattened down into a single stream. In other words, it's -map: followed by -flatten .

This can be used to extend or edit sequences:

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];
}
}];

Or create multiple signals of work which are automatically recombined:

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.");
}];

Combining signals

These operators combine multiple signals into a single new [RACSignal][].

Sequencing

[-then:][RACSignal+Operations] starts the original signal, waits for it to complete, and then only forwards the values from a new signal:

RACSignal *letters = [@"A B C D E F G H I" componentsSeparatedByString:@" "].rac_sequence.signal;

// The new signal only contains: 1 2 3 4 5 6 7 8 9
//
// But when subscribed to, it also outputs: 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;
}];

This is most useful for executing all the side effects of one signal, then
starting another, and only returning the second signal's values.

Merging

The [+merge:][RACSignal+Operations] method will forward the values from many signals into a single stream, as soon as those values arrive:

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

The [+combineLatest:][RACSignal+Operations] and +combineLatest:reduce: methods will watch multiple signals for changes, and then send the latest values from all of them when a change occurs:

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"];

Note that the combined signal will only send its first value when all of the inputs have sent at least one. In the example above, @"A" was never forwarded because numbers had not sent a value yet.

Switching

The [-switchToLatest][RACSignal+Operations] operator is applied to a signal-of-signals, and always forwards the values from the latest signal:

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"];

   
2820 ´Îä¯ÀÀ       28
 
Ïà¹ØÎÄÕÂ

ÊÖ»úÈí¼þ²âÊÔÓÃÀýÉè¼ÆÊµ¼ù
ÊÖ»ú¿Í»§¶ËUI²âÊÔ·ÖÎö
iPhoneÏûÏ¢ÍÆËÍ»úÖÆÊµÏÖÓë̽ÌÖ
AndroidÊÖ»ú¿ª·¢£¨Ò»£©
 
Ïà¹ØÎĵµ

Android_UI¹Ù·½Éè¼Æ½Ì³Ì
ÊÖ»ú¿ª·¢Æ½Ì¨½éÉÜ
androidÅÄÕÕ¼°ÉÏ´«¹¦ÄÜ
Android½²ÒåÖÇÄÜÊÖ»ú¿ª·¢
Ïà¹Ø¿Î³Ì

Android¸ß¼¶Òƶ¯Ó¦ÓóÌÐò
Androidϵͳ¿ª·¢
AndroidÓ¦Óÿª·¢
ÊÖ»úÈí¼þ²âÊÔ
×îл¼Æ»®
DeepSeekÔÚÈí¼þ²âÊÔÓ¦ÓÃʵ¼ù 4-12[ÔÚÏß]
DeepSeek´óÄ£ÐÍÓ¦Óÿª·¢Êµ¼ù 4-19[ÔÚÏß]
UAF¼Ü¹¹ÌåϵÓëʵ¼ù 4-11[±±¾©]
AIÖÇÄÜ»¯Èí¼þ²âÊÔ·½·¨Óëʵ¼ù 5-23[ÉϺ£]
»ùÓÚ UML ºÍEA½øÐзÖÎöÉè¼Æ 4-26[±±¾©]
ÒµÎñ¼Ü¹¹Éè¼ÆÓ뽨ģ 4-18[±±¾©]

androidÈË»ú½çÃæÖ¸ÄÏ
AndroidÊÖ»ú¿ª·¢£¨Ò»£©
AndroidÊÖ»ú¿ª·¢£¨¶þ£©
AndroidÊÖ»ú¿ª·¢£¨Èý£©
AndroidÊÖ»ú¿ª·¢£¨ËÄ£©
iPhoneÏûÏ¢ÍÆËÍ»úÖÆÊµÏÖ̽ÌÖ
ÊÖ»úÈí¼þ²âÊÔÓÃÀýÉè¼ÆÊµ¼ù
ÊÖ»ú¿Í»§¶ËUI²âÊÔ·ÖÎö
ÊÖ»úÈí¼þ×Ô¶¯»¯²âÊÔÑо¿±¨¸æ

Android¸ß¼¶Òƶ¯Ó¦ÓóÌÐò
AndroidÓ¦Óÿª·¢
Androidϵͳ¿ª·¢
ÊÖ»úÈí¼þ²âÊÔ
ǶÈëʽÈí¼þ²âÊÔ
AndroidÈí¡¢Ó²¡¢ÔÆÕûºÏ

ÁìÏÈIT¹«Ë¾ android¿ª·¢Æ½Ì¨×î¼Ñʵ¼ù
±±¾© Android¿ª·¢¼¼Êõ½ø½×
ijÐÂÄÜÔ´ÁìÓòÆóÒµ Android¿ª·¢¼¼Êõ
ijº½Ì칫˾ Android¡¢IOSÓ¦ÓÃÈí¼þ¿ª·¢
°¢¶û¿¨ÌØ LinuxÄÚºËÇý¶¯
°¬Ä¬Éú ǶÈëʽÈí¼þ¼Ü¹¹Éè¼Æ
Î÷ÃÅ×Ó Ç¶Èëʽ¼Ü¹¹Éè¼Æ