Skip to content

Commit

Permalink
restored UIKit specific files
Browse files Browse the repository at this point in the history
  • Loading branch information
StefanChannel committed Oct 1, 2024
1 parent 96af78a commit 241b0b8
Show file tree
Hide file tree
Showing 27 changed files with 1,155 additions and 31 deletions.
26 changes: 26 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,32 @@ let package = Package(
"RACUnarySequence.m",
"RACUnit.m",
"RACValueTransformer.m",
// "MKAnnotationView+RACSignalSupport.m",
// "NSControl+RACCommandSupport.m",
// "NSControl+RACTextSignalSupport.m",
// "NSFileHandle+RACSupport.m",
// "NSObject+RACAppKitBindings.m",
// "NSText+RACSignalSupport.m",
"UIActionSheet+RACSignalSupport.m",
"UIAlertView+RACSignalSupport.m",
"UIBarButtonItem+RACCommandSupport.m",
"UIButton+RACCommandSupport.m",
"UICollectionReusableView+RACSignalSupport.m",
"UIControl+RACSignalSupport.m",
"UIControl+RACSignalSupportPrivate.m",
"UIDatePicker+RACSignalSupport.m",
"UIGestureRecognizer+RACSignalSupport.m",
"UIImagePickerController+RACSignalSupport.m",
"UIRefreshControl+RACCommandSupport.m",
"UISegmentedControl+RACSignalSupport.m",
"UISlider+RACSignalSupport.m",
"UIStepper+RACSignalSupport.m",
"UISwitch+RACSignalSupport.m",
"UITableViewCell+RACSignalSupport.m",
"UITableViewHeaderFooterView+RACSignalSupport.m",
"UITextField+RACSignalSupport.m",
"UITextView+RACSignalSupport.m",

],
publicHeadersPath: "include",
cSettings: [
Expand Down
31 changes: 31 additions & 0 deletions ReactiveObjC/MKAnnotationView+RACSignalSupport.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//
// MKAnnotationView+RACSignalSupport.m
// ReactiveObjC
//
// Created by Zak Remer on 3/31/15.
// Copyright (c) 2015 GitHub. All rights reserved.
//

#import "MKAnnotationView+RACSignalSupport.h"
#import "NSObject+RACDescription.h"
#import "NSObject+RACSelectorSignal.h"
#import "RACSignal+Operations.h"
#import "RACUnit.h"
#import <objc/runtime.h>

@implementation MKAnnotationView (RACSignalSupport)

- (RACSignal *)rac_prepareForReuseSignal {
RACSignal *signal = objc_getAssociatedObject(self, _cmd);
if (signal != nil) return signal;

signal = [[[self
rac_signalForSelector:@selector(prepareForReuse)]
mapReplace:RACUnit.defaultUnit]
setNameWithFormat:@"%@ -rac_prepareForReuseSignal", RACDescription(self)];

objc_setAssociatedObject(self, _cmd, signal, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
return signal;
}

@end
57 changes: 57 additions & 0 deletions ReactiveObjC/NSControl+RACCommandSupport.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
//
// NSControl+RACCommandSupport.m
// ReactiveObjC
//
// Created by Josh Abernathy on 3/3/12.
// Copyright (c) 2012 GitHub, Inc. All rights reserved.
//

#import "NSControl+RACCommandSupport.h"
#import "RACCommand.h"
#import "RACScopedDisposable.h"
#import "RACSignal+Operations.h"
#import <objc/runtime.h>

static void *NSControlRACCommandKey = &NSControlRACCommandKey;
static void *NSControlEnabledDisposableKey = &NSControlEnabledDisposableKey;

@implementation NSControl (RACCommandSupport)

- (RACCommand *)rac_command {
return objc_getAssociatedObject(self, NSControlRACCommandKey);
}

- (void)setRac_command:(RACCommand *)command {
objc_setAssociatedObject(self, NSControlRACCommandKey, command, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

// Tear down any previous binding before setting up our new one, or else we
// might get assertion failures.
[objc_getAssociatedObject(self, NSControlEnabledDisposableKey) dispose];
objc_setAssociatedObject(self, NSControlEnabledDisposableKey, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

if (command == nil) {
self.enabled = YES;
return;
}

[self rac_hijackActionAndTargetIfNeeded];

RACScopedDisposable *disposable = [[command.enabled setKeyPath:@"enabled" onObject:self] asScopedDisposable];
objc_setAssociatedObject(self, NSControlEnabledDisposableKey, disposable, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (void)rac_hijackActionAndTargetIfNeeded {
SEL hijackSelector = @selector(rac_commandPerformAction:);
if (self.target == self && self.action == hijackSelector) return;

if (self.target != nil) NSLog(@"WARNING: NSControl.rac_command hijacks the control's existing target and action.");

self.target = self;
self.action = hijackSelector;
}

- (void)rac_commandPerformAction:(id)sender {
[self.rac_command execute:sender];
}

@end
38 changes: 38 additions & 0 deletions ReactiveObjC/NSControl+RACTextSignalSupport.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//
// NSControl+RACTextSignalSupport.m
// ReactiveObjC
//
// Created by Justin Spahr-Summers on 2013-03-08.
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
//

#import "NSControl+RACTextSignalSupport.h"
#import <ReactiveObjC/EXTScope.h>
#import "NSObject+RACDescription.h"
#import "RACDisposable.h"
#import "RACSignal.h"
#import "RACSubscriber.h"

@implementation NSControl (RACTextSignalSupport)

- (RACSignal *)rac_textSignal {
@weakify(self);
return [[[[RACSignal
createSignal:^(id<RACSubscriber> subscriber) {
@strongify(self);
id observer = [NSNotificationCenter.defaultCenter addObserverForName:NSControlTextDidChangeNotification object:self queue:nil usingBlock:^(NSNotification *note) {
[subscriber sendNext:note.object];
}];

return [RACDisposable disposableWithBlock:^{
[NSNotificationCenter.defaultCenter removeObserver:observer];
}];
}]
map:^(NSControl *control) {
return [control.stringValue copy];
}]
startWith:[self.stringValue copy]]
setNameWithFormat:@"%@ -rac_textSignal", RACDescription(self)];
}

@end
40 changes: 40 additions & 0 deletions ReactiveObjC/NSFileHandle+RACSupport.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//
// NSFileHandle+RACSupport.m
// ReactiveObjC
//
// Created by Josh Abernathy on 5/10/12.
// Copyright (c) 2012 GitHub. All rights reserved.
//

#import "NSFileHandle+RACSupport.h"
#import "NSNotificationCenter+RACSupport.h"
#import "NSObject+RACDescription.h"
#import "RACReplaySubject.h"
#import "RACDisposable.h"

@implementation NSFileHandle (RACSupport)

- (RACSignal *)rac_readInBackground {
RACReplaySubject *subject = [RACReplaySubject subject];
[subject setNameWithFormat:@"%@ -rac_readInBackground", RACDescription(self)];

RACSignal *dataNotification = [[[NSNotificationCenter defaultCenter] rac_addObserverForName:NSFileHandleReadCompletionNotification object:self] map:^(NSNotification *note) {
return note.userInfo[NSFileHandleNotificationDataItem];
}];

__block RACDisposable *subscription = [dataNotification subscribeNext:^(NSData *data) {
if (data.length > 0) {
[subject sendNext:data];
[self readInBackgroundAndNotify];
} else {
[subject sendCompleted];
[subscription dispose];
}
}];

[self readInBackgroundAndNotify];

return subject;
}

@end
146 changes: 146 additions & 0 deletions ReactiveObjC/NSObject+RACAppKitBindings.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
//
// NSObject+RACAppKitBindings.m
// ReactiveObjC
//
// Created by Josh Abernathy on 4/17/12.
// Copyright (c) 2012 GitHub, Inc. All rights reserved.
//

#import "NSObject+RACAppKitBindings.h"
#import <ReactiveObjC/EXTKeyPathCoding.h>
#import <ReactiveObjC/EXTScope.h>
#import "NSObject+RACDeallocating.h"
#import "RACChannel.h"
#import "RACCompoundDisposable.h"
#import "RACDisposable.h"
#import "RACKVOChannel.h"
#import "RACValueTransformer.h"
#import <objc/runtime.h>

// Used as an object to bind to, so we can hide the object creation and just
// expose a RACChannel instead.
@interface RACChannelProxy : NSObject

// The RACChannel used for this Cocoa binding.
@property (nonatomic, strong, readonly) RACChannel *channel;

// The KVC- and KVO-compliant property to be read and written by the Cocoa
// binding.
//
// This should not be set manually.
@property (nonatomic, strong) id value;

// The target of the Cocoa binding.
//
// This should be set to nil when the target deallocates.
@property (atomic, unsafe_unretained) id target;

// The name of the Cocoa binding used.
@property (nonatomic, copy, readonly) NSString *bindingName;

// Improves the performance of KVO on the receiver.
//
// See the documentation for <NSKeyValueObserving> for more information.
@property (atomic, assign) void *observationInfo;

// Initializes the receiver and binds to the given target.
//
// target - The target of the Cocoa binding. This must not be nil.
// bindingName - The name of the Cocoa binding to use. This must not be nil.
// options - Any options to pass to the binding. This may be nil.
//
// Returns an initialized channel proxy.
- (instancetype)initWithTarget:(id)target bindingName:(NSString *)bindingName options:(NSDictionary *)options;

@end

@implementation NSObject (RACAppKitBindings)

- (RACChannelTerminal *)rac_channelToBinding:(NSString *)binding {
return [self rac_channelToBinding:binding options:nil];
}

- (RACChannelTerminal *)rac_channelToBinding:(NSString *)binding options:(NSDictionary *)options {
NSCParameterAssert(binding != nil);

RACChannelProxy *proxy = [[RACChannelProxy alloc] initWithTarget:self bindingName:binding options:options];
return proxy.channel.leadingTerminal;
}

@end

@implementation RACChannelProxy

#pragma mark Properties

- (void)setValue:(id)value {
[self willChangeValueForKey:@keypath(self.value)];
_value = value;
[self didChangeValueForKey:@keypath(self.value)];
}

#pragma mark Lifecycle

- (instancetype)initWithTarget:(id)target bindingName:(NSString *)bindingName options:(NSDictionary *)options {
NSCParameterAssert(target != nil);
NSCParameterAssert(bindingName != nil);

self = [super init];

_target = target;
_bindingName = [bindingName copy];
_channel = [[RACChannel alloc] init];

@weakify(self);

void (^cleanUp)(void) = ^{
@strongify(self);

id target = self.target;
if (target == nil) return;

self.target = nil;

[target unbind:bindingName];
objc_setAssociatedObject(target, (__bridge void *)self, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
};

// When the channel terminates, tear down this proxy.
[self.channel.followingTerminal subscribeError:^(NSError *error) {
cleanUp();
} completed:cleanUp];

[self.target bind:bindingName toObject:self withKeyPath:@keypath(self.value) options:options];

// Keep the proxy alive as long as the target, or until the property subject
// terminates.
objc_setAssociatedObject(self.target, (__bridge void *)self, self, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

[[self.target rac_deallocDisposable] addDisposable:[RACDisposable disposableWithBlock:^{
@strongify(self);
[self.channel.followingTerminal sendCompleted];
}]];

RACChannelTo(self, value, options[NSNullPlaceholderBindingOption]) = self.channel.followingTerminal;
return self;
}

- (void)dealloc {
[self.channel.followingTerminal sendCompleted];
}

#pragma mark NSObject

- (NSString *)description {
return [NSString stringWithFormat:@"<%@: %p>{ target: %@, binding: %@ }", self.class, self, self.target, self.bindingName];
}

#pragma mark NSKeyValueObserving

+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key {
// Generating manual notifications for `value` is simpler and more
// performant than having KVO swizzle our class and add its own logic.
return NO;
}

@end
38 changes: 38 additions & 0 deletions ReactiveObjC/NSText+RACSignalSupport.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//
// NSText+RACSignalSupport.m
// ReactiveObjC
//
// Created by Justin Spahr-Summers on 2013-03-08.
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
//

#import "NSText+RACSignalSupport.h"
#import <ReactiveObjC/EXTScope.h>
#import "NSObject+RACDescription.h"
#import "RACDisposable.h"
#import "RACSignal.h"
#import "RACSubscriber.h"

@implementation NSText (RACSignalSupport)

- (RACSignal *)rac_textSignal {
@unsafeify(self);
return [[[[RACSignal
createSignal:^(id<RACSubscriber> subscriber) {
@strongify(self);
id observer = [NSNotificationCenter.defaultCenter addObserverForName:NSTextDidChangeNotification object:self queue:nil usingBlock:^(NSNotification *note) {
[subscriber sendNext:note.object];
}];

return [RACDisposable disposableWithBlock:^{
[NSNotificationCenter.defaultCenter removeObserver:observer];
}];
}]
map:^(NSText *text) {
return [text.string copy];
}]
startWith:[self.string copy]]
setNameWithFormat:@"%@ -rac_textSignal", RACDescription(self)];
}

@end
Loading

0 comments on commit 241b0b8

Please sign in to comment.