Skip to content

Instantly share code, notes, and snippets.

View jspahrsummers's full-sized avatar

Justin Spahr-Summers jspahrsummers

View GitHub Profile
[NSWindow ex_patchInstanceSelector: @selector(sendEvent:) withReplacementBlock: ^(EXPatchIMP *patch) {
return ^(NSEvent *event) {
NSWindow *window = (__bridge NSWindow *) patch->self;
if (window != self.window && [event type] == NSLeftMouseUp && [window isKeyWindow]) {
/* The last view seen */
static NSView *lastView = nil;
NSPoint point = [window.contentView convertPoint: [event locationInWindow] fromView: nil];
NSView *hitView = [window.contentView hitTest: point];
@jspahrsummers
jspahrsummers / ImageLoading.m
Last active December 29, 2015 03:59
Using -flatten:withPolicy: (from ReactiveCocoa 3.0) and related operators to deal with producers that can outstrip consumers
// Asynchronously loads UIImages from the given URLs, but throttles the loading
// to keep memory and CPU usage sane.
- (RACSignal *)loadImagesAtURLs:(NSArray *)imageURLs {
// Map each URL to a signal of work. The result is a signal of work signals.
return [[imageURLs.rac_signal
map:^(NSURL *imageURL) {
return [[[[NSURLConnection
// Load the URL asynchronously.
rac_sendAsynchronousRequest:[NSURLRequest requestWithURL:imageURL]]
reduceEach:^(NSURLResponse *response, NSData *data) {
@jspahrsummers
jspahrsummers / gist:7541192
Last active December 28, 2015 18:09
A cooperative reader-writer pattern using signal generators from ReactiveCocoa 3.0
// Reads until the given stream is exhausted, creating and subscribing to a new
// signal using `writer` for each chunk of data that is read.
//
// Sends completed or error.
- (RACSignal *)readStream:(Stream *)stream writingWithGenerator:(RACSignalGenerator *)writer {
return [[[RACSignal
create:^(id<RACSubscriber> subscriber) {
while (!subscriber.disposable.disposed && stream.hasData) {
NSError *error = nil;
NSData *data = [stream readData:&error];
@jspahrsummers
jspahrsummers / gist:7080228
Last active May 2, 2019 11:56
Advantages and disadvantages to RACCommand under MVVM

MVVM example

For a command that initiates a network request when:

  • The network connection is up (precondition)
  • The network request is not already in progress (enforced serialization)

The lifecycle proceeds as follows:

  1. The view model exposes the command and describes its behavior
@jspahrsummers
jspahrsummers / gist:7045771
Last active December 25, 2015 21:49
The RACCommand example from https://gist.github.com/jonsterling/7001562 with postcomposition instead.
- (id)initWithEnabled:(RACSignal *)enabled provider:(RACSignalProvider *)provider {
if (self = [super init]) {
_enabled = [enabledSignal replayLast];
_decoratedProvider = [[[RACSignalProvider alloc]
initWithBlock:^(id input) {
return [[self.enabled take:1] flattenMap:^(NSNumber *enabled) {
if (enabled.boolValue) {
return [RACSignal return:input];
} else {
@jspahrsummers
jspahrsummers / gist:7000136
Last active December 25, 2015 15:39
Various use cases that need to be considered for ReactiveCocoa 3.0, along with their current RAC 2.x or Rx solutions

Use cases

  1. Turning an eager, pure computation into a lazy one: RACSequence, RACSignal
  2. Side-effecting work that is safe to perform multiple times: RACSignal, RACCommand
  3. Side-effecting work that is safe to perform multiple times serially, but not concurrently: RACCommand, RefCount()
    • RACScheduler would seem to apply here, but execution could become interleaved and thus not serial
  4. Side-effecting work that should only be performed once, then memoized: RACMulticastConnection with a RACReplaySubject, RACSequence
  5. Enabling/disabling a UI based on whether work can be performed: RACCommand, RACReplaySubject
    • Replaying is a Good Idea™ because this information may arrive before the UI is ready for it
  6. Updating a UI with information about work in progress: RACCommand, RACSubject
@jspahrsummers
jspahrsummers / gist:6940184
Last active December 25, 2015 07:38
lol recursive blocks
__block void (^myRecursiveBlock)(int);
id myBlock = ^(int x) {
if (x > 5) {
// Release the block from its own implicit retain cycle.
myRecursiveBlock = nil;
} else {
myRecursiveBlock(x + 1);
}
};
@jspahrsummers
jspahrsummers / gist:6400596
Created August 31, 2013 20:57
Error installing ResourceT using Cabal and GHC 7.6.3.
Control/Monad/Trans/Resource.hs:613:24:
Could not deduce (m ~ IO)
from the context (MonadBaseControl IO m)
bound by the type signature for
resourceForkIO :: MonadBaseControl IO m =>
ResourceT m () -> ResourceT m ThreadId
at Control/Monad/Trans/Resource.hs:601:19-81
`m' is a rigid type variable bound by
the type signature for
resourceForkIO :: MonadBaseControl IO m =>
@jspahrsummers
jspahrsummers / gist:5812222
Last active December 18, 2015 16:29
Make "self" cause a compilation error only within blocks.
#define self \
( \
_Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wunused-value\"") self, \
/* Depends on _cmd being a const copy, like other captured variables. */ \
_Pragma("clang diagnostic pop") (*(_cmd = _cmd, &self)) \
)
// Replace libextobjc's @weakify with one that's aware of the "self" macro.
#undef ext_weakify_
#define ext_weakify_(INDEX, CONTEXT, VAR) \
@jspahrsummers
jspahrsummers / gist:5780224
Last active September 26, 2019 05:24
Untested proof of concept for a better @weakify macro.
#define $(...) \
({ \
__weak __typeof__(self) weakSelf = self; \
\
^(__VA_ARGS__) { \
__strong __typeof__(weakSelf) self = weakSelf; \
$_body_
#define $_body_(...) \
__VA_ARGS__ \