### Execute Setup Operations Sequentially with then Source: https://context7.com/reactivecocoa/reactiveobjc/llms.txt Execute a series of setup operations in sequence using the 'then:' operator. Each 'then:' block returns a new signal that is executed only after the previous one completes. ```objc // Execute setup operations in sequence RACSignal *setup = [[[[self initializeDatabase] then:^{ return [self migrateSchema]; }] then:^{ return [self loadConfiguration]; }] then:^{ return [self connectToServer]; }]; [setup subscribeError:^(NSError *error) { NSLog(@"Setup failed: %@", error); } completed:^{ NSLog(@"Setup complete!"); }]; ``` -------------------------------- ### Parallelizing Independent Work with ReactiveObjC Source: https://github.com/reactivecocoa/reactiveobjc/blob/master/README.md Shows how to achieve the same parallelization as the NSOperationQueue example using ReactiveObjC signals. This approach is more declarative and concise. ```objc RACSignal *databaseSignal = [[databaseClient fetchObjectsMatchingPredicate:predicate] subscribeOn:[RACScheduler scheduler]]; RACSignal *fileSignal = [RACSignal startEagerlyWithScheduler:[RACScheduler scheduler] block:^(id subscriber) { NSMutableArray *filesInProgress = [NSMutableArray array]; for (NSString *path in files) { [filesInProgress addObject:[NSData dataWithContentsOfFile:path]]; } [subscriber sendNext:[filesInProgress copy]]; [subscriber sendCompleted]; }]; [[RACSignal combineLatest:@[ databaseSignal, fileSignal ] reduce:^ id (NSArray *databaseObjects, NSArray *fileContents) { [self finishProcessingDatabaseObjects:databaseObjects fileContents:fileContents]; return nil; }] subscribeCompleted:^{ NSLog(@"Done processing"); }]; ``` -------------------------------- ### Incorrect recursive implementation of repeat Source: https://github.com/reactivecocoa/reactiveobjc/blob/master/Documentation/DesignGuidelines.md An example of a naive implementation that risks a stack overflow due to unbounded recursion. ```objc - (RACSignal *)repeat { return [RACSignal createSignal:^(id subscriber) { RACCompoundDisposable *compoundDisposable = [RACCompoundDisposable compoundDisposable]; __block void (^resubscribe)(void) = ^{ RACDisposable *disposable = [self subscribeNext:^(id x) { [subscriber sendNext:x]; } error:^(NSError *error) { [subscriber sendError:error]; } completed:^{ resubscribe(); }]; [compoundDisposable addDisposable:disposable]; }; return compoundDisposable; }]; } ``` -------------------------------- ### Collection Transformations with Loops Source: https://github.com/reactivecocoa/reactiveobjc/blob/master/README.md Illustrates a traditional imperative approach to transforming collections using loops, filtering, and appending strings. This can be verbose and error-prone. ```objc NSMutableArray *results = [NSMutableArray array]; for (NSString *str in strings) { if (str.length < 2) { continue; } NSString *newString = [str stringByAppendingString:@"foobar"]; [results addObject:newString]; } ``` -------------------------------- ### Manage Subscription Lifecycles with RACDisposable Source: https://context7.com/reactivecocoa/reactiveobjc/llms.txt Demonstrates various patterns for manual and automatic disposal of subscriptions, including scoped disposables, compound disposables, and lifecycle-bound operators. ```objective-c // Automatic disposal on completion [signal subscribeNext:^(id x) { // Subscriber removed when signal completes }]; // Manual disposal for infinite signals RACDisposable *disposable = [infiniteSignal subscribeNext:^(id x) { [self handleValue:x]; }]; // Cancel when view disappears - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; [self.disposable dispose]; } // Scoped disposable - disposes when deallocated @property (nonatomic, strong) RACDisposable *scopedDisposable; self.scopedDisposable = [[signal subscribeNext:^(id x) { // Automatically disposed when self deallocates }] asScopedDisposable]; // Compound disposable for multiple subscriptions RACCompoundDisposable *compound = [RACCompoundDisposable compoundDisposable]; [compound addDisposable:[signal1 subscribeNext:^(id x) {}]]; [compound addDisposable:[signal2 subscribeNext:^(id x) {}]]; [compound dispose]; // Disposes all at once // takeUntil for automatic disposal [[signal takeUntil:self.rac_willDeallocSignal] subscribeNext:^(id x) { // Automatically stops when self is deallocated }]; ``` -------------------------------- ### Filter Stream Values Source: https://github.com/reactivecocoa/reactiveobjc/blob/master/Documentation/BasicOperators.md The filter: operator includes values in the resulting stream only if they pass the test defined in the provided block. This example filters for even numbers. ```objc 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; }]; ``` -------------------------------- ### Collection Transformations with RACSequence Source: https://github.com/reactivecocoa/reactiveobjc/blob/master/README.md Demonstrates simplifying collection transformations using RACSequence, which provides declarative methods like filter and map. This approach is more concise and readable. ```objc RACSequence *results = [[strings.rac_sequence filter:^ BOOL (NSString *str) { return str.length >= 2; }] map:^(NSString *str) { return [str stringByAppendingString:@"foobar"]; }]; ``` -------------------------------- ### Track Signal Subscriptions Source: https://github.com/reactivecocoa/reactiveobjc/blob/master/Documentation/BasicOperators.md Demonstrates that side effects within a cold signal's creation block execute once per subscription. Use subscribeCompleted: to observe completion. ```objc __block unsigned subscriptions = 0; RACSignal *loggingSignal = [RACSignal createSignal:^ RACDisposable * (id subscriber) { subscriptions++; [subscriber sendCompleted]; return nil; }]; // Outputs: // subscription 1 [loggingSignal subscribeCompleted:^{ NSLog(@"subscription %u", subscriptions); }]; // Outputs: // subscription 2 [loggingSignal subscribeCompleted:^{ NSLog(@"subscription %u", subscriptions); }]; ``` -------------------------------- ### Connect RACCommand to UI Button Source: https://context7.com/reactivecocoa/reactiveobjc/llms.txt Connect a RACCommand to a UI button using 'rac_command'. This automatically handles enabling/disabling the button based on the command's 'executing' state and triggers the command's execution when the button is pressed. ```objc // Connect to button (on macOS) self.loginButton.rac_command = self.loginCommand; ``` -------------------------------- ### Execute Asynchronous Operations with RACCommand Source: https://github.com/reactivecocoa/reactiveobjc/blob/master/README.md Initiates asynchronous operations, such as network requests, via RACCommand. The loginCommand is executed when the loginButton is pressed. executionSignals emits signals for each command execution, allowing subscription to completion events. ```objc // Hooks up a "Log in" button to log in over the network. // // This block will be run whenever the login command is executed, starting // the login process. self.loginCommand = [[RACCommand alloc] initWithSignalBlock:^(id sender) { // The hypothetical -logIn method returns a signal that sends a value when // the network request finishes. return [client logIn]; }]; // -executionSignals returns a signal that includes the signals returned from // the above block, one for each time the command is executed. [self.loginCommand.executionSignals subscribeNext:^(RACSignal *loginSignal) { // Log a message whenever we log in successfully. [loginSignal subscribeCompleted:^{ NSLog(@"Logged in successfully!"); }]; }]; // Executes the login command when the button is pressed. self.loginButton.rac_command = self.loginCommand; ``` -------------------------------- ### Create Immediate Value Signals Source: https://context7.com/reactivecocoa/reactiveobjc/llms.txt ReactiveObjC provides convenience methods for creating signals that emit immediate values or complete immediately. ```objc // Create immediate value signals RACSignal *immediateValue = [RACSignal return:@"Hello"]; // Sends value and completes RACSignal *emptySignal = [RACSignal empty]; // Completes immediately RACSignal *errorSignal = [RACSignal error:someError]; // Sends error immediately RACSignal *neverSignal = [RACSignal never]; // Never completes ``` -------------------------------- ### Implement non-blocking map operator in Objective-C Source: https://github.com/reactivecocoa/reactiveobjc/blob/master/Documentation/DesignGuidelines.md Demonstrates the correct approach to implementing a map operator by returning a new stream immediately using flattenMap, rather than performing synchronous iteration. ```objc // WRONG! - (RACSequence *)map:(id (^)(id))block { RACSequence *result = [RACSequence empty]; for (id obj in self) { id mappedObj = block(obj); result = [result concat:[RACSequence return:mappedObj]]; } return result; } // Right! - (RACSequence *)map:(id (^)(id))block { return [self flattenMap:^(id obj) { id mappedObj = block(obj); return [RACSequence return:mappedObj]; }]; } ``` -------------------------------- ### Weak Self Capture with EXT-Scope Macros Source: https://github.com/reactivecocoa/reactiveobjc/blob/master/Documentation/MemoryManagement.md Utilize `@weakify` and `@strongify` macros from extlibobjc for cleaner weak self capture in signal blocks. Ensure the object supports weak references. ```objc @weakify(self); [RACObserve(self, username) subscribeNext:^(NSString *username) { @strongify(self); [self validateUsername]; }]; ``` -------------------------------- ### Parallelizing Independent Work with NSOperationQueue Source: https://github.com/reactivecocoa/reactiveobjc/blob/master/README.md Demonstrates parallelizing independent work using NSOperationQueue and NSBlockOperation. This approach involves manual dependency management and synchronization. ```objc __block NSArray *databaseObjects; __block NSArray *fileContents; NSOperationQueue *backgroundQueue = [[NSOperationQueue alloc] init]; NSBlockOperation *databaseOperation = [NSBlockOperation blockOperationWithBlock:^{ databaseObjects = [databaseClient fetchObjectsMatchingPredicate:predicate]; }]; NSBlockOperation *filesOperation = [NSBlockOperation blockOperationWithBlock:^{ NSMutableArray *filesInProgress = [NSMutableArray array]; for (NSString *path in files) { [filesInProgress addObject:[NSData dataWithContentsOfFile:path]]; } fileContents = [filesInProgress copy]; }]; NSBlockOperation *finishOperation = [NSBlockOperation blockOperationWithBlock:^{ [self finishProcessingDatabaseObjects:databaseObjects fileContents:fileContents]; NSLog(@"Done processing"); }]; [finishOperation addDependency:databaseOperation]; [finishOperation addDependency:filesOperation]; [backgroundQueue addOperation:databaseOperation]; [backgroundQueue addOperation:filesOperation]; [backgroundQueue addOperation:finishOperation]; ``` -------------------------------- ### Lift Selector with Signals Source: https://github.com/reactivecocoa/reactiveobjc/blob/master/Documentation/MemoryManagement.md An alternative pattern to avoid explicit subscriptions and self-references by lifting a selector to be driven by signals. ```objc [self rac_liftSelector:@selector(validateUsername:) withSignals:RACObserve(self, username), nil]; ``` -------------------------------- ### Sequence Signals with then Operator Source: https://context7.com/reactivecocoa/reactiveobjc/llms.txt Use the 'then:' operator to wait for a source signal to complete, then subscribe to and forward events from a new signal. This operator ignores all values from the source signal, making it suitable for sequential execution where only completion matters. ```objc // Wait for animation to complete, then load data [[[self animateViewOut] then:^RACSignal *{ return [self fetchNewContent]; }] subscribeNext:^(id content) { [self displayContent:content]; }]; ``` -------------------------------- ### Sequencing Signals with then: Source: https://github.com/reactivecocoa/reactiveobjc/blob/master/Documentation/BasicOperators.md Executes side effects of one signal before switching to a second signal. ```objective-c 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; }]; ``` -------------------------------- ### Create RACCommand with Enabled Signal Source: https://context7.com/reactivecocoa/reactiveobjc/llms.txt Create a RACCommand with an enabled signal that controls its execution. The command is only enabled when the input is valid, typically based on UI element states like text field content. ```objc // Create login command with enabled signal RACSignal *inputValid = [RACSignal combineLatest:@[ self.usernameField.rac_textSignal, self.passwordField.rac_textSignal ] reduce:^(NSString *user, NSString *pass) { return @(user.length > 0 && pass.length > 0); }]; self.loginCommand = [[RACCommand alloc] initWithEnabled:inputValid signalBlock:^RACSignal *(id input) { return [client loginWithUsername:self.usernameField.text password:self.passwordField.text]; }]; ``` -------------------------------- ### Execute RACCommand Programmatically Source: https://context7.com/reactivecocoa/reactiveobjc/llms.txt Execute a RACCommand programmatically by calling its 'execute:' method. This returns a signal that completes when the command's execution finishes. ```objc // Execute programmatically [[self.loginCommand execute:nil] subscribeCompleted:^{ [self dismissViewController]; }]; ``` -------------------------------- ### Explicitly Handle Signal Side Effects Source: https://github.com/reactivecocoa/reactiveobjc/blob/master/Documentation/DesignGuidelines.md Use doNext:, doError:, and doCompleted: to make side effects explicit and self-documenting within a signal chain. This improves clarity and maintainability. ```objc NSMutableArray *nexts = [NSMutableArray array]; __block NSError *receivedError = nil; __block BOOL success = NO; RACSignal *bookkeepingSignal = [[[valueSignal doNext:^(id x) { [nexts addObject:x]; }] doError:^(NSError *error) { receivedError = error; }] doCompleted:^{ success = YES; }]; RAC(self, value) = bookkeepingSignal; ``` -------------------------------- ### Multicast and Replay Signals Source: https://context7.com/reactivecocoa/reactiveobjc/llms.txt Share a single subscription across multiple observers to avoid redundant side effects like multiple network requests. ```objc // Problem: Each subscription triggers a new network request RACSignal *networkRequest = [self fetchUserData]; [networkRequest subscribeNext:^(id x) { /* subscriber 1 */ }]; [networkRequest subscribeNext:^(id x) { /* subscriber 2 - triggers another request! */ }]; // Solution: Multicast to share the subscription RACMulticastConnection *connection = [networkRequest multicast:[RACReplaySubject subject]]; [connection connect]; // Starts the single subscription [connection.signal subscribeNext:^(id x) { /* subscriber 1 */ }]; [connection.signal subscribeNext:^(id x) { /* subscriber 2 - same data */ }]; // Shorthand: replay captures and replays all values RACSignal *replayed = [networkRequest replay]; [replayed subscribeNext:^(id x) { /* Gets all values */ }]; // Later... [replayed subscribeNext:^(id x) { /* Also gets all previously sent values */ }]; // replayLast - only replay most recent value RACSignal *lastValue = [signal replayLast]; // replayLazily - connect on first subscription RACSignal *lazy = [networkRequest replayLazily]; ``` -------------------------------- ### ReactiveCocoa for Event Handling Source: https://github.com/reactivecocoa/reactiveobjc/blob/master/README.md This Objective-C code demonstrates how to handle events using ReactiveCocoa. It uses RAC signals to bind UI element properties and subscribe to events, simplifying complex event compositions. Ensure ReactiveCocoa is imported. ```Objective-C - (void)viewDidLoad { [super viewDidLoad]; @weakify(self); RAC(self.logInButton, enabled) = [RACSignal combineLatest:@[ self.usernameTextField.rac_textSignal, self.passwordTextField.rac_textSignal, RACObserve(LoginManager.sharedManager, loggingIn), RACObserve(self, loggedIn) ] reduce:^(NSString *username, NSString *password, NSNumber *loggingIn, NSNumber *loggedIn) { return @(username.length > 0 && password.length > 0 && !loggingIn.boolValue && !loggedIn.boolValue); }]; [[self.logInButton rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(UIButton *sender) { @strongify(self); RACSignal *loginSignal = [LoginManager.sharedManager logInWithUsername:self.usernameTextField.text password:self.passwordTextField.text]; [loginSignal subscribeError:^(NSError *error) { @strongify(self); [self presentError:error]; } completed:^{ @strongify(self); self.loggedIn = YES; }]; }]; RAC(self, loggedIn) = [[NSNotificationCenter.defaultCenter rac_addObserverForName:UserDidLogOutNotification object:nil] mapReplace:@NO]; } ``` -------------------------------- ### Correct recursive implementation using RACScheduler Source: https://github.com/reactivecocoa/reactiveobjc/blob/master/Documentation/DesignGuidelines.md A safe implementation using scheduleRecursiveBlock: to avoid stack overflow by scheduling resubscription. ```objc - (RACSignal *)repeat { return [RACSignal createSignal:^(id subscriber) { RACCompoundDisposable *compoundDisposable = [RACCompoundDisposable compoundDisposable]; RACScheduler *scheduler = RACScheduler.currentScheduler ?: [RACScheduler scheduler]; RACDisposable *disposable = [scheduler scheduleRecursiveBlock:^(void (^reschedule)(void)) { RACDisposable *disposable = [self subscribeNext:^(id x) { [subscriber sendNext:x]; } error:^(NSError *error) { [subscriber sendError:error]; } completed:^{ reschedule(); }]; [compoundDisposable addDisposable:disposable]; }]; [compoundDisposable addDisposable:disposable]; return compoundDisposable; }]; } ``` -------------------------------- ### Share Signal Side Effects with Multicasting Source: https://github.com/reactivecocoa/reactiveobjc/blob/master/Documentation/DesignGuidelines.md Employ -publish and -multicast: to share a single subscription to a signal, ensuring side effects like network requests occur only once. This is useful when multiple subscribers need the same result without redundant operations. ```objc // This signal starts a new request on each subscription. RACSignal *networkRequest = [RACSignal createSignal:^(id subscriber) { AFHTTPRequestOperation *operation = [client HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id response) { [subscriber sendNext:response]; [subscriber sendCompleted]; } failure:^(AFHTTPRequestOperation *operation, NSError *error) { [subscriber sendError:error]; }]; [client enqueueHTTPRequestOperation:operation]; return [RACDisposable disposableWithBlock:^{ [operation cancel]; }]; }]; // Starts a single request, no matter how many subscriptions `connection.signal` // gets. This is equivalent to the -replay operator, or similar to // +startEagerlyWithScheduler:block:. RACMulticastConnection *connection = [networkRequest multicast:[RACReplaySubject subject]]; [connection connect]; [connection.signal subscribeNext:^(id response) { NSLog(@"subscriber one: %@", response); }]; [connection.signal subscribeNext:^(id response) { NSLog(@"subscriber two: %@", response); }]; ``` -------------------------------- ### Manage signal subscription lifecycle Source: https://github.com/reactivecocoa/reactiveobjc/blob/master/Documentation/MemoryManagement.md Use a RACDisposable to manage the subscription lifecycle in a view controller, noting that the subscriber block creates an implicit reference to self. ```objc self.disposable = [signal subscribeCompleted:^{ doSomethingPossiblyInvolving(self); }]; ``` -------------------------------- ### Subscribe to Signal Values Source: https://github.com/reactivecocoa/reactiveobjc/blob/master/Documentation/BasicOperators.md Use subscribeNext: to access values from a signal. Side effects occur once per subscription for cold signals. ```objc RACSignal *letters = [@"A B C D E F G H I" componentsSeparatedByString:@" "].rac_sequence.signal; // Outputs: A B C D E F G H I [letters subscribeNext:^(NSString *x) { NSLog(@"%@", x); }]; ``` -------------------------------- ### Apply switchToLatest to a Signal of Signals Source: https://github.com/reactivecocoa/reactiveobjc/blob/master/Documentation/BasicOperators.md Use switchToLatest when you have a signal that emits other signals. It subscribes to the latest signal and forwards its values, discarding values from previous signals. ```objc 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"]; ``` -------------------------------- ### Handle RACCommand Execution Results Source: https://context7.com/reactivecocoa/reactiveobjc/llms.txt Handle the results of a RACCommand's execution by subscribing to its 'executionSignals'. Each subscription receives a signal that represents a single execution of the command. ```objc // Handle execution results [self.loginCommand.executionSignals subscribeNext:^(RACSignal *execution) { [execution subscribeCompleted:^{ NSLog(@"Login successful!"); }]; }]; ``` -------------------------------- ### Derive State with RAC and combineLatest:reduce: Source: https://github.com/reactivecocoa/reactiveobjc/blob/master/README.md Creates a one-way binding to derive state from multiple signals. RAC() macro simplifies the binding syntax. combineLatest:reduce: combines the latest values from an array of signals and applies a reduction block to produce a new signal. ```objc // Creates a one-way binding so that self.createEnabled will be // true whenever self.password and self.passwordConfirmation // are equal. // // RAC() is a macro that makes the binding look nicer. // // +combineLatest:reduce: takes an array of signals, executes the block with the // latest value from each signal whenever any of them changes, and returns a new // RACSignal that sends the return value of that block as values. RAC(self, createEnabled) = [RACSignal combineLatest:@[ RACObserve(self, password), RACObserve(self, passwordConfirmation) ] reduce:^(NSString *password, NSString *passwordConfirm) { return @([passwordConfirm isEqualToString:password]); }]; ``` -------------------------------- ### Inject Side Effects with doCompleted Source: https://github.com/reactivecocoa/reactiveobjc/blob/master/Documentation/BasicOperators.md Use doCompleted: to add side effects that execute upon signal completion without triggering immediate subscription. This allows observing subscription counts. ```objc __block unsigned subscriptions = 0; RACSignal *loggingSignal = [RACSignal createSignal:^ RACDisposable * (id 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); }]; ``` -------------------------------- ### Combining Latest Values Source: https://github.com/reactivecocoa/reactiveobjc/blob/master/Documentation/BasicOperators.md Watches multiple signals and sends the latest values from all when any change occurs. ```objective-c 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"]; ``` -------------------------------- ### Traditional Cocoa Event Handling Source: https://github.com/reactivecocoa/reactiveobjc/blob/master/README.md This Objective-C code demonstrates traditional event handling in Cocoa using observers, notifications, and target-action patterns. It sets up observers for login status changes and text field edits, and handles button taps and logout notifications. ```Objective-C static void *ObservationContext = &ObservationContext; - (void)viewDidLoad { [super viewDidLoad]; [LoginManager.sharedManager addObserver:self forKeyPath:@"loggingIn" options:NSKeyValueObservingOptionInitial context:&ObservationContext]; [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(loggedOut:) name:UserDidLogOutNotification object:LoginManager.sharedManager]; [self.usernameTextField addTarget:self action:@selector(updateLogInButton) forControlEvents:UIControlEventEditingChanged]; [self.passwordTextField addTarget:self action:@selector(updateLogInButton) forControlEvents:UIControlEventEditingChanged]; [self.logInButton addTarget:self action:@selector(logInPressed:) forControlEvents:UIControlEventTouchUpInside]; } - (void)dealloc { [LoginManager.sharedManager removeObserver:self forKeyPath:@"loggingIn" context:ObservationContext]; [NSNotificationCenter.defaultCenter removeObserver:self]; } - (void)updateLogInButton { BOOL textFieldsNonEmpty = self.usernameTextField.text.length > 0 && self.passwordTextField.text.length > 0; BOOL readyToLogIn = !LoginManager.sharedManager.isLoggingIn && !self.loggedIn; self.logInButton.enabled = textFieldsNonEmpty && readyToLogIn; } - (IBAction)logInPressed:(UIButton *)sender { [[LoginManager sharedManager] logInWithUsername:self.usernameTextField.text password:self.passwordTextField.text success:^{ self.loggedIn = YES; } failure:^(NSError *error) { [self presentError:error]; }]; } - (void)loggedOut:(NSNotification *)notification { self.loggedIn = NO; } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if (context == ObservationContext) { [self updateLogInButton]; } else { [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; } } ``` -------------------------------- ### Manage Threading with RACScheduler Source: https://context7.com/reactivecocoa/reactiveobjc/llms.txt RACScheduler controls execution context, including main thread delivery, background work, and delayed execution. ```objc // Deliver events on main thread for UI updates [[signal deliverOnMainThread] subscribeNext:^(id value) { self.label.text = value; // Safe UI update }]; // Perform work on background scheduler RACSignal *backgroundWork = [[RACSignal createSignal:^(id subscriber) { // Expensive computation here [subscriber sendNext:result]; [subscriber sendCompleted]; return nil; }] subscribeOn:[RACScheduler scheduler]]; // Schedule with specific priority RACScheduler *lowPriority = [RACScheduler schedulerWithPriority:RACSchedulerPriorityLow]; [[signal deliverOn:lowPriority] subscribeNext:^(id x) { [self processInBackground:x]; }]; // Delayed execution RACScheduler *scheduler = [RACScheduler mainThreadScheduler]; [scheduler afterDelay:2.0 schedule:^{ NSLog(@"Executed after 2 seconds"); }]; // Periodic timer signal RACSignal *timer = [RACSignal interval:1.0 onScheduler:scheduler]; [timer subscribeNext:^(NSDate *date) { NSLog(@"Tick: %@", date); }]; // Deliver events with delay [[signal delay:0.5] subscribeNext:^(id x) { // Receives each value 0.5s after it was sent }]; ``` -------------------------------- ### Handle UI Actions with RACCommand Source: https://github.com/reactivecocoa/reactiveobjc/blob/master/README.md Represents UI actions and associates work with them using RACCommand. The -rac_command property on NSButton allows the button to send itself to the command when pressed. The signal block within RACCommand is executed upon command execution. ```objc // Logs a message whenever the button is pressed. // // RACCommand creates signals to represent UI actions. Each signal can // represent a button press, for example, and have additional work associated // with it. // // -rac_command is an addition to NSButton. The button will send itself on that // command whenever it's pressed. self.button.rac_command = [[RACCommand alloc] initWithSignalBlock:^(id _) { NSLog(@"button was pressed!"); return [RACSignal empty]; }]; ``` -------------------------------- ### Extend Sequences by Duplicating Values with flattenMap Source: https://context7.com/reactivecocoa/reactiveobjc/llms.txt Extend sequences by duplicating values using flattenMap. For each element in the source sequence, return a new sequence containing the element multiple times. ```objc RACSequence *numbers = @[@1, @2, @3].rac_sequence; RACSequence *duplicated = [numbers flattenMap:^RACSequence *(NSNumber *num) { return @[num, num].rac_sequence; }]; // Contains: 1, 1, 2, 2, 3, 3 ``` -------------------------------- ### Combining Signals with combineLatest Source: https://context7.com/reactivecocoa/reactiveobjc/llms.txt Combine multiple signals into one, emitting whenever any source signal emits. Note that the combined signal waits for all inputs to emit at least once before producing a value. ```objc // Enable login button only when both fields are valid RACSignal *enabledSignal = [RACSignal combineLatest:@[ self.usernameTextField.rac_textSignal, self.passwordTextField.rac_textSignal, RACObserve(LoginManager.sharedManager, loggingIn) ] reduce:^NSNumber *(NSString *username, NSString *password, NSNumber *loggingIn) { BOOL valid = username.length > 0 && password.length >= 8 && !loggingIn.boolValue; return @(valid); }]; RAC(self.loginButton, enabled) = enabledSignal; // Combine two signals into tuples RACSignal *combined = [signalA combineLatestWith:signalB]; [combined subscribeNext:^(RACTuple *tuple) { RACTupleUnpack(NSString *a, NSNumber *b) = tuple; NSLog(@"A: %@, B: %@", a, b); }]; // Note: Combined signal waits for ALL inputs to emit at least once RACSubject *letters = [RACSubject subject]; RACSubject *numbers = [RACSubject subject]; RACSignal *combined = [RACSignal combineLatest:@[letters, numbers] reduce:^(NSString *l, NSString *n) { return [l stringByAppendingString:n]; }]; [letters sendNext:@"A"]; // No output yet [letters sendNext:@"B"]; // No output yet [numbers sendNext:@"1"]; // Outputs: B1 [numbers sendNext:@"2"]; // Outputs: B2 ``` -------------------------------- ### Binding UI Elements with RAC in ReactiveObjC Source: https://github.com/reactivecocoa/reactiveobjc/blob/master/README.md Use the `RAC` macro for one-way bindings to update UI elements, such as an image view, as soon as data is available. `deliverOn:` is used to manage threading, ensuring work is done on a background queue and updates occur on the main thread. ```objc RAC(self.imageView, image) = [[[[client fetchUserWithUsername:@"joshaber"] deliverOn:[RACScheduler scheduler]] map:^(User *user) { // Download the avatar (this is done on a background queue). return [[NSImage alloc] initWithContentsOfURL:user.avatarURL]; }] // Now the assignment will be done on the main thread. deliverOn:RACScheduler.mainThreadScheduler]; ``` -------------------------------- ### Transforming Signals with map Source: https://context7.com/reactivecocoa/reactiveobjc/llms.txt Use map to transform signal values or mapReplace to replace all values with a constant. These operators create new signals based on the original stream. ```objc // Transform user objects to usernames RACSignal *userSignal = [self fetchUsers]; RACSignal *usernameSignal = [userSignal map:^NSString *(User *user) { return user.username; }]; // Chain multiple transformations RACSignal *formattedNames = [[userSignal map:^(User *user) { return user.name; }] map:^(NSString *name) { return [name uppercaseString]; }]; // Download and process images on background thread, deliver on main thread RAC(self.imageView, image) = [[[[client fetchUserWithUsername:@"joshaber"] deliverOn:[RACScheduler scheduler]] map:^(User *user) { // Download avatar on background queue return [[NSImage alloc] initWithContentsOfURL:user.avatarURL]; }] deliverOn:RACScheduler.mainThreadScheduler]; // Replace all values with a constant RACSignal *logoutNotifications = [[NSNotificationCenter.defaultCenter rac_addObserverForName:UserDidLogOutNotification object:nil] mapReplace:@NO]; ``` -------------------------------- ### Sequence Signals with Side Effects using then and doNext Source: https://context7.com/reactivecocoa/reactiveobjc/llms.txt Sequence signals while performing side effects on the source signal's values using 'doNext:'. The 'then:' operator then subscribes to a new signal, forwarding its values. ```objc // Sequence with doNext for side effects on source values RACSignal *sequenced = [[letters doNext:^(NSString *letter) { NSLog(@"Processing: %@", letter); // Side effect on source values }] then:^{ return numbers; // Return new signal's values }]; ``` -------------------------------- ### Bind Properties with RAC Macro Source: https://context7.com/reactivecocoa/reactiveobjc/llms.txt Use the RAC macro for declarative one-way data binding between signals and object properties. ```objc // Bind signal to property RAC(self, username) = self.usernameTextField.rac_textSignal; // Bind with transformation RAC(self.avatarImageView, image) = [[self.user.avatarURLSignal flattenMap:^(NSURL *url) { return [self downloadImageFromURL:url]; }] deliverOnMainThread]; // Bind computed property RAC(self.loginButton, enabled) = [RACSignal combineLatest:@[ self.usernameField.rac_textSignal, self.passwordField.rac_textSignal ] reduce:^(NSString *user, NSString *pass) { return @(user.length > 0 && pass.length > 0); }]; // Manual binding with setKeyPath [enabledSignal setKeyPath:@"enabled" onObject:self.submitButton]; // Bind with nil value handling for primitives [signal setKeyPath:@"alpha" onObject:self.view nilValue:@1.0]; ``` -------------------------------- ### Create Custom RACSignal Source: https://context7.com/reactivecocoa/reactiveobjc/llms.txt Use `+createSignal:` to create custom signals that perform asynchronous work and send values to subscribers. Return a `RACDisposable` to handle cleanup or cancellation. ```objc // Create a custom signal that performs work and sends values RACSignal *networkSignal = [RACSignal createSignal:^RACDisposable *(id subscriber) { // Perform async network request NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { if (error) { [subscriber sendError:error]; } else { [subscriber sendNext:data]; [subscriber sendCompleted]; } }]; [task resume]; // Return disposable for cleanup/cancellation return [RACDisposable disposableWithBlock:^{ [task cancel]; }]; }]; ``` -------------------------------- ### Subscribe to Signal Completion in ReactiveObjC Source: https://github.com/reactivecocoa/reactiveobjc/blob/master/README.md Use `subscribeCompleted:` to execute a block when a signal finishes. This is useful for coordinating multiple asynchronous operations. ```objc [[RACSignal merge:@[ [client fetchUserRepos], [client fetchOrgRepos] ]] subscribeCompleted:^{ NSLog(@"They're both done!"); }]; ``` -------------------------------- ### Lazy evaluation of a RACSequence Source: https://github.com/reactivecocoa/reactiveobjc/blob/master/Documentation/DesignGuidelines.md Demonstrates how RACSequence performs operations lazily, where transformations are only executed when values are accessed. ```objc NSArray *strings = @[ @"A", @"B", @"C" ]; RACSequence *sequence = [strings.rac_sequence map:^(NSString *str) { return [str stringByAppendingString:@"_"]; }]; ``` -------------------------------- ### Merging and Concatenating Signals Source: https://context7.com/reactivecocoa/reactiveobjc/llms.txt Merge multiple signals to forward values as they arrive, or concatenate them to sequence execution. Use flatten to handle nested signals with concurrency limits. ```objc // Merge multiple data sources - values arrive as they're ready RACSignal *allRepos = [RACSignal merge:@[ [client fetchUserRepos], [client fetchOrgRepos], [client fetchStarredRepos] ]]; [allRepos subscribeCompleted:^{ NSLog(@"All repositories loaded!"); }]; // Concatenate signals - second starts after first completes RACSignal *letters = @[@"A", @"B", @"C"].rac_sequence.signal; RACSignal *numbers = @[@"1", @"2", @"3"].rac_sequence.signal; RACSignal *concatenated = [letters concat:numbers]; // Outputs: A, B, C, 1, 2, 3 (in order) // Merge with instance method RACSignal *merged = [localDataSignal merge:remoteDataSignal]; // Flatten nested signals with concurrency limit RACSignal *signalOfSignals = [urls map:^(NSURL *url) { return [self downloadDataFromURL:url]; }]; RACSignal *results = [signalOfSignals flatten:3]; // Max 3 concurrent downloads ``` -------------------------------- ### Observe RACCommand Executing State Source: https://context7.com/reactivecocoa/reactiveobjc/llms.txt Observe the 'executing' signal of a RACCommand to manage UI elements like activity indicators. This signal emits YES when the command is executing and NO when it completes or is cancelled. ```objc // Observe executing state for activity indicator RAC(self.activityIndicator, animating) = self.loginCommand.executing; ``` -------------------------------- ### Handle RACCommand Errors Source: https://context7.com/reactivecocoa/reactiveobjc/llms.txt Handle errors generated during RACCommand execution by subscribing to the 'errors' signal. Errors are sent as next events on this signal. ```objc // Handle errors (sent as next events, not error events) [self.loginCommand.errors subscribeNext:^(NSError *error) { [self showErrorAlert:error]; }]; ``` -------------------------------- ### ReactiveCocoa for Chaining Dependent Operations Source: https://github.com/reactivecocoa/reactiveobjc/blob/master/README.md This Objective-C code demonstrates chaining dependent operations using ReactiveCocoa signals. It utilizes methods like `then` and `flattenMap` to manage sequential asynchronous tasks and error handling, providing a more declarative style. ```Objective-C [[[[client logIn] then:^{ return [client loadCachedMessages]; }] flattenMap:^(NSArray *messages) { return [client fetchMessagesAfterMessage:messages.lastObject]; }] subscribeError:^(NSError *error) { [self presentError:error]; } completed:^{ NSLog(@"Fetched all messages."); }]; ``` -------------------------------- ### Chaining Asynchronous Operations with flattenMap in ReactiveObjC Source: https://github.com/reactivecocoa/reactiveobjc/blob/master/README.md Chain asynchronous operations sequentially using `flattenMap`. This method executes its block when the signal sends a value and merges the returned signals into a single stream. It's ideal for complex workflows like login followed by data loading. ```objc [[[[client logInUser] flattenMap:^(User *user) { // Return a signal that loads cached messages for the user. return [client loadCachedMessagesForUser:user]; }] flattenMap:^(NSArray *messages) { // Return a signal that fetches any remaining messages. return [client fetchMessagesAfterMessage:messages.lastObject]; }] subscribeNext:^(NSArray *newMessages) { NSLog(@"New messages: %@", newMessages); } completed:^{ NSLog(@"Fetched all messages."); }]; ``` -------------------------------- ### Subscribe to RACSignal Events Source: https://context7.com/reactivecocoa/reactiveobjc/llms.txt Subscribe to signals to receive their emitted values, errors, or completion events. Subscriptions are automatically disposed upon completion or error, or can be manually disposed. ```objc RACSignal *signal = [self fetchUserData]; // Subscribe to all events RACDisposable *disposable = [signal subscribeNext:^(NSDictionary *userData) { NSLog(@"Received user data: %@", userData); } error:^(NSError *error) { NSLog(@"Error fetching user: %@", error.localizedDescription); } completed:^{ NSLog(@"Finished fetching user data"); }]; ``` ```objc // Subscribe to specific events only [signal subscribeNext:^(id value) { // Handle each value }]; ``` ```objc [signal subscribeCompleted:^{ // Handle completion only }]; ``` ```objc [signal subscribeError:^(NSError *error) { // Handle errors only }]; ``` ```objc // Cancel subscription manually if needed [disposable dispose]; ``` -------------------------------- ### Merging Signals Source: https://github.com/reactivecocoa/reactiveobjc/blob/master/Documentation/BasicOperators.md Combines multiple signals into a single stream, forwarding values as they arrive. ```objective-c 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"]; ``` -------------------------------- ### Observe Property Changes with RACObserve Source: https://github.com/reactivecocoa/reactiveobjc/blob/master/README.md Logs the new value of a property whenever it changes. RACObserve creates a signal that emits the current and subsequent values of the specified key path. Use subscribeNext: to execute a block when a new value is received. ```objc // When self.username changes, logs the new name to the console. // // RACObserve(self, username) creates a new RACSignal that sends the current // value of self.username, then the new value whenever it changes. // -subscribeNext: will execute the block whenever the signal sends a value. [RACObserve(self, username) subscribeNext:^(NSString *newName) { NSLog(@"%@", newName); }]; ``` -------------------------------- ### Traditional Chaining of Dependent Operations Source: https://github.com/reactivecocoa/reactiveobjc/blob/master/README.md This Objective-C code shows a traditional, callback-based approach to chaining dependent network requests. It uses nested completion blocks to handle sequential operations and error reporting. ```Objective-C [client logInWithSuccess:^{ [client loadCachedMessagesWithSuccess:^(NSArray *messages) { [client fetchMessagesAfterMessage:messages.lastObject success:^(NSArray *nextMessages) { NSLog(@"Fetched all messages."); } failure:^(NSError *error) { [self presentError:error]; }]; } failure:^(NSError *error) { [self presentError:error]; }]; } failure:^(NSError *error) { [self presentError:error]; }]; ``` -------------------------------- ### Indent single stream operations Source: https://github.com/reactivecocoa/reactiveobjc/blob/master/Documentation/DesignGuidelines.md Use standard indentation for simple stream transformations or single method invocations. ```objective-c RACStream *result = [stream startWith:@0]; RACStream *result2 = [stream map:^(NSNumber *value) { return @(value.integerValue + 1); }]; ``` -------------------------------- ### Filtering Signals Source: https://context7.com/reactivecocoa/reactiveobjc/llms.txt Filter signals based on conditions, ignore specific values, or limit the number of emissions using operators like filter, ignore, distinctUntilChanged, and take. ```objc // Filter to only valid usernames RACSignal *validUsernames = [RACObserve(self, username) filter:^BOOL(NSString *name) { return name.length >= 3 && name.length <= 20; }]; // Filter numbers to even values only RACSequence *numbers = @[@1, @2, @3, @4, @5, @6].rac_sequence; RACSequence *evenNumbers = [numbers filter:^BOOL(NSNumber *num) { return num.intValue % 2 == 0; }]; // Contains: 2, 4, 6 // Ignore nil values RACSignal *nonNilValues = [signal ignore:nil]; // Only emit when value changes RACSignal *distinctValues = [RACObserve(self, searchText) distinctUntilChanged]; // Take only first N values RACSignal *firstThree = [signal take:3]; // Skip first N values RACSignal *afterSkip = [signal skip:2]; // Take values until condition RACSignal *untilEmpty = [signal takeUntilBlock:^BOOL(NSString *text) { return text.length == 0; }]; ``` -------------------------------- ### FlattenMap for Signals Source: https://github.com/reactivecocoa/reactiveobjc/blob/master/Documentation/BasicOperators.md Transforms signal values into new signals, useful for chaining asynchronous work. ```objective-c 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."); }]; ``` -------------------------------- ### Map Signal for Validation Source: https://github.com/reactivecocoa/reactiveobjc/blob/master/Documentation/MemoryManagement.md Use the `map` operator on a signal to encapsulate validation logic, returning a signal that indicates validation status. ```objc RACSignal *validated = [RACObserve(self, username) map:^(NSString *username) { // Put validation logic here. return @YES; }]; ``` -------------------------------- ### FlattenMap for Sequences Source: https://github.com/reactivecocoa/reactiveobjc/blob/master/Documentation/BasicOperators.md Transforms sequence values into new sequences and flattens the result. ```objective-c 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]; } }]; ``` -------------------------------- ### Perform Collection Operations with RACSequence Source: https://context7.com/reactivecocoa/reactiveobjc/llms.txt RACSequence provides lazy evaluation and functional operators like map, filter, and fold for collections. ```objc // Transform collections with map and filter NSArray *strings = @[@"hello", @"world", @"foo", @"bar"]; RACSequence *sequence = strings.rac_sequence; RACSequence *result = [[sequence filter:^BOOL(NSString *str) { return str.length >= 4; // Keep strings with 4+ chars }] map:^NSString *(NSString *str) { return [str uppercaseString]; // Transform to uppercase }]; NSArray *resultArray = result.array; // @[@"HELLO", @"WORLD"] // Reduce/fold operations NSNumber *sum = [[@[@1, @2, @3, @4].rac_sequence foldLeftWithStart:@0 reduce:^id(NSNumber *acc, NSNumber *val) { return @(acc.intValue + val.intValue); }]; // Result: 10 // Lazy evaluation - work only done when needed RACSequence *lazy = [[hugeArray.rac_sequence map:^(id item) { return [self expensiveTransform:item]; }] take:5]; // Only transforms 5 items // Convert to eager sequence for immediate evaluation RACSequence *eager = sequence.eagerSequence; // Convert sequence to signal for async processing RACSignal *asyncSignal = [sequence signalWithScheduler:[RACScheduler scheduler]]; ``` -------------------------------- ### Align multiple stream transformations Source: https://github.com/reactivecocoa/reactiveobjc/blob/master/Documentation/DesignGuidelines.md Align chained operators vertically to improve readability when transforming a stream multiple times. ```objective-c RACStream *result = [[[RACStream zip:@[ firstStream, secondStream ] reduce:^(NSNumber *first, NSNumber *second) { return @(first.integerValue + second.integerValue); }] filter:^ BOOL (NSNumber *value) { return value.integerValue >= 0; }] map:^(NSNumber *value) { return @(value.integerValue + 1); }]; ```