├── .gitignore
├── Examples
├── Chain Examples.xcodeproj
│ ├── project.pbxproj
│ └── project.xcworkspace
│ │ └── contents.xcworkspacedata
├── Examples
│ ├── Controls
│ │ ├── CAEControlsExample.h
│ │ ├── CAEControlsExample.m
│ │ └── CAEControlsExample.xib
│ ├── Scroll View
│ │ ├── CAEScrollViewExample.h
│ │ └── CAEScrollViewExample.m
│ ├── Stopwatch
│ │ ├── CAEStopwatchExample.h
│ │ └── CAEStopwatchExample.m
│ └── Throttled
│ │ ├── CAEThrottledExample.h
│ │ └── CAEThrottledExample.m
├── Images.xcassets
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ └── LaunchImage.launchimage
│ │ └── Contents.json
├── Info.plist
└── Sources
│ ├── CAEAppDelegate.h
│ ├── CAEAppDelegate.m
│ ├── CAEExampleViewController.h
│ ├── CAEExampleViewController.m
│ ├── CAEListViewController.h
│ ├── CAEListViewController.m
│ ├── Prefix.pch
│ └── main.m
├── LICENSE
├── Objective-Chain.podspec
├── Objective-Chain.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ └── contents.xcworkspacedata
└── xcshareddata
│ ├── xcdebugger
│ └── Breakpoints_v2.xcbkptlist
│ └── xcschemes
│ ├── OS X Library.xcscheme
│ └── iOS Library.xcscheme
├── README.md
├── Sources
├── Foundation
│ ├── Consumers
│ │ ├── OCAConsumer.h
│ │ ├── OCAInvoker.h
│ │ ├── OCAInvoker.m
│ │ ├── OCASubscriber.h
│ │ ├── OCASubscriber.m
│ │ ├── OCASwitch.h
│ │ └── OCASwitch.m
│ ├── Mediators
│ │ ├── OCABridge.h
│ │ ├── OCABridge.m
│ │ ├── OCAContext.h
│ │ ├── OCAContext.m
│ │ ├── OCAFilter.h
│ │ ├── OCAFilter.m
│ │ ├── OCALowPassFilter.h
│ │ ├── OCALowPassFilter.m
│ │ ├── OCAMediator.h
│ │ ├── OCAMediator.m
│ │ ├── OCAThrottle.h
│ │ └── OCAThrottle.m
│ ├── OCAFoundation.h
│ ├── OCAObject.h
│ ├── OCAObject.m
│ ├── Predicates
│ │ ├── OCAPredicate.h
│ │ └── OCAPredicate.m
│ ├── Producers
│ │ ├── OCACommand.h
│ │ ├── OCACommand.m
│ │ ├── OCAHub.h
│ │ ├── OCAHub.m
│ │ ├── OCAInterpolator.h
│ │ ├── OCAInterpolator.m
│ │ ├── OCANotificator.h
│ │ ├── OCANotificator.m
│ │ ├── OCAProducer+Subclass.h
│ │ ├── OCAProducer.h
│ │ ├── OCAProducer.m
│ │ ├── OCAProperty.h
│ │ ├── OCAProperty.m
│ │ ├── OCATimer.h
│ │ └── OCATimer.m
│ ├── Transformers
│ │ ├── OCAMath.h
│ │ ├── OCAMath.m
│ │ ├── OCATransformer+Base.h
│ │ ├── OCATransformer+Base.m
│ │ ├── OCATransformer+Collections.h
│ │ ├── OCATransformer+Collections.m
│ │ ├── OCATransformer+Core.h
│ │ ├── OCATransformer+Core.m
│ │ ├── OCATransformer+NSData.h
│ │ ├── OCATransformer+NSData.m
│ │ ├── OCATransformer+NSDate.h
│ │ ├── OCATransformer+NSDate.m
│ │ ├── OCATransformer+NSString.h
│ │ ├── OCATransformer+NSString.m
│ │ └── OCATransformer.h
│ └── Utilities
│ │ ├── Accessors
│ │ ├── OCAAccessor.h
│ │ ├── OCAAccessor.m
│ │ ├── OCAIndexAccessor.h
│ │ ├── OCAIndexAccessor.m
│ │ ├── OCAKeyPathAccessor.h
│ │ ├── OCAKeyPathAccessor.m
│ │ ├── OCAStructureAccessor.h
│ │ └── OCAStructureAccessor.m
│ │ ├── NSArray+Ordinals.h
│ │ ├── NSArray+Ordinals.m
│ │ ├── NSValue+Boxing.h
│ │ ├── NSValue+Boxing.m
│ │ ├── OCADebug.h
│ │ ├── OCADebug.m
│ │ ├── OCADecomposer.h
│ │ ├── OCADecomposer.m
│ │ ├── OCAInvocationCatcher.h
│ │ ├── OCAInvocationCatcher.m
│ │ ├── OCAKeyValueChange.h
│ │ ├── OCAKeyValueChange.m
│ │ ├── OCAMutableArrayProxy.h
│ │ ├── OCAMutableArrayProxy.m
│ │ ├── OCAPlaceholderObject.h
│ │ ├── OCAPlaceholderObject.m
│ │ ├── OCAQueue.h
│ │ ├── OCAQueue.m
│ │ ├── OCASemaphore.h
│ │ ├── OCASemaphore.m
│ │ ├── OCASwizzling.h
│ │ ├── OCASwizzling.m
│ │ ├── OCAVariadic.h
│ │ └── OCAVariadic.m
├── Geometry
│ ├── OCAGeometry+Functions.h
│ ├── OCAGeometry+Functions.m
│ ├── OCAGeometry.h
│ ├── Predicates
│ │ ├── OCAPredicate+CATransform3D.h
│ │ ├── OCAPredicate+CATransform3D.m
│ │ ├── OCAPredicate+CGAffineTransform.h
│ │ ├── OCAPredicate+CGAffineTransform.m
│ │ ├── OCAPredicate+CGPoint.h
│ │ ├── OCAPredicate+CGPoint.m
│ │ ├── OCAPredicate+CGRect.h
│ │ ├── OCAPredicate+CGRect.m
│ │ ├── OCAPredicate+CGSize.h
│ │ ├── OCAPredicate+CGSize.m
│ │ ├── OCAPredicate+UIEdgeInsets.h
│ │ └── OCAPredicate+UIEdgeInsets.m
│ └── Transformers
│ │ ├── OCATransformer+CATransform3D.h
│ │ ├── OCATransformer+CATransform3D.m
│ │ ├── OCATransformer+CGAffineTransform.h
│ │ ├── OCATransformer+CGAffineTransform.m
│ │ ├── OCATransformer+CGPoint.h
│ │ ├── OCATransformer+CGPoint.m
│ │ ├── OCATransformer+CGRect.h
│ │ ├── OCATransformer+CGRect.m
│ │ ├── OCATransformer+CGSize.h
│ │ ├── OCATransformer+CGSize.m
│ │ ├── OCATransformer+UIEdgeInsets.h
│ │ └── OCATransformer+UIEdgeInsets.m
├── ObjectiveChain.h
├── README.md
└── UIKit
│ ├── Consumers
│ ├── OCAUIKit+UIButton.h
│ └── OCAUIKit+UIButton.m
│ ├── Mediators
│ ├── OCAContext+UIKit.h
│ ├── OCAContext+UIKit.m
│ ├── OCAFader.h
│ └── OCAFader.m
│ ├── OCAUIKit.h
│ ├── Producers
│ ├── OCATargetter.h
│ ├── OCATargetter.m
│ ├── UITextField+editedText.h
│ ├── UITextField+editedText.m
│ ├── UIView+Gestures.h
│ ├── UIView+Gestures.m
│ ├── UIView+tintColor.h
│ └── UIView+tintColor.m
│ ├── Transformers
│ ├── OCATransformer+UIColor.h
│ ├── OCATransformer+UIColor.m
│ ├── OCATransformer+UIImage.h
│ └── OCATransformer+UIImage.m
│ └── Utilities
│ ├── OCAErrorRecoveryAttempter.h
│ └── OCAErrorRecoveryAttempter.m
└── Tests
├── Info.plist
├── OCAAccessorTest.m
├── OCAConnectionTest.m
├── OCAFilterTest.m
├── OCAFoundationTest.m
├── OCAHubTest.m
├── OCAInterpolatorTest.m
├── OCAInvokerTest.m
├── OCAMathTest.m
├── OCAObjectTest.m
├── OCAPropertyTest.m
├── OCAQueueTest.m
├── OCASwitchTest.m
├── OCAThrottleTest.m
├── OCATransformerTest.m
├── OCAVariadicTest.m
└── Prefix.pch
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | .DS_Store
3 | */build/*
4 | *.pbxuser
5 | !default.pbxuser
6 | *.mode1v3
7 | !default.mode1v3
8 | *.mode2v3
9 | !default.mode2v3
10 | *.perspectivev3
11 | !default.perspectivev3
12 | xcuserdata
13 | profile
14 | *.moved-aside
15 | DerivedData
16 | .idea/
17 | *.hmap
18 | *.xccheckout
19 |
20 | #CocoaPods
21 | Pods
22 |
--------------------------------------------------------------------------------
/Examples/Chain Examples.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Examples/Examples/Controls/CAEControlsExample.h:
--------------------------------------------------------------------------------
1 | //
2 | // CAEControlsExample.h
3 | // Chain Examples
4 | //
5 | // Created by Martin Kiss on 14.1.14.
6 | // Copyright (c) 2014 iMartin Kiss. All rights reserved.
7 | //
8 |
9 | #import "CAEExampleViewController.h"
10 |
11 | @interface CAEControlsExample : CAEExampleViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/Examples/Examples/Scroll View/CAEScrollViewExample.h:
--------------------------------------------------------------------------------
1 | //
2 | // CAEScrollViewExample.h
3 | // Chain Examples
4 | //
5 | // Created by Martin Kiss on 15.1.14.
6 | // Copyright (c) 2014 iMartin Kiss. All rights reserved.
7 | //
8 |
9 | #import "CAEExampleViewController.h"
10 |
11 | @interface CAEScrollViewExample : CAEExampleViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/Examples/Examples/Stopwatch/CAEStopwatchExample.h:
--------------------------------------------------------------------------------
1 | //
2 | // CAEStopwatchExample.h
3 | // Chain Examples
4 | //
5 | // Created by Martin Kiss on 17.1.14.
6 | // Copyright (c) 2014 iMartin Kiss. All rights reserved.
7 | //
8 |
9 | #import "CAEExampleViewController.h"
10 |
11 | @interface CAEStopwatchExample : CAEExampleViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/Examples/Examples/Throttled/CAEThrottledExample.h:
--------------------------------------------------------------------------------
1 | //
2 | // CAEThrottledExample.h
3 | // Chain Examples
4 | //
5 | // Created by Martin Kiss on 10.3.14.
6 | // Copyright (c) 2014 iMartin Kiss. All rights reserved.
7 | //
8 |
9 | #import "CAEExampleViewController.h"
10 |
11 | @interface CAEThrottledExample : CAEExampleViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/Examples/Examples/Throttled/CAEThrottledExample.m:
--------------------------------------------------------------------------------
1 | //
2 | // CAEThrottledExample.m
3 | // Chain Examples
4 | //
5 | // Created by Martin Kiss on 10.3.14.
6 | // Copyright (c) 2014 iMartin Kiss. All rights reserved.
7 | //
8 |
9 | #import "CAEThrottledExample.h"
10 |
11 |
12 |
13 |
14 |
15 | @interface CAEThrottledExample ()
16 |
17 |
18 |
19 | @property (nonatomic, readwrite, assign) NSUInteger integer;
20 | @property (nonatomic, readwrite, strong) UILabel *label;
21 | @property (nonatomic, readwrite, strong) UISlider *slider;
22 |
23 |
24 |
25 | @end
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 | @implementation CAEThrottledExample
37 |
38 |
39 |
40 |
41 |
42 | #pragma mark Example Info & Registration
43 |
44 |
45 | + (void)load {
46 | [self registerExample];
47 | }
48 |
49 |
50 | + (NSString *)exampleTitle {
51 | return @"Throttled";
52 | }
53 |
54 |
55 | + (NSString *)exampleSubtitle {
56 | return @"Limiting frequency of events";
57 | }
58 |
59 |
60 | + (NSString *)exampleDescription {
61 | return @"This example uses Throttling mechanism to limit how often is value from Slider applied. It then animates the changed value by interpolating from previous to the current. Total of 2 chains";
62 | }
63 |
64 |
65 | + (NSString *)exampleAuthor {
66 | return @"iMartin Kiss";
67 | }
68 |
69 |
70 | + (NSDate *)exampleDate {
71 | return [self day:10 month:3 year:2014];
72 | }
73 |
74 |
75 |
76 |
77 |
78 | #pragma mark Setup
79 |
80 |
81 | - (void)setupViews {
82 | [super setupViews];
83 |
84 | self.label = ({
85 | UILabel *label = [[UILabel alloc] init];
86 | label.font = [UIFont fontWithName:@"HelveticaNeue-UltraLight" size:90];
87 | label.backgroundColor = [UIColor clearColor];
88 | label.frame = CGRectMake(20, 64+40, 280, label.font.pointSize);
89 | label.text = @"1000";
90 | label.textAlignment = NSTextAlignmentCenter;
91 |
92 | [self.view addSubview:label];
93 | label;
94 | });
95 |
96 | self.slider = ({
97 | UISlider *slider = [[UISlider alloc] init];
98 | slider.frame = CGRectMake(20, CGRectGetMaxY(self.label.frame) + 60, 280, 44);
99 | slider.minimumValue = 0;
100 | slider.maximumValue = 100;
101 |
102 | [self.view addSubview:slider];
103 | slider;
104 | });
105 |
106 | }
107 |
108 |
109 | - (void)setupChains {
110 | [super setupChains];
111 | OCAWeakify(self);
112 |
113 | __block __weak OCAInterpolator *interpolator = nil; // Weak, because it will deallocate automatically once finished.
114 | [[OCAProperty(self, integer, NSUInteger) produceChanges]
115 | subscribeForClass:[OCAKeyValueChangeSetting class] handler:^(OCAKeyValueChangeSetting *change) {
116 | OCAStrongify(self);
117 |
118 | [interpolator finishWithLastValue:YES]; // Will stop and display final value.
119 |
120 | NSUInteger previous = [change.previousValue unsignedIntegerValue];
121 | NSUInteger latest = [change.latestValue unsignedIntegerValue];
122 | interpolator = [OCAInterpolator interpolatorWithDuration:0.5
123 | frequency:30
124 | fromValue:previous
125 | toValue:latest];
126 |
127 | [[interpolator transformValues:
128 | [OCATransformer stringWithNumberStyle:NSNumberFormatterDecimalStyle fractionDigits:0],
129 | nil] connectTo:OCAProperty(self, label.text, NSString)];
130 | }];
131 |
132 | [[[self.slider producerForValue]
133 | throttleContinuous:1] // Sends latest value every 1 second
134 | connectTo:OCAProperty(self, integer, NSUInteger)];
135 | }
136 |
137 |
138 |
139 |
140 |
141 | @end
142 |
143 |
144 |
--------------------------------------------------------------------------------
/Examples/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "29x29",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "40x40",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "60x60",
16 | "scale" : "2x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/Examples/Images.xcassets/LaunchImage.launchimage/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "orientation" : "portrait",
5 | "idiom" : "iphone",
6 | "extent" : "full-screen",
7 | "minimum-system-version" : "7.0",
8 | "scale" : "2x"
9 | },
10 | {
11 | "orientation" : "portrait",
12 | "idiom" : "iphone",
13 | "subtype" : "retina4",
14 | "extent" : "full-screen",
15 | "minimum-system-version" : "7.0",
16 | "scale" : "2x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/Examples/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | Obj-Chain
9 | CFBundleExecutable
10 | ${EXECUTABLE_NAME}
11 | CFBundleIdentifier
12 | com.iMartinKiss.Objective-Chain.${PRODUCT_NAME:rfc1034identifier}
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | ${PRODUCT_NAME}
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | 1.0
25 | LSRequiresIPhoneOS
26 |
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/Examples/Sources/CAEAppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // CAEAppDelegate.h
3 | // Chain Examples
4 | //
5 | // Created by Martin Kiss on 14.1.14.
6 | // Copyright (c) 2014 iMartin Kiss. All rights reserved.
7 | //
8 |
9 |
10 |
11 |
12 |
13 | @interface CAEAppDelegate : UIResponder
14 |
15 |
16 | @property (strong, nonatomic) UIWindow *window;
17 |
18 |
19 | @end
20 |
--------------------------------------------------------------------------------
/Examples/Sources/CAEAppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // CAEAppDelegate.m
3 | // Chain Examples
4 | //
5 | // Created by Martin Kiss on 14.1.14.
6 | // Copyright (c) 2014 iMartin Kiss. All rights reserved.
7 | //
8 |
9 | #import "CAEAppDelegate.h"
10 | #import "CAEListViewController.h"
11 |
12 |
13 |
14 |
15 |
16 | @implementation CAEAppDelegate
17 |
18 |
19 |
20 |
21 |
22 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
23 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
24 | self.window.backgroundColor = [UIColor blackColor];
25 |
26 | CAEListViewController *listViewController = [[CAEListViewController alloc] init];
27 | self.window.rootViewController = [[UINavigationController alloc] initWithRootViewController:listViewController];
28 |
29 | [self.window makeKeyAndVisible];
30 | return YES;
31 | }
32 |
33 |
34 |
35 |
36 |
37 | @end
38 |
39 |
40 |
--------------------------------------------------------------------------------
/Examples/Sources/CAEExampleViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // CAEExampleViewController.h
3 | // Chain Examples
4 | //
5 | // Created by Martin Kiss on 14.1.14.
6 | // Copyright (c) 2014 iMartin Kiss. All rights reserved.
7 | //
8 |
9 |
10 | #import "ObjectiveChain.h"
11 |
12 |
13 |
14 |
15 |
16 | @interface CAEExampleViewController : UIViewController
17 |
18 |
19 |
20 | #pragma mark Registering Subclasses
21 |
22 | + (void)registerExample;
23 |
24 | + (NSArray *)allSubclasses;
25 |
26 |
27 | #pragma mark Getting Info about Examples
28 |
29 | + (NSString *)exampleTitle;
30 | + (NSString *)exampleSubtitle;
31 | + (NSString *)exampleDescription;
32 | + (NSString *)exampleAuthor;
33 | + (NSDate *)exampleDate;
34 |
35 | + (NSDate *)day:(NSUInteger)day month:(NSUInteger)month year:(NSUInteger)year;
36 |
37 |
38 | #pragma mark Setup the Example
39 |
40 | - (void)setupViews;
41 | - (void)setupChains;
42 |
43 |
44 | #pragma mark State Properties
45 |
46 | @property (nonatomic, readonly, assign) BOOL partiallyVisible;
47 | @property (nonatomic, readonly, assign) BOOL fullyVisible;
48 |
49 |
50 |
51 | @end
52 |
53 |
54 |
--------------------------------------------------------------------------------
/Examples/Sources/CAEListViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // CAEListViewController.h
3 | // Chain Examples
4 | //
5 | // Created by Martin Kiss on 14.1.14.
6 | // Copyright (c) 2014 iMartin Kiss. All rights reserved.
7 | //
8 |
9 |
10 |
11 |
12 |
13 | @interface CAEListViewController : UITableViewController
14 |
15 | @end
16 |
17 |
18 |
--------------------------------------------------------------------------------
/Examples/Sources/CAEListViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // CAEListViewController.m
3 | // Chain Examples
4 | //
5 | // Created by Martin Kiss on 14.1.14.
6 | // Copyright (c) 2014 iMartin Kiss. All rights reserved.
7 | //
8 |
9 | #import "CAEListViewController.h"
10 | #import "CAEExampleViewController.h"
11 |
12 |
13 |
14 |
15 |
16 | @interface CAEListViewController ()
17 |
18 |
19 | @property (nonatomic, readonly, strong) NSArray *exampleClasses;
20 |
21 |
22 | @end
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | @implementation CAEListViewController
34 |
35 |
36 |
37 |
38 |
39 | #pragma mark Creating & Loading
40 |
41 |
42 | - (instancetype)initWithStyle:(UITableViewStyle)style {
43 | self = [super initWithStyle:UITableViewStyleGrouped];
44 | if (self) {
45 | self.title = @"Objective-Chain Examples";
46 | self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] init];
47 | self.navigationItem.backBarButtonItem.title = @"Examples";
48 |
49 | NSSortDescriptor *sortByDate = [NSSortDescriptor sortDescriptorWithKey:OCAKPUnsafe(exampleDate) ascending:YES];
50 | self->_exampleClasses = [[CAEExampleViewController allSubclasses] sortedArrayUsingDescriptors:@[ sortByDate ]];
51 | }
52 | return self;
53 | }
54 |
55 |
56 | - (void)viewDidLoad {
57 | [super viewDidLoad];
58 |
59 | UILabel *footnote = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, self.tableView.bounds.size.width, 100)];
60 | footnote.textColor = [UIColor darkGrayColor];
61 | footnote.numberOfLines = 0;
62 | footnote.font = [UIFont fontWithName:@"HelveticaNeue-Light" size:[UIFont smallSystemFontSize]];
63 | footnote.textAlignment = NSTextAlignmentCenter;
64 | footnote.text =
65 | @"github.com/iMartinKiss/Objective-Chain" @"\n"
66 | @"\n"
67 | @"Copyright © 2014 Martin Kiss" @"\n"
68 | @"Licensed under MIT License";
69 | self.tableView.tableFooterView = footnote;
70 | }
71 |
72 |
73 |
74 |
75 |
76 | #pragma mark tTable View
77 |
78 |
79 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
80 | return self.exampleClasses.count;
81 | }
82 |
83 |
84 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
85 | static NSString *CAEListCellIdentifier = @"CAEListCellIdentifier";
86 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CAEListCellIdentifier];
87 | if ( ! cell) {
88 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CAEListCellIdentifier];
89 | cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
90 | }
91 |
92 | Class exampleClass = [self.exampleClasses objectAtIndex:indexPath.row];
93 | cell.textLabel.text = [exampleClass exampleTitle];
94 | cell.detailTextLabel.text = [exampleClass exampleSubtitle];
95 |
96 | return cell;
97 | }
98 |
99 |
100 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
101 | Class exampleClass = [self.exampleClasses objectAtIndex:indexPath.row];
102 | CAEExampleViewController *example = [[exampleClass alloc] init];
103 | [self.navigationController pushViewController:example animated:YES];
104 | }
105 |
106 |
107 |
108 |
109 |
110 | @end
111 |
--------------------------------------------------------------------------------
/Examples/Sources/Prefix.pch:
--------------------------------------------------------------------------------
1 | //
2 | // Prefix.pch
3 | // Chain Examples
4 | //
5 | // Created by Martin Kiss on 14.1.14.
6 | // Copyright (c) 2014 iMartin Kiss. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 | #import
12 |
--------------------------------------------------------------------------------
/Examples/Sources/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // Chain Examples
4 | //
5 | // Created by Martin Kiss on 14.1.14.
6 | // Copyright (c) 2014 iMartin Kiss. All rights reserved.
7 | //
8 |
9 | #import "CAEAppDelegate.h"
10 |
11 |
12 |
13 | int main(int argc, char * argv[]) {
14 | @autoreleasepool {
15 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([CAEAppDelegate class]));
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Martin Kiss
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/Objective-Chain.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 |
3 | s.name = "Objective-Chain"
4 | s.version = "0.2.0"
5 | s.summary = "Object-oriented reactive framework, inspired by ReactiveCocoa"
6 | s.homepage = "https://github.com/iMartinKiss/Objective-Chain"
7 | s.license = { :type => "MIT", :file => "LICENSE" }
8 |
9 | s.author = { "Martin Kiss" => "martin.kiss@me.com" }
10 |
11 | s.source = { :git => "https://github.com/iMartinKiss/Objective-Chain.git", :tag => "#{s.version}" }
12 |
13 | s.framework = "Foundation"
14 | s.framework = "UIKit"
15 |
16 | s.requires_arc = true
17 |
18 | s.source_files = "Sources/**/*.{h,m}"
19 |
20 | end
21 |
--------------------------------------------------------------------------------
/Objective-Chain.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Objective-Chain.xcodeproj/xcshareddata/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
8 |
14 |
15 |
17 |
19 |
20 |
21 |
22 |
23 |
37 |
38 |
39 |
40 |
41 |
43 |
49 |
50 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/Objective-Chain.xcodeproj/xcshareddata/xcschemes/OS X Library.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
55 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
74 |
76 |
77 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/Objective-Chain.xcodeproj/xcshareddata/xcschemes/iOS Library.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
55 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
74 |
76 |
77 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/Sources/Foundation/Consumers/OCAConsumer.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCAConsumer.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 30.12.13.
6 | // Copyright © 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 |
12 |
13 |
14 |
15 | /*! Consumer is abstract receiver of values that are send from Producers.
16 | * Consumers are retained by all Producers from whose they receive values .
17 | */
18 | @protocol OCAConsumer
19 |
20 |
21 |
22 | @required
23 |
24 | //! Return a class of values that your instance consumes. Retunr nil or NSObject for any values.
25 | - (Class)consumedValueClass;
26 |
27 | //! Called after Producer sends new value. Do whatever your implementation requires. Your Consumer can receive from multiple Producers and you don't have a reference to them unless you create it.
28 | - (void)consumeValue:(id)value;
29 |
30 | //! Called after Producer finishes sending values. Your Consumer can receive from multiple Producers, so this MAY get called multiple times, one for each Producer.
31 | - (void)finishConsumingWithError:(NSError *)error;
32 |
33 |
34 |
35 | @optional
36 |
37 | //! Return an array of classes of values that your instance consumes. Implementing this method is optional and takes precedence over -consumedValueClass.
38 | - (NSArray *)consumedValueClasses;
39 |
40 |
41 |
42 | @end
43 |
44 |
45 |
--------------------------------------------------------------------------------
/Sources/Foundation/Consumers/OCAInvoker.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCAInvoker.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 27.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAObject.h"
10 | #import "OCAConsumer.h"
11 | #import "OCAProducer.h"
12 | #import "OCAPlaceholderObject.h"
13 | #import "OCAInvocationCatcher.h"
14 |
15 |
16 |
17 |
18 |
19 | @interface OCAInvoker : OCAObject < OCAConsumer >
20 |
21 |
22 |
23 | #define OCAInvocation(TARGET, METHOD) \
24 | (OCAInvoker *)({ \
25 | OCAInvoker *invoker = nil;\
26 | if (TARGET) {\
27 | OCAInvocationCatcher *catcher = [[OCAInvocationCatcher alloc] initWithTarget:(TARGET)]; \
28 | [(typeof(TARGET))catcher METHOD]; \
29 | invoker = [[OCAInvoker alloc] initWithInvocationCatcher:catcher]; \
30 | }\
31 | invoker;\
32 | }) \
33 |
34 | //TODO: OCAInvocation subclass to handle flaws of NSInvocation.
35 |
36 | - (instancetype)initWithInvocationCatcher:(OCAInvocationCatcher *)catcher;
37 |
38 | @property (atomic, readonly, weak) id target;
39 | @property (atomic, readonly, strong) NSInvocation *invocation;
40 |
41 |
42 |
43 | @end
44 |
45 |
46 |
--------------------------------------------------------------------------------
/Sources/Foundation/Consumers/OCASubscriber.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCASubscriber.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 30.12.13.
6 | // Copyright © 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAObject.h"
10 | #import "OCAConsumer.h"
11 |
12 |
13 |
14 | typedef void(^OCASubscriberValueHandler)(id value);
15 | typedef void(^OCASubscriberFinishHandler)(NSError *error);
16 |
17 |
18 |
19 |
20 |
21 | /*! Subscriber is concrete universal Consumer, that can be customized using blocks. It is best alternative to implementing your own Consumer class.
22 | * NOTE: Since Subscriber uses blocks and is retained by Producers, you have to be careful about retain cycles. Best way to avoid them is not to use Subscriber at all. There may be better alternatives to achieve your goal, for example Invoker or Property can handle many cases without creating retain cycles.
23 | */
24 | @interface OCASubscriber : OCAObject < OCAConsumer >
25 |
26 |
27 |
28 | #pragma mark Creating Subscriber
29 |
30 | //! Designated initializer. Use specific value class to opt-in to class-checking. All arguments may be nil.
31 | - (instancetype)initWithValueClass:(Class)valueClass
32 | valueHandler:(OCASubscriberValueHandler)valueHandler
33 | finishHandler:(OCASubscriberFinishHandler)finishHandler;
34 |
35 | //! Returns new Subscriber, that invokes given block once a value is received, but the value itself is ignored.
36 | + (instancetype)subscribe:(void(^)(void))handler;
37 |
38 | //! Returns new Subscriber with given value class and value handler.
39 | + (instancetype)subscribeForClass:(Class)valueClass handler:(OCASubscriberValueHandler)valueHandler;
40 |
41 | //! Returns new Subscriber with given value class, value handler and finish handler.
42 | + (instancetype)subscribeForClass:(Class)valueClass handler:(OCASubscriberValueHandler)valueHandler finish:(OCASubscriberFinishHandler)finishHandler;
43 |
44 |
45 | @property (atomic, readonly, strong) Class consumedValueClass;
46 |
47 |
48 | @end
49 |
50 |
51 |
--------------------------------------------------------------------------------
/Sources/Foundation/Consumers/OCASubscriber.m:
--------------------------------------------------------------------------------
1 | //
2 | // OCASubscriber.m
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 30.12.13.
6 | // Copyright © 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCASubscriber.h"
10 |
11 |
12 |
13 |
14 |
15 | @interface OCASubscriber ()
16 |
17 |
18 | @property (atomic, readonly, copy) OCASubscriberValueHandler valueHandler;
19 | @property (atomic, readonly, copy) OCASubscriberFinishHandler finishHandler;
20 |
21 |
22 | @end
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | @implementation OCASubscriber
34 |
35 |
36 |
37 |
38 |
39 | #pragma mark Creating Subscriber
40 |
41 |
42 | - (instancetype)init {
43 | return [self initWithValueClass:nil valueHandler:nil finishHandler:nil];
44 | }
45 |
46 |
47 | - (instancetype)initWithValueClass:(Class)valueClass
48 | valueHandler:(OCASubscriberValueHandler)valueHandler
49 | finishHandler:(OCASubscriberFinishHandler)finishHandler {
50 | self = [super init];
51 | if (self) {
52 | self->_consumedValueClass = valueClass;
53 | self->_valueHandler = valueHandler;
54 | self->_finishHandler = finishHandler;
55 | }
56 | return self;
57 | }
58 |
59 |
60 | + (instancetype)subscribe:(void (^)(void))handler {
61 | return [[self alloc] initWithValueClass:nil
62 | valueHandler:^(id value){
63 | handler();
64 | }
65 | finishHandler:nil];
66 | }
67 |
68 |
69 | + (instancetype)subscribeForClass:(Class)valueClass handler:(OCASubscriberValueHandler)valueHandler {
70 | return [[self alloc] initWithValueClass:valueClass valueHandler:valueHandler finishHandler:nil];
71 | }
72 |
73 |
74 | + (instancetype)subscribeForClass:(Class)valueClass handler:(OCASubscriberValueHandler)valueHandler finish:(OCASubscriberFinishHandler)finishHandler {
75 | return [[self alloc] initWithValueClass:valueClass valueHandler:valueHandler finishHandler:finishHandler];
76 | }
77 |
78 |
79 |
80 |
81 |
82 | #pragma mark Lifetime of Subscriber
83 |
84 |
85 | @synthesize consumedValueClass = _consumedValueClass;
86 |
87 |
88 | - (void)consumeValue:(id)value {
89 | // Values are validated on Producer's side.
90 | OCASubscriberValueHandler handler = self.valueHandler;
91 | if (handler) handler(value);
92 | }
93 |
94 |
95 | - (void)finishConsumingWithError:(NSError *)error {
96 | OCASubscriberFinishHandler handler = self.finishHandler;
97 | if (handler) handler(error);
98 | }
99 |
100 |
101 |
102 |
103 |
104 | @end
105 |
106 |
107 |
--------------------------------------------------------------------------------
/Sources/Foundation/Consumers/OCASwitch.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCASwitch.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 4.2.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAObject.h"
10 | #import "OCAConsumer.h"
11 |
12 |
13 |
14 |
15 |
16 | @interface OCASwitch : OCAObject
17 |
18 |
19 | - (instancetype)initWithDictionary:(NSDictionary *)consumersByPredicates;
20 |
21 | + (OCASwitch *)switchYes:(id)consumer no:(id)consumer;
22 | + (OCASwitch *)switchIf:(NSPredicate *)predicate then:(id)consumer else:(id)consumer;
23 |
24 | @property (atomic, readonly, strong) NSDictionary *consumersByPredicates;
25 | @property (atomic, readonly, strong) Class consumedValueClass;
26 |
27 |
28 | @end
29 |
30 |
31 |
--------------------------------------------------------------------------------
/Sources/Foundation/Consumers/OCASwitch.m:
--------------------------------------------------------------------------------
1 | //
2 | // OCASwitch.m
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 4.2.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCASwitch.h"
10 | #import "OCAPredicate.h"
11 |
12 |
13 |
14 |
15 |
16 | @implementation OCASwitch
17 |
18 |
19 |
20 | - (instancetype)initWithDictionary:(NSDictionary *)consumersByPredicates {
21 | self = [super init];
22 | if (self) {
23 | self->_consumersByPredicates = consumersByPredicates;
24 |
25 | NSArray *classes = [consumersByPredicates.allValues valueForKeyPath:OCAKP(OCASwitch, consumedValueClass)];
26 | self->_consumedValueClass = [self valueClassForClasses:classes];
27 | }
28 | return self;
29 | }
30 |
31 |
32 | + (OCASwitch *)switchYes:(id)trueConsumer no:(id)falseConsumer {
33 | return [[self alloc] initWithDictionary:@{
34 | [OCAPredicate isTrue]: trueConsumer ?: (id)[NSNull null],
35 | [OCAPredicate isFalse]: falseConsumer ?: (id)[NSNull null],
36 | }];
37 | }
38 |
39 |
40 | + (OCASwitch *)switchIf:(NSPredicate *)predicate then:(id)thenConsumer else:(id)elseConsumer {
41 | return [[self alloc] initWithDictionary:@{
42 | predicate: thenConsumer ?: (id)[NSNull null],
43 | [predicate negate]: elseConsumer ?: (id)[NSNull null],
44 | }];
45 | }
46 |
47 |
48 |
49 |
50 |
51 | - (void)consumeValue:(id)value {
52 | [self.consumersByPredicates enumerateKeysAndObjectsUsingBlock:^(NSPredicate *predicate, id consumer, BOOL *stop) {
53 | if (consumer != (id)[NSNull null]) {
54 | BOOL passed = [predicate evaluateWithObject:value];
55 | if ( ! passed) return;
56 |
57 | id consumedValue = value; // Always new variable.
58 | BOOL consumedValid = [self validateObject:&consumedValue ofClass:[consumer consumedValueClass]];
59 | if (consumedValid) {
60 | [consumer consumeValue:consumedValue];
61 | }
62 | }
63 | }];
64 | }
65 |
66 |
67 | - (void)finishConsumingWithError:(NSError *)error {
68 | self->_consumersByPredicates = nil;
69 | }
70 |
71 |
72 |
73 |
74 |
75 | @end
76 |
77 |
78 |
--------------------------------------------------------------------------------
/Sources/Foundation/Mediators/OCABridge.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCABridge.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 5.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAMediator.h"
10 |
11 |
12 |
13 |
14 |
15 | //! Bridge is a Mediator (Producer and Consumer), that simply passes values further with optional transformation.
16 | @interface OCABridge : OCAMediator
17 |
18 |
19 |
20 | #pragma mark Creating Bridge
21 |
22 | /*! Designated initializer. Initializes new Bridge that uses given transformer to transform values. Pass nil for no transformation on values.
23 | * The receiver will use transformer's +valueClass and +transformedValueClass methods to declare its own -valueClass and -consumedValueClass.
24 | */
25 | - (instancetype)initWithTransformer:(NSValueTransformer *)transformer;
26 |
27 | //! Creates new Bridge, that passes values of given class. If class is nil, it passes all values to its Consumers.
28 | + (OCABridge *)bridgeForClass:(Class)theClass;
29 |
30 | //! Create new Bridge, that uses sequence of transformers to transform values passed then to Consumers.
31 | + (OCABridge *)bridgeWithTransformers:(NSValueTransformer *)transformer, ... NS_REQUIRES_NIL_TERMINATION;
32 |
33 |
34 |
35 | #pragma mark Transformer
36 |
37 | //! Property that contains the transformer passed to initializer, if any.
38 | @property (atomic, readonly, strong) NSValueTransformer *transformer;
39 |
40 |
41 |
42 | @end
43 |
44 |
45 |
--------------------------------------------------------------------------------
/Sources/Foundation/Mediators/OCABridge.m:
--------------------------------------------------------------------------------
1 | //
2 | // OCABridge.m
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 5.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCABridge.h"
10 | #import "OCAProducer+Subclass.h"
11 | #import "OCATransformer+Core.h"
12 | #import "OCAVariadic.h"
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | @implementation OCABridge
24 |
25 |
26 |
27 |
28 |
29 | #pragma mark Creating Bridge
30 |
31 |
32 | - (instancetype)initWithValueClass:(Class)valueClass {
33 | NSValueTransformer *transformer = [[OCATransformer pass] specializeFromClass:valueClass toClass:valueClass];
34 | return [self initWithTransformer:transformer];
35 | }
36 |
37 |
38 | - (instancetype)initWithTransformer:(NSValueTransformer *)transformer {
39 | self = [super initWithValueClass:[transformer.class transformedValueClass]];
40 | if (self) {
41 | self->_transformer = transformer ?: [OCATransformer pass];
42 | }
43 | return self;
44 | }
45 |
46 |
47 | + (OCABridge *)bridgeForClass:(Class)class {
48 | NSValueTransformer *transformer = [[OCATransformer pass] specializeFromClass:class toClass:class];
49 | return [[self alloc] initWithTransformer:transformer];
50 | }
51 |
52 |
53 | + (OCABridge *)bridgeWithTransformers:(NSValueTransformer *)firstTransformer, ... NS_REQUIRES_NIL_TERMINATION {
54 | NSArray *transformersArray = OCAArrayFromVariadicArguments(firstTransformer);
55 | NSValueTransformer *transformer = (transformersArray.count <= 1
56 | ? transformersArray.firstObject
57 | : [OCATransformer sequence:transformersArray]);
58 | return [[self alloc] initWithTransformer:transformer];
59 | }
60 |
61 |
62 |
63 |
64 |
65 | #pragma mark Lifetime of Bridge
66 |
67 |
68 | - (Class)consumedValueClass {
69 | return [self.transformer.class valueClass];
70 | }
71 |
72 |
73 | - (void)consumeValue:(id)value {
74 | id transformedValue = [self.transformer transformedValue:value];
75 | [self produceValue:transformedValue];
76 | }
77 |
78 |
79 | - (void)finishConsumingWithError:(NSError *)error {
80 | [self finishProducingWithError:error];
81 | }
82 |
83 |
84 |
85 |
86 |
87 | @end
88 |
89 |
90 |
--------------------------------------------------------------------------------
/Sources/Foundation/Mediators/OCAContext.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCAContext.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 15.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAMediator.h"
10 | #import "OCAProperty.h"
11 | #import "OCAQueue.h"
12 |
13 |
14 |
15 | typedef void(^OCAContextExecutionBlock)(void);
16 | typedef void(^OCAContextDefinitionBlock)(OCAContextExecutionBlock executionBlock);
17 |
18 | extern OCAContextDefinitionBlock const OCAContextDefaultDefinitionBlock;
19 |
20 |
21 |
22 |
23 |
24 | /*! This class represents “a context”, that acts as a Consumer and a Producer. Received values are passed to Consumers in a known context.
25 | * “Context” for the purpose of this class means, that some code is executed before and after the main task.
26 | * Good example is use of NSLock (via +lock: constructor). When the Context object receives a value, it locks the Lock, passes the value to Consumers and then unlocks the Lock. This means, that the Consumers are invoked in a known “context”.
27 | * You can use one of the provided constructors or define your own using simple block.
28 | *
29 | * NOTE: Since this class is quite abstract, it allows you to do anything in the definition block. For thing like filtering, transformations or delaying the production of values, use appropriate Mediator subclasses. Don't abuse this Context.
30 | */
31 | @interface OCAContext : OCAMediator
32 |
33 |
34 |
35 | #pragma mark Creating Context
36 |
37 | //! Designated initializer. Definition block receives execution block that must be invoked. Execute desired code before and after the execution block as you wish. You may even nest the execution block into other block, for example for animations or queues.
38 | - (instancetype)initWithDefinitionBlock:(OCAContextDefinitionBlock)definitionBlock;
39 |
40 | //! Returns a Context that does nothing extra.
41 | + (OCAContext *)empty;
42 |
43 | //! Shorthand for designated initializer.
44 | + (OCAContext *)custom:(OCAContextDefinitionBlock)block;
45 |
46 | //! Returns a Context, that sets given value to the property, then produces consumed value and reverts the proeprty to previous value. For example, you may have a flag to supress observations of a notification, so you may want to set the flag to YES while sending it.
47 | + (OCAContext *)property:(OCAProperty *)property value:(id)value;
48 |
49 | //! Returns a Context, that produces consumed values on provided queue.
50 | + (OCAContext *)onQueue:(OCAQueue *)queue synchronous:(BOOL)synchronous;
51 |
52 | //! Returns a Context, that lock and unlocks provided NSLocking object. This means all chained Consumers are executed inside of locked context.
53 | + (OCAContext *)lock:(id)lock;
54 |
55 | //! Returns a Context, that uses @synchronized directive to produce values.
56 | + (OCAContext *)synchronized:(id)object;
57 |
58 | //! Returns a Context, that produces consumed values in auto-release pool.
59 | + (OCAContext *)autoreleasepool;
60 |
61 |
62 |
63 | #pragma mark Using Context
64 |
65 | //! Definition block as passed to the designated initializer.
66 | @property (atomic, readonly, strong) OCAContextDefinitionBlock definitionBlock;
67 |
68 | //! You can use this method to execute arbitrary code inside of the context represented by the receiver.
69 | - (void)execute:(OCAContextExecutionBlock)executionBlock;
70 |
71 |
72 |
73 | @end
74 |
75 |
76 |
--------------------------------------------------------------------------------
/Sources/Foundation/Mediators/OCAContext.m:
--------------------------------------------------------------------------------
1 | //
2 | // OCAContext.m
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 15.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAContext.h"
10 | #import "OCAProducer+Subclass.h"
11 |
12 |
13 |
14 |
15 |
16 | OCAContextDefinitionBlock const OCAContextDefaultDefinitionBlock = ^(OCAContextExecutionBlock executionBlock){
17 | executionBlock();
18 | };
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | @implementation OCAContext
30 |
31 |
32 |
33 |
34 |
35 | #pragma mark Creating Context
36 |
37 |
38 | - (instancetype)initWithValueClass:(Class)valueClass {
39 | return [self initWithDefinitionBlock:nil];
40 | }
41 |
42 |
43 | - (instancetype)initWithDefinitionBlock:(OCAContextDefinitionBlock)definitionBlock {
44 | self = [super initWithValueClass:nil];
45 | if (self) {
46 | self->_definitionBlock = definitionBlock ?: OCAContextDefaultDefinitionBlock;
47 | }
48 | return self;
49 | }
50 |
51 |
52 | + (OCAContext *)empty {
53 | return [[self alloc] initWithDefinitionBlock:nil];
54 | }
55 |
56 |
57 | + (OCAContext *)custom:(OCAContextDefinitionBlock)block {
58 | return [[self alloc] initWithDefinitionBlock:block];
59 | }
60 |
61 |
62 | + (OCAContext *)property:(OCAProperty *)property value:(id)value {
63 | return [[self alloc] initWithDefinitionBlock:^(OCAContextExecutionBlock executionBlock) {
64 | id originalValue = [property value];
65 | [property setValue:value];
66 |
67 | executionBlock(); // Block is executed when the property has desired value.
68 |
69 | [property setValue:originalValue];
70 | }];
71 | }
72 |
73 |
74 | + (OCAContext *)onQueue:(OCAQueue *)queue synchronous:(BOOL)synchronous {
75 | if (synchronous) {
76 | return [[self alloc] initWithDefinitionBlock:^(OCAContextExecutionBlock executionBlock) {
77 | [queue performBlockAndWait:executionBlock];
78 | }];
79 | }
80 | else {
81 | return [[self alloc] initWithDefinitionBlock:^(OCAContextExecutionBlock executionBlock) {
82 | [queue performBlockAndTryWait:executionBlock];
83 | }];
84 | }
85 | }
86 |
87 |
88 | + (OCAContext *)lock:(id)lock {
89 | OCAAssert(lock != nil, @"Lock is missing.") return nil;
90 | return [[OCAContext alloc] initWithDefinitionBlock:^(OCAContextExecutionBlock executionBlock) {
91 | [lock lock];
92 |
93 | executionBlock();
94 |
95 | [lock unlock];
96 | }];
97 | }
98 |
99 |
100 | + (OCAContext *)synchronized:(id)object {
101 | OCAAssert(object != nil, @"Object is missing.") return nil;
102 | return [[OCAContext alloc] initWithDefinitionBlock:^(OCAContextExecutionBlock executionBlock) {
103 | @synchronized(object) {
104 | executionBlock();
105 | }
106 | }];
107 | }
108 |
109 |
110 | + (OCAContext *)autoreleasepool {
111 | return [[OCAContext alloc] initWithDefinitionBlock:^(OCAContextExecutionBlock executionBlock) {
112 | @autoreleasepool {
113 | executionBlock();
114 | }
115 | }];
116 | }
117 |
118 |
119 |
120 |
121 |
122 | #pragma mark Using Context
123 |
124 |
125 | - (void)execute:(OCAContextExecutionBlock)executionBlock {
126 | self.definitionBlock(executionBlock);
127 | }
128 |
129 |
130 |
131 |
132 |
133 | #pragma mark Context as a Consumer
134 |
135 |
136 | - (Class)consumedValueClass {
137 | return nil;
138 | }
139 |
140 |
141 | - (void)consumeValue:(id)value {
142 | [self execute:^{
143 | [self produceValue:value];
144 | }];
145 | }
146 |
147 |
148 | - (void)finishConsumingWithError:(NSError *)error {
149 | [self execute:^{
150 | [self finishProducingWithError:error];
151 | }];
152 | }
153 |
154 |
155 |
156 |
157 |
158 | @end
159 |
160 |
161 |
--------------------------------------------------------------------------------
/Sources/Foundation/Mediators/OCAFilter.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCAFilter.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 16.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAMediator.h"
10 |
11 |
12 |
13 |
14 |
15 | //! Filter is a Mediator, that evaluates predicates on the values. If the object evaluates to Yes, it is passed further, otherwise no action is made.
16 | @interface OCAFilter : OCAMediator
17 |
18 |
19 |
20 | #pragma mark Creating Filter
21 |
22 | //! Designated initializer. Pass a predicate object you wish to evaluate on the values.
23 | - (instancetype)initWithPredicate:(NSPredicate *)predicate;
24 |
25 | //! Returns new Filer with given predicate.
26 | + (OCAFilter *)filterWithPredicate:(NSPredicate *)predicate;
27 |
28 | //! Returns new Filter, that remembers number of consumed objects and passes all of them once it receives more than \c count.
29 | + (OCAFilter *)filterThatSkipsFirst:(NSUInteger)count;
30 |
31 | //! Returns new Filter, that stores previously evaluated object and passes new objects only is they are not equal (as defined by isEqual: method).
32 | + (OCAFilter *)filterThatSkipsEqual;
33 |
34 |
35 |
36 | #pragma mark Using Filter
37 |
38 | //! Predicate as passed to the initializer.
39 | @property (atomic, readonly, strong) NSPredicate *predicate;
40 |
41 | //! This allows you to use Filter out of chain.
42 | - (BOOL)validateObject:(id)object;
43 |
44 |
45 |
46 | @end
47 |
48 |
49 |
--------------------------------------------------------------------------------
/Sources/Foundation/Mediators/OCAFilter.m:
--------------------------------------------------------------------------------
1 | //
2 | // OCAFilter.m
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 16.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAFilter.h"
10 | #import "OCAProducer+Subclass.h"
11 | #import "OCAPredicate.h"
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | @implementation OCAFilter
23 |
24 |
25 |
26 |
27 |
28 | #pragma mark Creating Filter
29 |
30 |
31 | - (instancetype)initWithValueClass:(Class)valueClass {
32 | NSPredicate *predicate = [OCAPredicate predicateForClass:valueClass block:^BOOL(id object) {
33 | return YES; // Pass all of that class.
34 | }];
35 | return [self initWithPredicate:predicate];
36 | }
37 |
38 |
39 | - (instancetype)initWithPredicate:(NSPredicate *)predicate {
40 | self = [super initWithValueClass:nil];
41 | if (self) {
42 | self->_predicate = predicate ?: [NSPredicate predicateWithValue:YES];
43 | }
44 | return self;
45 | }
46 |
47 |
48 | + (OCAFilter *)filterWithPredicate:(NSPredicate *)predicate {
49 | return [[self alloc] initWithPredicate:predicate];
50 | }
51 |
52 |
53 | + (OCAFilter *)filterThatSkipsFirst:(NSUInteger)countToSkip {
54 | // This instance uses __block variable that outlives the block scope.
55 | __block NSUInteger countOfValues = 0;
56 | NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
57 | countOfValues ++;
58 | return (countOfValues > countToSkip);
59 | }];
60 | return [[self alloc] initWithPredicate:predicate];
61 | }
62 |
63 |
64 | + (OCAFilter *)filterThatSkipsEqual {
65 | // This instance uses __block variable that outlives the block scope.
66 | __block id previouslyEvaluatedObject = nil; //TODO: Don't retain the previous forever. Maybe class and hash comparision would be enough.
67 | NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
68 | BOOL isEqual = OCAEqual(previouslyEvaluatedObject, evaluatedObject);
69 | previouslyEvaluatedObject = evaluatedObject;
70 | return ! isEqual;
71 | }];
72 | return [[self alloc] initWithPredicate:predicate];
73 | }
74 |
75 |
76 |
77 |
78 |
79 | #pragma mark Using Filter
80 |
81 |
82 | - (BOOL)validateObject:(id)object {
83 | BOOL compatible = [self isClass:[object class] compatibleWithClass:self.valueClass];
84 | return (compatible && [self.predicate evaluateWithObject:object]);
85 | }
86 |
87 |
88 |
89 |
90 |
91 | #pragma mark Filter as a Consumer
92 |
93 |
94 | - (Class)consumedValueClass {
95 | return nil;
96 | }
97 |
98 |
99 | - (void)consumeValue:(id)value {
100 | if ([self validateObject:value]) {
101 | [self produceValue:value];
102 | }
103 | }
104 |
105 |
106 | - (void)finishConsumingWithError:(NSError *)error {
107 | [self finishProducingWithError:error];
108 | }
109 |
110 |
111 |
112 |
113 |
114 | @end
115 |
116 |
117 |
--------------------------------------------------------------------------------
/Sources/Foundation/Mediators/OCALowPassFilter.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCALowPassFilter.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 23.10.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAMediator.h"
10 | #import "OCAMath.h"
11 | #import "OCAAccessor.h"
12 |
13 |
14 |
15 | /*! Low-pass filter is used for processing of real-time data with constant frequency. It produces smoother values than it receives.
16 | * Low-pass filters are good for animating data that changes very quickly, for example input from accelerometer or similar sensors.
17 | * You feed the filter by connecting it to a chain or setting input property. Input may come at any frequency, even irregularly.
18 | * You obtain the values by connecting the filter to other Consumer or by observing output property. Output is updated with operating frequency.
19 | *
20 | * Low-pass filter typically processes scalar values, but you may also provide class and its accessors to proces structured values.
21 | * Example: To process CGPoint values wrapped in NSValue, initialize the instance with NSValue class and accessors for X and Y components.
22 | * Processing non-scalar types is more computationally expensive and processed types must conform to NSCopying protocol.
23 | * When no accessors are specified, the filter uses -doubleValue method to convert the processed values to scalars.
24 | */
25 | @interface OCALowPassFilter : OCAMediator
26 |
27 |
28 | //! Creates new low-pass filter at 60Hz, with cut-off frequency of fraction * 60Hz.
29 | + (instancetype)filterWithTolerance:(OCAReal)fraction;
30 |
31 | //! Creates new low-pass filter that operates on given frequency and processes numbers. Cut-off frequency is used to soften the input.
32 | + (instancetype)filterWithFrequency:(OCAInteger)hertz cutoff:(OCAInteger)hertz;
33 |
34 | //! Creates new low-pass filter that operates on given frequency. You may specify custom class and its accessors that must return NSNumber objects.
35 | - (instancetype)initWithFrequency:(OCAInteger)hertz cutoff:(OCAInteger)hertz fadeNils:(BOOL)fadeNils inputClass:(Class)inputClass accessors:(OCAAccessor *)accessors, ... NS_REQUIRES_NIL_TERMINATION;
36 |
37 |
38 | //! Frequency on which this filter operates. Use 60Hz when you display the output values.
39 | @property (nonatomic, readonly) OCAInteger frequency;
40 | //! Cut-off frequency used to calculate intersteps of output values.
41 | @property (nonatomic, readonly) OCAInteger cutoff;
42 | //! Whether the filter treats nils as zero values (YES), or it immediately produces nils (NO).
43 | @property (nonatomic, readonly) BOOL fadeNils;
44 | //! Accessors used on input values to obtain numeric components and then used on copy of the input to set them.
45 | @property (nonatomic, readonly) NSArray *accessors;
46 |
47 |
48 | //! Last value that has passes to the filter. Set this to feed the filter, or use it as a Consumer.
49 | @property (atomic, strong) id input;
50 | //! Lats value produced by this filter. Read this property, observe it or connecting the filter to other Consumer.
51 | @property (atomic, readonly) id output;
52 |
53 |
54 | @end
55 |
56 |
57 |
--------------------------------------------------------------------------------
/Sources/Foundation/Mediators/OCAMediator.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCAMediator.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 27.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAProducer.h"
10 |
11 |
12 |
13 |
14 |
15 | /*! Mediator is abstract class, that inherits from Producer and conforms to Consumer protocol.
16 | * Subclasses of this class have two things in common:
17 | * 1. They don't really consume the values in meaningful manner.
18 | * 2. They don't really produce any genuine values.
19 | * Mediator serves as an intermediate step between original Producer and final Consumer and allows you to do powerful manipulations to the values that flow between them.
20 | *
21 | * Concrete Mediators allow you to transform the values, filter them, forward them in a known context, limit them, or temporarily stop them.
22 | */
23 | @interface OCAMediator : OCAProducer
24 |
25 | @end
26 |
27 |
28 |
--------------------------------------------------------------------------------
/Sources/Foundation/Mediators/OCAMediator.m:
--------------------------------------------------------------------------------
1 | //
2 | // OCAMediator.m
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 27.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAMediator.h"
10 | #import "OCAProducer+Subclass.h"
11 |
12 |
13 |
14 |
15 |
16 | @implementation OCAMediator
17 |
18 |
19 |
20 |
21 |
22 | - (Class)consumedValueClass {
23 | return nil;
24 | }
25 |
26 |
27 | - (void)consumeValue:(id)value {
28 | OCAAssert(NO, @"You can't use this abstract class!") return;
29 | }
30 |
31 |
32 | - (void)finishConsumingWithError:(NSError *)error {
33 | OCAAssert(NO, @"You can't use this abstract class!") return;
34 | }
35 |
36 |
37 |
38 |
39 |
40 | - (void)finishProducingWithError:(NSError *)error {
41 | if (self.isFinished) return;
42 |
43 | if (error) {
44 | // Errors are fatal, so we finish.
45 | [super finishProducingWithError:error];
46 | }
47 | else {
48 | // When Producer finished successfully, do nothing there should be more of them. And if not...
49 | }
50 | }
51 |
52 |
53 | - (void)dealloc {
54 | // ... we will finish once deallocated.
55 | [super finishProducingWithError:nil];
56 | }
57 |
58 |
59 |
60 |
61 |
62 | @end
63 |
64 |
65 |
--------------------------------------------------------------------------------
/Sources/Foundation/Mediators/OCAThrottle.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCAThrottle.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 2.2.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAMediator.h"
10 |
11 |
12 |
13 |
14 |
15 | /*! Throttle is a Mediator, that reduces frequency of production. It takes a time interval and can operate in two modes:
16 | * 1. Non-continuous: Will forward latest value after no new value came in given time interval.
17 | * 2. Continuous: Will forward one latest value repeatedly after the given interval.
18 | */
19 | @interface OCAThrottle : OCAMediator
20 |
21 |
22 |
23 | #pragma mark Creating Throttle
24 |
25 | //! Designated initializer. Pass desired interval and choose the continuation mode.
26 | - (instancetype)initWithInterval:(NSTimeInterval)interval continuous:(BOOL)continuous;
27 |
28 | //! Returns new Throttle with given interval and continuity.
29 | + (OCAThrottle *)throttleWithInterval:(NSTimeInterval)interval continuous:(BOOL)continuous;
30 |
31 |
32 |
33 | #pragma mark State of the Throttle
34 |
35 | //! Interval as passed to designated initializer.
36 | @property (atomic, readonly, assign) NSTimeInterval interval;
37 |
38 | //! Continuity flag as passed to designated initializer.
39 | @property (atomic, readonly, assign) BOOL isContinuous;
40 |
41 | //! Flag, that indicates whether the receiver is actually throttling a value.
42 | @property (atomic, readonly, assign) BOOL isThrottled;
43 |
44 | //! Last consumed value, that has not yet been forwarded.
45 | @property (atomic, readonly, strong) id lastThrottledValue;
46 |
47 |
48 |
49 | @end
50 |
51 |
52 |
--------------------------------------------------------------------------------
/Sources/Foundation/Mediators/OCAThrottle.m:
--------------------------------------------------------------------------------
1 | //
2 | // OCAThrottle.m
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 2.2.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAThrottle.h"
10 | #import "OCAProducer+Subclass.h"
11 | #import "OCATimer.h"
12 | #import "OCASubscriber.h"
13 |
14 |
15 |
16 |
17 |
18 | @interface OCAThrottle ()
19 |
20 |
21 | @property (atomic, readwrite, strong) OCATimer *timer;
22 | @property (atomic, readwrite, assign) BOOL isThrottled;
23 | @property (atomic, readwrite, strong) id lastThrottledValue;
24 | @property (atomic, readwrite, strong) OCASubscriber *subscriber;
25 |
26 |
27 | @end
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | @implementation OCAThrottle
39 |
40 |
41 |
42 |
43 |
44 | #pragma mark Creating Throttle
45 |
46 |
47 | - (instancetype)initWithValueClass:(Class)valueClass {
48 | return [self initWithInterval:0 continuous:NO];
49 | }
50 |
51 |
52 | - (instancetype)initWithInterval:(NSTimeInterval)interval continuous:(BOOL)continuous {
53 | self = [super initWithValueClass:nil];
54 | if (self) {
55 | OCAAssert(interval >= 0, @"I am not a time traveller.") interval = 0;
56 |
57 | self->_interval = interval;
58 | self->_isContinuous = continuous;
59 |
60 | OCAWeakify(self);
61 | self.subscriber = [[OCASubscriber alloc] initWithValueClass:nil
62 | valueHandler:^(id value) {
63 | OCAStrongify(self);
64 |
65 | self.timer = nil;
66 | self.isThrottled = NO;
67 | [self produceValue:self.lastThrottledValue];
68 | self.lastThrottledValue = nil;
69 |
70 | } finishHandler:nil];
71 | }
72 | return self;
73 | }
74 |
75 |
76 | + (OCAThrottle *)throttleWithInterval:(NSTimeInterval)delay {
77 | return [[self alloc] initWithInterval:delay continuous:NO];
78 | }
79 |
80 |
81 | + (OCAThrottle *)throttleWithInterval:(NSTimeInterval)delay continuous:(BOOL)continuous {
82 | return [[self alloc] initWithInterval:delay continuous:continuous];
83 | }
84 |
85 |
86 |
87 |
88 |
89 | #pragma mark Lifetime of Throttle
90 |
91 |
92 | - (void)consumeValue:(id)value {
93 | if (self.interval == 0) {
94 | [self produceValue:value];
95 | return;
96 | }
97 |
98 | self.lastThrottledValue = value;
99 | if (self.isContinuous && self.timer.isRunning) return;
100 |
101 | [self.timer stop];
102 | NSDate *fireDate = [NSDate dateWithTimeIntervalSinceNow:self.interval];
103 | self.timer = [[OCATimer alloc] initWithOwner:self queue:nil startDate:fireDate interval:0 leeway:0 endDate:nil];
104 | self.isThrottled = YES;
105 | [self.timer addConsumer:self.subscriber];
106 | }
107 |
108 |
109 | - (void)finishConsumingWithError:(NSError *)error {
110 | [self.timer stop];
111 | self.isThrottled = NO;
112 | self.lastThrottledValue = nil;
113 | [self finishProducingWithError:error];
114 | }
115 |
116 |
117 |
118 |
119 |
120 | @end
121 |
122 |
123 |
--------------------------------------------------------------------------------
/Sources/Foundation/OCAFoundation.h:
--------------------------------------------------------------------------------
1 | //
2 | // ObjectiveChain.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 30.12.13.
6 | // Copyright © 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 |
10 |
11 | /// Producers
12 |
13 | #import "OCAProducer.h"
14 | #import "OCACommand.h"
15 | #import "OCAHub.h"
16 | #import "OCAProperty.h"
17 | #import "OCATimer.h"
18 | #import "OCANotificator.h"
19 | #import "OCAInterpolator.h"
20 |
21 |
22 | /// Mediators
23 |
24 | #import "OCAMediator.h"
25 | #import "OCABridge.h"
26 | #import "OCAContext.h"
27 | #import "OCAFilter.h"
28 | #import "OCAThrottle.h"
29 | #import "OCALowPassFilter.h"
30 |
31 |
32 | /// Consumers
33 |
34 | #import "OCAConsumer.h"
35 | #import "OCASubscriber.h"
36 | #import "OCAInvoker.h"
37 | #import "OCASwitch.h"
38 |
39 |
40 | /// Transformers
41 |
42 | #import "OCATransformer.h"
43 |
44 |
45 | /// Predicates
46 |
47 | #import "OCAPredicate.h"
48 |
49 |
50 | /// Utilities
51 |
52 | #import "OCAKeyPathAccessor.h"
53 | #import "OCAStructureAccessor.h"
54 | #import "OCAIndexAccessor.h"
55 |
56 | #import "OCAQueue.h"
57 | #import "OCASemaphore.h"
58 |
59 | #import "NSValue+Boxing.h"
60 | #import "NSArray+Ordinals.h"
61 | #import "OCADecomposer.h"
62 | #import "OCAInvocationCatcher.h"
63 | #import "OCAKeyValueChange.h"
64 | #import "OCAVariadic.h"
65 | #import "OCAPlaceholderObject.h"
66 | #import "OCAMutableArrayProxy.h"
67 |
68 | #import "OCADebug.h"
69 |
70 |
71 |
--------------------------------------------------------------------------------
/Sources/Foundation/OCAObject.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCAObject.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 30.12.13.
6 | // Copyright © 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 |
12 |
13 | #define OCAKPUnsafe(KEYPATH) NSStringFromSelector(@selector(KEYPATH))
14 | #define OCAKP(CLASS, KEYPATH) OCAKPObject([CLASS new], KEYPATH)
15 | #define OCAKPObject(OBJECT, KEYPATH) \
16 | _Pragma("clang diagnostic push") \
17 | _Pragma("clang diagnostic ignored \"-Warc-repeated-use-of-weak\"") \
18 | ((NSString *)@(((void)(NO && ((void)OBJECT.KEYPATH, NO)), # KEYPATH))) \
19 | _Pragma("clang diagnostic pop") \
20 |
21 | #define OCAWeakify(VARIABLE) __weak typeof(VARIABLE) VARIABLE##_weak = VARIABLE
22 | #define OCAStrongify(VARIABLE) __strong typeof(VARIABLE##_weak) VARIABLE = VARIABLE##_weak
23 |
24 | #define OCAKeyPathsAffecting(AFFECTED, KEYPATHS...)\
25 | + (NSSet *)keyPathsForValuesAffecting##AFFECTED { return [NSSet setWithObjects: KEYPATHS, nil]; }
26 |
27 | #define OCAEqual(A, B) OCAEqualCustom(A, isEqual:, B)
28 | #define OCAEqualString(A, B) OCAEqualCustom(A, isEqualToString:, B)
29 | #define OCAEqualCustom(A, SELECTOR, B) \
30 | (BOOL)({ \
31 | typeof(A) a = (A); \
32 | typeof(B) b = (B); \
33 | ((a == b) || (b && [a SELECTOR b])); \
34 | }) \
35 |
36 | #define OCA_iOS TARGET_OS_IPHONE
37 |
38 | #define CONVENIENCE
39 |
40 | #define OCAT(TYPE) @(@encode(TYPE))
41 | #define OCATypes(...) ( [@[ __VA_ARGS__ ] componentsJoinedByString:@""] )
42 |
43 |
44 |
45 |
46 |
47 | @interface OCAObject : NSObject
48 |
49 |
50 |
51 | #pragma mark Class Checking
52 |
53 | + (Class)valueClassForClasses:(NSArray *)classes;
54 | - (Class)valueClassForClasses:(NSArray *)classes;
55 |
56 | //! These methods take reference to the variable, because they may modify the value to make it valid. So far only one modification is made: NSNull is replaced with nil (and YES is returned).
57 | + (BOOL)validateObject:(id *)object ofClass:(Class)theClass;
58 | - (BOOL)validateObject:(id *)object ofClass:(Class)theClass;
59 | + (BOOL)validateObject:(id *)object ofClasses:(NSArray *)classes;
60 | - (BOOL)validateObject:(id *)object ofClasses:(NSArray *)classes;
61 |
62 | + (BOOL)isClass:(Class)class1 compatibleWithClass:(Class)class2;
63 | + (BOOL)isClass:(Class)classToCheck compatibleWithClasses:(NSArray *)classes;
64 | - (BOOL)isClass:(Class)class1 compatibleWithClass:(Class)class2;
65 |
66 |
67 | #pragma mark Describing Objects
68 |
69 | - (NSString *)descriptionName;
70 | - (NSString *)description;
71 | - (NSString *)shortDescription;
72 | - (NSDictionary *)debugDescriptionValues;
73 | - (NSString *)debugDescription;
74 | - (NSString *)debugShortDescription;
75 |
76 |
77 |
78 | @end
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 | #if !defined(NS_BLOCK_ASSERTIONS)
89 |
90 | #define OCAAssert(CONDITION, MESSAGE, ...) \
91 | if ( ! (CONDITION) && (( [[NSAssertionHandler currentHandler] \
92 | handleFailureInFunction: [NSString stringWithUTF8String:__PRETTY_FUNCTION__] \
93 | file: [NSString stringWithUTF8String:__FILE__] \
94 | lineNumber: __LINE__ \
95 | description: (MESSAGE), ##__VA_ARGS__], YES)) ) // Will NOT execute appended code, if exception is thrown.
96 |
97 | #else
98 |
99 | #define OCAAssert(CONDITION, MESSAGE, ...)\
100 | if ( ! (CONDITION) && (( NSLog(@"*** Assertion failure in %s, %s:%d, Condition not satisfied: %s, reason: '" MESSAGE "'", __PRETTY_FUNCTION__, __FILE__, __LINE__, #CONDITION, ##__VA_ARGS__), YES)) ) // Will execute appended code.
101 |
102 | #endif
103 |
104 |
105 |
--------------------------------------------------------------------------------
/Sources/Foundation/Predicates/OCAPredicate.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCAPredicate.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 11.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAObject.h"
10 | #import "OCAAccessor.h"
11 | #import "OCAProperty.h"
12 |
13 |
14 |
15 |
16 |
17 | @interface NSPredicate (OCAPredicateCompatibility)
18 |
19 |
20 | - (instancetype)negate;
21 |
22 |
23 | @end
24 |
25 |
26 |
27 |
28 |
29 | @interface OCAPredicate : OCAObject
30 |
31 |
32 | + (NSPredicate *)isNil;
33 | + (NSPredicate *)isNotNil;
34 | + (NSPredicate *)predicateForClass:(Class)theClass block:(BOOL(^)(id object))block;
35 |
36 |
37 | @end
38 |
39 |
40 |
41 |
42 |
43 | @interface OCAPredicate (Predefined)
44 |
45 |
46 |
47 | + (NSPredicate *)isTrue;
48 | + (NSPredicate *)isFalse;
49 | + (NSPredicate *)isEmpty;
50 | + (NSPredicate *)isNotEmpty;
51 |
52 | + (NSPredicate *)pass;
53 | + (NSPredicate *)discard;
54 |
55 | + (NSPredicate *)isKindOf:(Class)theClass;
56 |
57 | + (NSPredicate *)not:(NSPredicate *)predicate;
58 | + (NSPredicate *)and:(NSArray *)subpredicates;
59 | + (NSPredicate *)or:(NSArray *)subpredicates;
60 | + (NSPredicate *)all:(NSPredicate *)predicate;
61 | + (NSPredicate *)any:(NSPredicate *)predicate;
62 |
63 | + (NSPredicate *)predicateForClass:(Class)theClass predicate:(NSPredicate *)predicate;
64 | + (NSPredicate *)predicateFor:(Class)theClass format:(NSString *)format, ...;
65 |
66 | + (NSPredicate *)isProperty:(OCAProperty *)property;
67 | + (NSPredicate *)compareProperty:(OCAProperty *)property using:(NSPredicate *)predicate;
68 |
69 | + (NSPredicate *)compare:(OCAAccessor *)accessor using:(NSPredicate *)predicate;
70 | + (NSPredicate *)compare:(OCAAccessor *)accessor format:(NSString *)operatorFormat value:(id)value;
71 |
72 | + (NSPredicate *)operator:(NSPredicateOperatorType)theOperator options:(NSComparisonPredicateOptions)options value:(id)value;
73 | + (NSPredicate *)isLessThan:(id)value;
74 | + (NSPredicate *)isLessThanOrEqual:(id)value;
75 | + (NSPredicate *)isGreaterThan:(id)value;
76 | + (NSPredicate *)isGreaterThanOrEqual:(id)value;
77 | + (NSPredicate *)isEqualTo:(id)value;
78 | + (NSPredicate *)isNotEqualTo:(id)value;
79 | + (NSPredicate *)matches:(NSString *)regex;
80 | + (NSPredicate *)isLike:(NSString *)string;
81 | + (NSPredicate *)beginsWith:(id)value;
82 | + (NSPredicate *)endsWith:(id)value;
83 | + (NSPredicate *)isIn:(id)value;
84 | + (NSPredicate *)contains:(id)value;
85 | + (NSPredicate *)isBetween:(id)lower and:(id)upper;
86 |
87 |
88 |
89 | @end
90 |
91 |
92 |
--------------------------------------------------------------------------------
/Sources/Foundation/Producers/OCACommand.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCACommand.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 30.12.13.
6 | // Copyright © 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAProducer.h"
10 |
11 |
12 |
13 |
14 |
15 | //! Command is a Producer that allows manually sending values. Using Command is an alternative to subclassing the Producer.
16 | @interface OCACommand : OCAProducer
17 |
18 |
19 |
20 | #pragma mark Creating Command
21 |
22 | //! Initializes Command that produces values of given class.
23 | - (instancetype)initWithValueClass:(Class)valueClass;
24 |
25 | //! Creates Command that produces values of given class.
26 | + (instancetype)commandForClass:(Class)valueClass;
27 |
28 | //! Shortcut to manually send value to any consumer. Creates temporary Command producer.
29 | + (void)send:(id)value to:(id)consumer;
30 |
31 |
32 |
33 | #pragma mark Using Command
34 |
35 | //! Produces value to all Consumers.
36 | - (void)sendValue:(id)value;
37 |
38 | //! Produces values in array to all Consumers.
39 | - (void)sendValues:(NSArray *)values;
40 |
41 | //! Marks the Command as finished and sends the errro to Consumers.
42 | - (void)finishWithError:(NSError *)error;
43 |
44 |
45 |
46 | @end
47 |
48 |
49 |
--------------------------------------------------------------------------------
/Sources/Foundation/Producers/OCACommand.m:
--------------------------------------------------------------------------------
1 | //
2 | // OCACommand.m
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 30.12.13.
6 | // Copyright © 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCACommand.h"
10 | #import "OCAProducer+Subclass.h"
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | @implementation OCACommand
22 |
23 |
24 |
25 |
26 |
27 | #pragma mark Creating Command
28 |
29 |
30 | - (instancetype)initWithValueClass:(Class)valueClass {
31 | return [super initWithValueClass:valueClass];
32 | }
33 |
34 |
35 | + (instancetype)commandForClass:(Class)valueClass {
36 | return [[self alloc] initWithValueClass:valueClass];
37 | }
38 |
39 |
40 | + (void)send:(id)value to:(id)consumer {
41 | if ( ! consumer) return;
42 |
43 | OCACommand *command = [OCACommand commandForClass:[value classForCoder]];
44 | [command connectTo:consumer];
45 | [command sendValue:value];
46 | }
47 |
48 |
49 |
50 |
51 |
52 | #pragma mark Using Command
53 |
54 |
55 | - (void)sendValue:(id)value {
56 | [self produceValue:value];
57 | }
58 |
59 |
60 | - (void)sendValues:(NSArray *)values {
61 | for (id object in values) {
62 | [self produceValue:object];
63 | }
64 | }
65 |
66 |
67 | - (void)finishWithError:(NSError *)error {
68 | [self finishProducingWithError:error];
69 | }
70 |
71 |
72 |
73 |
74 |
75 | @end
76 |
77 |
78 |
--------------------------------------------------------------------------------
/Sources/Foundation/Producers/OCAHub.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCAHub.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 5.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAProducer.h"
10 |
11 |
12 |
13 | typedef enum : NSInteger {
14 | OCAHubTypeMerge,
15 | OCAHubTypeCombine,
16 | OCAHubTypeDependency,
17 | } OCAHubType;
18 |
19 |
20 |
21 |
22 |
23 | @interface OCAHub : OCAProducer
24 |
25 |
26 |
27 | #pragma mark Creating Hub
28 |
29 | - (instancetype)initWithType:(OCAHubType)type producers:(NSArray *)producers;
30 | + (instancetype)merge:(OCAProducer *)producers, ... NS_REQUIRES_NIL_TERMINATION;
31 | + (instancetype)combine:(OCAProducer *)producers, ... NS_REQUIRES_NIL_TERMINATION;
32 | + (OCAProducer *)allTrue:(OCAProducer *)producers, ... NS_REQUIRES_NIL_TERMINATION;
33 | + (OCAProducer *)anyTrue:(OCAProducer *)producers, ... NS_REQUIRES_NIL_TERMINATION;
34 |
35 | #pragma mark Attributes of Hub
36 |
37 | @property (atomic, readonly, assign) OCAHubType type;
38 | @property (atomic, readonly, copy) NSArray *producers; //TODO: Make mutable
39 |
40 |
41 |
42 | @end
43 |
44 |
45 |
--------------------------------------------------------------------------------
/Sources/Foundation/Producers/OCAInterpolator.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCAInterpolator.h
3 | // Objective-Chain
4 | //
5 | // Created by Juraj Homola on 24.2.2014.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAProducer.h"
10 | #import "OCAMath.h"
11 |
12 |
13 |
14 | @interface OCAInterpolator : OCAProducer
15 |
16 |
17 | /// Designated initializer
18 | - (instancetype)initWithDuration:(NSTimeInterval)duration
19 | frequency:(NSInteger)frequency
20 | fromValue:(OCAReal)fromValue
21 | toValue:(OCAReal)toValue;
22 |
23 |
24 | /// Interpolates between 0 and 1.
25 | + (instancetype)interpolatorWithDuration:(NSTimeInterval)duration frequency:(NSInteger)frequency;
26 |
27 |
28 | /// Interpolates between specific values.
29 | + (instancetype)interpolatorWithDuration:(NSTimeInterval)duration
30 | frequency:(NSInteger)frequency
31 | fromValue:(OCAReal)fromValue
32 | toValue:(OCAReal)toValue;
33 |
34 |
35 | /// Duration for which the interpolator is producing it's respective values. Must be non-negative.
36 | @property (nonatomic, readonly, assign) NSTimeInterval duration;
37 |
38 | /// Indicates how many values are produced per one second. Must be non-negative.
39 | @property (nonatomic, readonly, assign) NSInteger frequency;
40 |
41 | /// Value that is interpolated from.
42 | @property (nonatomic, readonly, assign) OCAReal fromValue;
43 |
44 | /// Value that is interpolated to.
45 | @property (nonatomic, readonly, assign) OCAReal toValue;
46 |
47 |
48 | /// Stops the interpolator and if the BOOL is YES - produces the last value.
49 | - (void)finishWithLastValue:(BOOL)withLastValue;
50 |
51 |
52 | @end
53 |
--------------------------------------------------------------------------------
/Sources/Foundation/Producers/OCAInterpolator.m:
--------------------------------------------------------------------------------
1 | //
2 | // OCAInterpolator.m
3 | // Objective-Chain
4 | //
5 | // Created by Juraj Homola on 24.2.2014.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAInterpolator.h"
10 | #import "OCAProducer+Subclass.h"
11 | #import "OCATimer.h"
12 |
13 |
14 | @interface OCAInterpolator ()
15 |
16 |
17 | @property (nonatomic, readwrite, strong) OCATimer *timer;
18 | @property (nonatomic, readwrite, strong) NSDate *initialDate;
19 |
20 |
21 | @end
22 |
23 |
24 |
25 |
26 |
27 | @implementation OCAInterpolator
28 |
29 |
30 | - (instancetype)init {
31 | return [self initWithDuration:0 frequency:1 fromValue:0 toValue:1];
32 | }
33 |
34 | - (instancetype)initWithDuration:(NSTimeInterval)duration
35 | frequency:(NSInteger)frequency
36 | fromValue:(OCAReal)fromValue
37 | toValue:(OCAReal)toValue {
38 | self = [super initWithValueClass:[NSNumber class]];
39 | if (self) {
40 |
41 | OCAAssert(frequency >= 0, @"Interpolator's frequency must be a non-negative value") return nil;
42 | OCAAssert(duration >= 0, @"Interpolator's duration must be a non-negative value") return nil;
43 |
44 | self->_duration = duration;
45 | self->_frequency = frequency;
46 | self->_fromValue = fromValue;
47 | self->_toValue = toValue;
48 |
49 | self.initialDate = [NSDate date];
50 |
51 | [self start];
52 | }
53 | return self;
54 | }
55 |
56 |
57 | + (instancetype)interpolatorWithDuration:(NSTimeInterval)duration frequency:(NSInteger)frequency {
58 | return [[self alloc] initWithDuration:duration frequency:frequency fromValue:0.0 toValue:1.0];
59 | }
60 |
61 | + (instancetype)interpolatorWithDuration:(NSTimeInterval)duration
62 | frequency:(NSInteger)frequency
63 | fromValue:(OCAReal)fromValue
64 | toValue:(OCAReal)toValue {
65 | return [[self alloc] initWithDuration:duration frequency:frequency fromValue:fromValue toValue:toValue];
66 | }
67 |
68 |
69 |
70 | - (void)start {
71 |
72 | if (self.duration <= 0 || (self.fromValue == self.toValue)) {
73 | [self finishWithLastValue:YES];
74 | return;
75 | }
76 |
77 |
78 | BOOL isFrequencyZero = (self.frequency == 0);
79 |
80 | [self produceValue:@(self.fromValue)];
81 |
82 | NSDate *untilDate = [self.initialDate dateByAddingTimeInterval:self.duration];
83 | if (isFrequencyZero) {
84 | self.timer = [OCATimer timerForDate:untilDate];
85 | } else {
86 | self.timer = [OCATimer timerWithInterval:MIN(1.0/self.frequency, self.duration) untilDate:untilDate];
87 | }
88 |
89 | OCAWeakify(self);
90 | [self.timer subscribeForClass:[NSNumber class] handler:^(NSNumber *lastFireInterval) {
91 | OCAStrongify(self);
92 |
93 | if ( ! isFrequencyZero) {
94 |
95 | OCAReal progress = -self.initialDate.timeIntervalSinceNow / self.duration;
96 |
97 | OCAReal producedValue = self.fromValue + (self.toValue - self.fromValue) * progress;
98 |
99 | [self produceValue:@(producedValue)];
100 | }
101 |
102 | } finish:^(NSError *error) {
103 | [self finishWithLastValue:YES];
104 | }];
105 |
106 | }
107 |
108 | - (void)finishWithLastValue:(BOOL)withLastValue {
109 | [self.timer stop];
110 | self.timer = nil;
111 | if (withLastValue) {
112 | [self produceValue:@(self.toValue)];
113 | }
114 | [self finishProducingWithError:nil];
115 | }
116 |
117 |
118 | @end
119 |
--------------------------------------------------------------------------------
/Sources/Foundation/Producers/OCANotificator.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCANotificator.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 8.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAProducer.h"
10 |
11 |
12 |
13 |
14 |
15 | @interface OCANotificator : OCAProducer
16 |
17 |
18 |
19 | #pragma mark Creating Notifier
20 |
21 | - (instancetype)initWithCenter:(NSNotificationCenter *)center name:(NSString *)name sender:(id)sender;
22 |
23 | @property (atomic, readonly, weak) NSNotificationCenter *notificationCenter;
24 | @property (atomic, readonly, copy) NSString *notificationName;
25 | @property (atomic, readonly, weak) id notificationSender;
26 |
27 |
28 | #pragma mark Receiving Notifications
29 |
30 | + (instancetype)notify:(NSString *)name;
31 | + (instancetype)notify:(NSString *)name from:(id)sender;
32 | + (OCAProducer *)notify:(NSString *)name from:(id)sender transform:(NSValueTransformer *)transformer;
33 | + (OCAProducer *)mergedNotify:(NSString *)name from:(NSArray *)senders;
34 |
35 |
36 | #pragma mark Notification Transformations
37 |
38 | - (OCAProducer *)produceName CONVENIENCE;
39 | - (OCAProducer *)produceSender CONVENIENCE;
40 | - (OCAProducer *)produceUserInfo CONVENIENCE;
41 | - (OCAProducer *)produceUserInfoForKey:(NSString *)key CONVENIENCE;
42 |
43 |
44 | #pragma mark Posting Notifications
45 |
46 | //TODO: Move to OCAConsumer class
47 | + (id)postNotification:(NSString *)name;
48 | + (id)postNotification:(NSString *)name sender:(NSObject *)object;
49 | + (id)postNotification:(NSString *)name sender:(NSObject *)object userInfoKey:(id)key;
50 |
51 |
52 |
53 | @end
54 |
55 |
56 |
--------------------------------------------------------------------------------
/Sources/Foundation/Producers/OCAProducer+Subclass.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCAProducer+Subclass.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 30.12.13.
6 | // Copyright © 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAProducer.h"
10 |
11 |
12 |
13 |
14 |
15 | /*! Interface to be used by subclasses. Before you decide to subclass Producer, you may consider to use Command subclass.
16 | * Every Producer must manage its own lifetime, so it should live and produce values until it makes sense. For example, a Timer produces values until the end date. Property produces until its observed object deallocates.
17 | * To hook onto another object (a.k.a. owner), use Decomposer class.
18 | */
19 | @interface OCAProducer ()
20 |
21 |
22 |
23 | #pragma mark Creating Producer
24 |
25 | //! Designated initializer. Your custom public initializer can provide a class that you are planning to produce. All produced values are validated to be of this class. May be nil, which means any values pass the validation.
26 | - (instancetype)initWithValueClass:(Class)valueClass;
27 |
28 |
29 | #pragma mark Managing Connections
30 |
31 | //! Your subclass can provide a replacement for added consumer. Pass the original consumer or create Mediator, for example, to transform produced values.
32 | - (id)replacementConsumerForConsumer:(id)consumer;
33 |
34 | //! Empty. Called before the consumer is added, but after -replacementConsumerForConsumer: is called.
35 | - (void)willAddConsumer:(id )consumer;
36 |
37 | //! If the receiver already finished, it calls -finishConsumingWithError: on the Consumer, otherwise it re-sends the latest produced value.
38 | - (void)didAddConsumer:(id )consumer;
39 |
40 | //! Empty.
41 | - (void)willRemoveConsumer:(id )consumer;
42 |
43 | //! Empty.
44 | - (void)didRemoveConsumer:(id )consumer;
45 |
46 |
47 |
48 | #pragma mark Lifetime of Producer
49 |
50 | //! Core method. Call this from your subclass with values you want to produce. Values are validated and sent to all Consumers. If the Producer already finished, nothing is sent.
51 | - (void)produceValue:(id)value NS_REQUIRES_SUPER;
52 |
53 | //! Core method. Call this from your subclass once you plan to send no more values. Marks the Producer as finished, sends the error to consumers and removes them. Usually after finishing, the Producer is no longer needed and may be deallocated. This method is automatically called before deallocation.
54 | - (void)finishProducingWithError:(NSError *)error NS_REQUIRES_SUPER;
55 |
56 | //! Readwrite acces to the laste produced value. You usually don't need to do any changes to it.
57 | @property (atomic, readwrite, strong) id lastValue;
58 |
59 | //! Called from -prodcuceValue:. Default implementation validated class of the value to the valueClass property. Override if you need other validation.
60 | - (BOOL)validateProducedValue:(id)value;
61 |
62 |
63 |
64 | #pragma mark Describing Producer
65 |
66 | - (NSString *)descriptionName;
67 | - (NSDictionary *)debugDescriptionValues;
68 |
69 |
70 |
71 | @end
72 |
73 |
74 |
--------------------------------------------------------------------------------
/Sources/Foundation/Transformers/OCAMath.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCAMath.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 2.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAObject.h"
10 | #import "OCATransformer.h"
11 | #import
12 |
13 |
14 |
15 | typedef long OCAInteger;
16 | typedef double OCAReal;
17 | typedef OCAInteger(^OCAIntegerTransformBlock)(OCAInteger x);
18 | typedef OCAReal(^OCARealTransformBlock)(OCAReal x);
19 |
20 |
21 |
22 |
23 |
24 | @interface OCAMath : OCAObject
25 |
26 |
27 |
28 | #pragma mark Generic
29 |
30 | + (OCATransformer *)transform:(OCARealTransformBlock)transform;
31 | + (OCATransformer *)transform:(OCARealTransformBlock)transform reverse:(OCARealTransformBlock)reverse;
32 |
33 | + (OCATransformer *)function:(OCAReal(*)(OCAReal))function;
34 | + (OCATransformer *)function:(OCAReal(*)(OCAReal))function reverse:(OCAReal(*)(OCAReal))reverse;
35 |
36 |
37 | #pragma mark Basic
38 |
39 | + (OCATransformer *)add:(OCAReal)add;
40 | + (OCATransformer *)subtract:(OCAReal)substract;
41 | + (OCATransformer *)subtractFrom:(OCAReal)value;
42 | + (OCATransformer *)multiplyBy:(OCAReal)multiplier;
43 | + (OCATransformer *)divideBy:(OCAReal)divisor;
44 | + (OCATransformer *)modulus:(OCAInteger)value;
45 | + (OCATransformer *)absoluteValue;
46 | + (OCATransformer *)inversedValue;
47 |
48 | + (OCATransformer *)relativeBetween:(OCAReal)lower and:(OCAReal)upper;
49 | + (OCATransformer *)absoluteBetween:(OCAReal)lower and:(OCAReal)upper;
50 |
51 |
52 | #pragma mark Advanced
53 |
54 | + (OCATransformer *)powerBy:(OCAReal)value;
55 | + (OCATransformer *)rootOf:(OCAReal)value;
56 | + (OCATransformer *)exponentOf:(OCAReal)value;
57 | + (OCATransformer *)logarithmWithBase:(OCAReal)base;
58 |
59 |
60 | #pragma mark Rounding
61 |
62 | + (OCATransformer *)roundTo:(OCAReal)scale;
63 | + (OCATransformer *)floorTo:(OCAReal)scale;
64 | + (OCATransformer *)ceilTo:(OCAReal)scale;
65 |
66 |
67 | #pragma mark Limits
68 |
69 | + (OCATransformer *)maximumOf:(OCAReal)value;
70 | + (OCATransformer *)minimumOf:(OCAReal)value;
71 | + (OCATransformer *)clampFrom:(OCAReal)minimum to:(OCAReal)maximum;
72 |
73 |
74 | #pragma mark Trigonometry
75 |
76 | + (OCATransformer *)sine;
77 | + (OCATransformer *)cosine;
78 | + (OCATransformer *)tangent;
79 | + (OCATransformer *)arcSine;
80 | + (OCATransformer *)arcCosine;
81 | + (OCATransformer *)arcTangent;
82 |
83 | + (OCATransformer *)toDegrees;
84 | + (OCATransformer *)toRadians;
85 |
86 |
87 | #pragma mark Array
88 |
89 | + (OCATransformer *)sum;
90 | + (OCATransformer *)average;
91 | + (OCATransformer *)minimum;
92 | + (OCATransformer *)maximum;
93 |
94 |
95 | #pragma mark Random
96 |
97 | + (OCATransformer *)randomUpTo:(NSUInteger)bound;
98 |
99 |
100 | #pragma mark Logic
101 |
102 | + (OCATransformer *)allTrue;
103 | + (OCATransformer *)anyTrue;
104 |
105 |
106 |
107 | @end
108 |
109 |
110 |
111 |
112 |
113 | #pragma mark Functions
114 |
115 | extern OCAReal OCALogarithm(OCAReal x, OCAReal base);
116 | extern OCAReal OCARound(OCAReal x, OCAReal scale);
117 | extern OCAReal OCACeil(OCAReal x, OCAReal scale);
118 | extern OCAReal OCAFloor(OCAReal x, OCAReal scale);
119 | extern OCAReal OCAClamp(OCAReal lower, OCAReal value, OCAReal upper);
120 |
121 |
122 |
--------------------------------------------------------------------------------
/Sources/Foundation/Transformers/OCATransformer+Base.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCATransformer+Base.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 10.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "OCAObject.h"
11 |
12 |
13 |
14 | typedef id (^OCATransformerBlock)(id input);
15 |
16 |
17 |
18 |
19 |
20 | @interface NSValueTransformer (OCATransformerCompatibility)
21 |
22 | + (Class)valueClass;
23 |
24 | - (NSValueTransformer *)reversed;
25 |
26 | @end
27 |
28 |
29 |
30 |
31 |
32 | @interface OCATransformer : NSValueTransformer
33 |
34 |
35 |
36 | #pragma mark Class Info
37 |
38 | + (Class)valueClass;
39 | + (Class)transformedValueClass;
40 | + (BOOL)allowsReverseTransformation;
41 |
42 |
43 |
44 | #pragma mark Transformation
45 |
46 | - (id)transformedValue:(id)value;
47 | - (id)reverseTransformedValue:(id)value;
48 |
49 |
50 |
51 | #pragma mark Describing
52 |
53 | @property (nonatomic, readonly, copy) NSString *reverseDescription;
54 | - (instancetype)describe:(NSString *)description;
55 | - (instancetype)describe:(NSString *)description reverse:(NSString *)reverseDescription;
56 |
57 |
58 |
59 | #pragma mark Deriving Transformers
60 |
61 | - (OCATransformer *)reversed;
62 | - (OCATransformer *)specializeFromClass:(Class)fromClass toClass:(Class)toClass;
63 |
64 |
65 |
66 | #pragma mark Customizing Using Blocks
67 |
68 | + (Class)subclassForInputClass:(Class)inputClass outputClass:(Class)outputClass reversible:(BOOL)isReversible;
69 | - (OCATransformer *)initWithBlock:(OCATransformerBlock)block reverseBlock:(OCATransformerBlock)reverseBlock;
70 |
71 | + (OCATransformer *)fromClass:(Class)fromClass toClass:(Class)toClass symetric:(OCATransformerBlock)symetric;
72 | + (OCATransformer *)fromClass:(Class)fromClass toClass:(Class)toClass asymetric:(OCATransformerBlock)asymetric;
73 | + (OCATransformer *)fromClass:(Class)fromClass toClass:(Class)toClass transform:(OCATransformerBlock)transform reverse:(OCATransformerBlock)reverse;
74 |
75 | + (OCATransformer *)there:(NSValueTransformer *)forward back:(NSValueTransformer *)backward;
76 |
77 |
78 |
79 | @end
80 |
81 |
82 |
83 |
84 |
85 | extern OCATransformerBlock const OCATransformationDiscard;
86 | extern OCATransformerBlock const OCATransformationPass;
87 |
88 |
89 |
90 |
91 |
92 | @interface NSObject (NSValueTransformer)
93 |
94 | - (id)transform:(NSValueTransformer *)transformer __deprecated;
95 |
96 | @end
97 |
98 |
99 |
--------------------------------------------------------------------------------
/Sources/Foundation/Transformers/OCATransformer+Collections.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCATransformer+Collections.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 10.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCATransformer+Base.h"
10 |
11 |
12 |
13 |
14 |
15 | @interface OCATransformer (Collections)
16 |
17 |
18 |
19 | + (OCATransformer *)countCollection;
20 | + (OCATransformer *)objectForKey:(id)key;
21 |
22 |
23 |
24 |
25 | #pragma mark -
26 | #pragma mark Array
27 | #pragma mark -
28 |
29 |
30 | #pragma mark Creating Array
31 |
32 | + (OCATransformer *)branchArray:(NSArray *)transformers;
33 | + (OCATransformer *)wrapInArray;
34 | + (OCATransformer *)arrayFromFile;
35 |
36 |
37 | #pragma mark Getting Subarray
38 |
39 | + (OCATransformer *)objectsAtIndexes:(NSIndexSet *)indexes;
40 | + (OCATransformer *)subarrayToIndex:(NSInteger)index;
41 | + (OCATransformer *)subarrayFromIndex:(NSInteger)index;
42 | + (OCATransformer *)subarrayWithRange:(NSRange)range;
43 |
44 |
45 | #pragma mark Altering Array
46 |
47 | + (OCATransformer *)transformArray:(NSValueTransformer *)transformer;
48 | + (OCATransformer *)filterArray:(NSPredicate *)predicate;
49 | + (OCATransformer *)sortArray:(NSArray *)sortDescriptors;
50 | + (OCATransformer *)flattenArrayRecursively:(BOOL)recursively;
51 | + (OCATransformer *)randomizeArray;
52 | + (OCATransformer *)removeNullsFromArray;
53 | + (OCATransformer *)mutateArray:(void(^)(NSMutableArray *array))block;
54 |
55 |
56 | #pragma mark Disposing Array
57 |
58 | + (OCATransformer *)objectAtIndex:(NSInteger)index;
59 | + (OCATransformer *)joinWithString:(NSString *)string;
60 | + (OCATransformer *)joinWithAttributedString:(NSAttributedString *)attrString;
61 | + (OCATransformer *)joinWithString:(NSString *)string last:(NSString *)lastString;
62 |
63 | + (OCATransformer *)objectFromArray:(NSArray *)objects;
64 | + (OCATransformer *)indexInArray:(NSArray *)objects;
65 |
66 |
67 |
68 | #pragma mark -
69 | #pragma mark Dictionary
70 | #pragma mark -
71 |
72 |
73 | #pragma mark Creating Dictionary
74 |
75 | + (OCATransformer *)dictionaryFromFile;
76 | + (OCATransformer *)mappedArray:(NSValueTransformer *)transformer;
77 | + (OCATransformer *)keyedArray:(NSArray *)keys;
78 | + (OCATransformer *)mergeDictionaries;
79 |
80 |
81 | #pragma mark Altering Dictionary
82 |
83 | + (OCATransformer *)filteredDictionary:(NSPredicate *)predicate;
84 | + (OCATransformer *)transformValues:(NSValueTransformer *)transformer;
85 | + (OCATransformer *)mutateDictionary:(void(^)(NSMutableDictionary *dictionary))block;
86 |
87 |
88 | #pragma mark Disposing Dictionary
89 |
90 | + (OCATransformer *)joinPairs:(NSString *)string;
91 | + (OCATransformer *)keysForValue:(id)value;
92 |
93 |
94 |
95 | #pragma mark -
96 | #pragma mark Index Set
97 | #pragma mark -
98 |
99 |
100 | #pragma mark Creating Index Set
101 |
102 | + (OCATransformer *)indexSetFromArray;
103 | + (OCATransformer *)wrapIndex;
104 | + (OCATransformer *)wrapRange;
105 |
106 |
107 | #pragma mark Altering Index Set
108 |
109 | + (OCATransformer *)mutateIndexSet:(void(^)(NSMutableIndexSet *indexSet))block;
110 |
111 |
112 | #pragma mark Disposing Index Set
113 |
114 | + (OCATransformer *)lowestIndex;
115 | + (OCATransformer *)highestIndex;
116 |
117 |
118 |
119 | #pragma mark -
120 | #pragma mark Index Path
121 | #pragma mark -
122 |
123 |
124 | + (OCATransformer *)indexPathFromArray;
125 | + (OCATransformer *)indexPathInSection:(NSUInteger)section;
126 |
127 |
128 |
129 | @end
130 |
131 |
132 |
--------------------------------------------------------------------------------
/Sources/Foundation/Transformers/OCATransformer+Core.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCATransformer+Core.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 31.12.13.
6 | // Copyright © 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCATransformer+Base.h"
10 | #import "OCAKeyPathAccessor.h"
11 | #import "OCAStructureAccessor.h"
12 |
13 |
14 |
15 |
16 |
17 | @interface OCATransformer (Core)
18 |
19 |
20 |
21 |
22 |
23 | #pragma mark Basic
24 |
25 | + (OCATransformer *)pass;
26 | + (OCATransformer *)discard;
27 | + (OCATransformer *)replaceWith:(id)replacement;
28 |
29 |
30 |
31 | #pragma mark Conditions
32 |
33 | + (OCATransformer *)if:(NSPredicate *)predicate then:(NSValueTransformer *)thenTransformer else:(NSValueTransformer *)elseTransformer;
34 | + (OCATransformer *)passesPredicate:(NSPredicate *)predicate or:(id)replacement;
35 | + (OCATransformer *)replaceNil:(id)replacement;
36 | + (OCATransformer *)kindOfClass:(Class)theClass or:(id)replacement;
37 | + (OCATransformer *)ifYes:(id)yesReplacement ifNo:(id)noReplacement;
38 |
39 |
40 |
41 | #pragma mark Boolean
42 |
43 | + (OCATransformer *)evaluatePredicate:(NSPredicate *)predicate;
44 | + (OCATransformer *)negateBoolean;
45 |
46 |
47 |
48 | #pragma mark Accessors & Other
49 |
50 | + (OCATransformer *)access:(OCAAccessor *)accessor;
51 | + (OCATransformer *)modify:(OCAAccessor *)accessor value:(id)value;
52 | + (OCATransformer *)modify:(OCAAccessor *)accessor transformer:(NSValueTransformer *)transformer;
53 | + (OCATransformer *)evaluateExpression:(NSExpression *)expression;
54 | + (OCATransformer *)map:(NSDictionary *)dictionary;
55 | + (OCATransformer *)replace:(NSDictionary *)dictionary;
56 | + (OCATransformer *)makeCopy;
57 |
58 |
59 |
60 | #pragma mark Control Flow
61 |
62 | + (OCATransformer *)sequence:(NSArray *)transformers;
63 | + (OCATransformer *)convertTo:(Class)finalClass using:(NSArray *)transformers;
64 | + (OCATransformer *)repeat:(NSUInteger)count transformer:(NSValueTransformer *)transformer;
65 |
66 |
67 |
68 | #pragma mark Side Effects
69 |
70 | + (OCATransformer *)sideEffect:(void(^)(id value))block;
71 | + (OCATransformer *)debugPrintWithPrefix:(NSString *)prefix;
72 |
73 |
74 |
75 |
76 |
77 | @end
78 |
79 |
80 |
--------------------------------------------------------------------------------
/Sources/Foundation/Transformers/OCATransformer+NSData.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCATransformer+NSData.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 10.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCATransformer+Base.h"
10 |
11 |
12 |
13 |
14 |
15 | @interface OCATransformer (NSData)
16 |
17 |
18 |
19 | #pragma mark -
20 | #pragma mark Data
21 | #pragma mark -
22 |
23 | #pragma mark Creating Data
24 |
25 | + (OCATransformer *)dataFromFile;
26 | + (OCATransformer *)dataFromString; //! UTF-8
27 | + (OCATransformer *)subdataWithRange:(NSRange)range;
28 |
29 |
30 | #pragma mark Keyed Archivation
31 |
32 | + (OCATransformer *)archiveBinary:(BOOL)binary;
33 | + (OCATransformer *)unarchive;
34 |
35 |
36 | #pragma mark Property List Serialization
37 |
38 | + (OCATransformer *)serializePropertyListBinary:(BOOL)binary;
39 | + (OCATransformer *)deserializePropertyListMutable:(BOOL)isMutable;
40 |
41 |
42 | #pragma mark JSON Serialization
43 |
44 | + (OCATransformer *)serializeJSONPretty:(BOOL)pretty;
45 | + (OCATransformer *)deserializeJSONMutable:(BOOL)isMutable;
46 |
47 |
48 | #pragma mark Base64 Encoding
49 |
50 | + (OCATransformer *)decodeBase64Data;
51 | + (OCATransformer *)encodeBase64Data;
52 |
53 |
54 | #pragma mark Hexadecimal String
55 |
56 | + (OCATransformer *)dataFromHex;
57 | + (OCATransformer *)hexFromData;
58 |
59 |
60 |
61 | #pragma mark -
62 | #pragma mark UUID
63 | #pragma mark -
64 |
65 | #pragma mark Creating UUID
66 |
67 | + (OCATransformer *)UUIDFromData;
68 | + (OCATransformer *)UUIDFromString;
69 |
70 | #pragma mark Disposing UUID
71 |
72 | + (OCATransformer *)dataFromUUID;
73 | + (OCATransformer *)stringFromUUID;
74 |
75 |
76 |
77 | @end
78 |
79 |
80 |
--------------------------------------------------------------------------------
/Sources/Foundation/Transformers/OCATransformer+NSDate.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCATransformer+NSDate.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 10.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCATransformer+Base.h"
10 |
11 |
12 |
13 |
14 |
15 | @interface OCATransformer (NSDate)
16 |
17 |
18 |
19 | #pragma mark -
20 | #pragma mark Date
21 | #pragma mark -
22 |
23 |
24 | + (OCATransformer *)replaceWithCurrentDate;
25 |
26 |
27 | #pragma mark Working with Time Intervals
28 |
29 | + (OCATransformer *)dateFromTimeIntervalSinceUNIX:(BOOL)unix;
30 | + (OCATransformer *)timeIntervalSinceUNIX:(BOOL)unix;
31 | + (OCATransformer *)addTimeInterval:(NSTimeInterval)interval;
32 | + (OCATransformer *)timeIntervalSinceDate:(NSDate *)otherDate;
33 | + (OCATransformer *)timeIntervalToDate:(NSDate *)otherDate;
34 | + (OCATransformer *)timeIntervalSinceMidnight;
35 |
36 |
37 | #pragma mark Parsing Dates
38 |
39 | + (OCATransformer *)dateWithFormatter:(NSDateFormatter *)formatter;
40 | + (OCATransformer *)dateFromStringFormat:(NSString *)dateFormat;
41 |
42 |
43 | #pragma mark Formatting Dates
44 |
45 | + (OCATransformer *)stringWithDateFormatter:(NSDateFormatter *)formatter;
46 | + (OCATransformer *)stringWithDateFormat:(NSString *)dateFormat;
47 | + (OCATransformer *)stringWithDateStyle:(NSDateFormatterStyle)dateStyle timeStyle:(NSDateFormatterStyle)timeStyle;
48 | + (OCATransformer *)stringWithDateStyle:(NSDateFormatterStyle)dateStyle timeStyle:(NSDateFormatterStyle)timeStyle relative:(BOOL)doesRelative;
49 |
50 |
51 | #pragma mark Limiting Dates
52 |
53 | + (OCATransformer *)earlierDate:(NSDate *)otherDate;
54 | + (OCATransformer *)laterDate:(NSDate *)otherDate;
55 | + (OCATransformer *)roundDateToUnit:(NSCalendarUnit)unit mode:(NSRoundingMode)mode;
56 |
57 |
58 | #pragma mark Date Components
59 |
60 | + (OCATransformer *)dateComponents:(NSCalendarUnit)units;
61 | + (OCATransformer *)dateComponents:(NSCalendarUnit)units sinceDate:(NSDate *)otherDate;
62 | + (OCATransformer *)dateComponentsSinceCurrentDate:(NSCalendarUnit)units;
63 | + (OCATransformer *)dateComponentsUntilCurrentDate:(NSCalendarUnit)units;
64 | + (OCATransformer *)addDateComponents:(NSDateComponents *)components;
65 | + (OCATransformer *)modifyDateComponents:(NSCalendarUnit)units block:(void(^)(NSDateComponents *components))block;
66 | + (OCATransformer *)dateComponent:(NSCalendarUnit)unit;
67 | + (OCATransformer *)nameFromWeekdayShort:(BOOL)shortWeekdays;
68 | + (OCATransformer *)nameFromMonthShort:(BOOL)shortMonths;
69 |
70 |
71 |
72 | @end
73 |
74 |
75 |
76 |
77 |
78 |
79 | extern NSCalendarUnit const OCACalendarUnitDefault;
80 |
81 |
82 |
83 | @interface NSDateComponents (OCATransformer)
84 |
85 | - (NSInteger)oca_valueForUnit:(NSCalendarUnit)unit;
86 | - (void)oca_setValue:(NSInteger)value forUnit:(NSCalendarUnit)unit;
87 |
88 | @end
89 |
90 |
91 |
--------------------------------------------------------------------------------
/Sources/Foundation/Transformers/OCATransformer+NSString.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCATransformer+NSString.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 10.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCATransformer+Base.h"
10 |
11 |
12 |
13 |
14 |
15 | @interface OCATransformer (NSString)
16 |
17 |
18 |
19 | #pragma mark -
20 | #pragma mark String
21 | #pragma mark -
22 |
23 |
24 | #pragma mark Creating String
25 |
26 | + (OCATransformer *)stringFromFile;
27 | + (OCATransformer *)stringFromData;
28 | + (OCATransformer *)formatString:(NSString *)format;
29 |
30 |
31 | #pragma mark Getting Substring
32 |
33 | + (OCATransformer *)substringToIndex:(NSInteger)index;
34 | + (OCATransformer *)substringFromIndex:(NSInteger)index;
35 | + (OCATransformer *)substringWithRange:(NSRange)range;
36 |
37 |
38 | #pragma mark Altering String
39 |
40 | + (OCATransformer *)appendFormat:(NSString *)format, ... NS_FORMAT_FUNCTION(1, 2);
41 | + (OCATransformer *)trimWhitespace;
42 | + (OCATransformer *)replaceString:(NSString *)find withString:(NSString *)replace;
43 | + (OCATransformer *)mutateString:(void(^)(NSMutableString *string))block;
44 | + (OCATransformer *)capitalizeString;
45 | + (OCATransformer *)uppercaseString;
46 | + (OCATransformer *)lowercaseString;
47 |
48 |
49 | #pragma mark Splitting String
50 |
51 | + (OCATransformer *)splitString:(NSString *)split;
52 | + (OCATransformer *)splitByWhitespace;
53 |
54 |
55 |
56 | #pragma mark -
57 | #pragma mark Attributed String
58 | #pragma mark -
59 |
60 |
61 | #pragma mark Creating Attributed String
62 |
63 | + (OCATransformer *)stringWithAttributes:(NSDictionary *)attributes;
64 |
65 |
66 | #pragma mark Changing Attributes
67 |
68 | + (OCATransformer *)addAttributes:(NSDictionary *)attributes;
69 | + (OCATransformer *)addAttributes:(NSDictionary *)attributes range:(NSRange)range;
70 | + (OCATransformer *)transformAttribute:(NSString *)attribute transformer:(NSValueTransformer *)transformer;
71 |
72 | #pragma mark Altering Attributed String
73 |
74 | + (OCATransformer *)appendAttributedString:(NSAttributedString *)attributedString;
75 | + (OCATransformer *)attributedSubstringInRange:(NSRange)range;
76 | + (OCATransformer *)mutateAttributedString:(void(^)(NSMutableAttributedString *attributedString))block;
77 |
78 |
79 |
80 | #pragma mark -
81 | #pragma mark Number
82 | #pragma mark -
83 |
84 |
85 | #pragma mark Format Numbers
86 |
87 | + (OCATransformer *)stringWithNumberStyle:(NSNumberFormatterStyle)style fractionDigits:(NSUInteger)fractionalDigits;
88 | + (OCATransformer *)stringWithNumberFormatter:(NSNumberFormatter *)formatter;
89 | + (OCATransformer *)stringFromNumber;
90 | + (OCATransformer *)stringFromCountWithZero:(NSString *)zeroSuffix one:(NSString *)oneSuffix few:(NSString *)fewSuffix many:(NSString *)manySuffix;
91 |
92 | #pragma mark Format Byte Count
93 |
94 | + (OCATransformer *)stringWithMemoryByteCount;
95 | + (OCATransformer *)stringWithFileByteCount;
96 | + (OCATransformer *)stringWithByteCountFormatter:(NSByteCountFormatter *)formatter;
97 |
98 |
99 | #pragma mark Parse Numbers
100 |
101 | + (OCATransformer *)numberWithFormatter:(NSNumberFormatter *)formatter;
102 | + (OCATransformer *)numberFromString;
103 |
104 |
105 | #pragma mark -
106 | #pragma mark URL
107 | #pragma mark -
108 |
109 |
110 | #pragma mark Creating URL
111 |
112 | + (OCATransformer *)URLFromString;
113 | + (OCATransformer *)URLFromPath;
114 | + (OCATransformer *)URLWithBaseURL:(NSURL *)base;
115 |
116 | #pragma mark URL Components
117 |
118 | + (OCATransformer *)componentsOfURL;
119 | + (OCATransformer *)modifyURLComponents:(void(^)(NSURLComponents *components))block;
120 |
121 |
122 |
123 | @end
124 |
125 |
126 |
--------------------------------------------------------------------------------
/Sources/Foundation/Transformers/OCATransformer.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCATransformer.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 31.12.13.
6 | // Copyright © 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 |
10 |
11 | #import "OCATransformer+Base.h"
12 | #import "OCATransformer+Core.h"
13 | #import "OCAMath.h"
14 | #import "OCATransformer+Collections.h"
15 | #import "OCATransformer+NSData.h"
16 | #import "OCATransformer+NSDate.h"
17 | #import "OCATransformer+NSString.h"
18 |
19 |
20 |
--------------------------------------------------------------------------------
/Sources/Foundation/Utilities/Accessors/OCAAccessor.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCAAccessor.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 8.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAObject.h"
10 |
11 |
12 |
13 |
14 |
15 | @interface OCAAccessor : OCAObject
16 |
17 |
18 |
19 | #pragma mark Using Accessor
20 |
21 | - (id)accessObject:(id)object;
22 | - (id)modifyObject:(id)object withValue:(id)value;
23 |
24 |
25 | #pragma mark Class Validation of Accessor
26 |
27 | - (Class)objectClass;
28 | - (Class)valueClass;
29 |
30 |
31 |
32 | @end
33 |
34 |
35 |
--------------------------------------------------------------------------------
/Sources/Foundation/Utilities/Accessors/OCAAccessor.m:
--------------------------------------------------------------------------------
1 | //
2 | // OCAAccessor.m
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 8.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAAccessor.h"
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | @implementation OCAAccessor
21 |
22 |
23 |
24 |
25 |
26 | #pragma mark Using Accessor
27 |
28 |
29 | - (id)accessObject:(id)object {
30 | return object;
31 | }
32 |
33 |
34 | - (id)modifyObject:(id)object withValue:(id)value {
35 | return object;
36 | }
37 |
38 |
39 |
40 |
41 |
42 | #pragma mark Clas Validation
43 |
44 |
45 | - (Class)objectClass {
46 | return nil;
47 | }
48 |
49 |
50 | - (Class)valueClass {
51 | return nil;
52 | }
53 |
54 |
55 |
56 |
57 |
58 | @end
59 |
60 |
61 |
--------------------------------------------------------------------------------
/Sources/Foundation/Utilities/Accessors/OCAIndexAccessor.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCAIndexAccessor.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 17.4.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAAccessor.h"
10 |
11 |
12 |
13 |
14 |
15 | @interface OCAIndexAccessor : OCAAccessor
16 |
17 |
18 | #define OCAIndex(index) ( [[OCAIndexAccessor alloc] initWithIndex:index] )
19 |
20 | //! Uses so can be negative and can be out of range.
21 | - (instancetype)initWithIndex:(NSInteger)index;
22 | @property (nonatomic, readonly, assign) NSInteger index;
23 |
24 |
25 | @end
26 |
27 |
28 |
--------------------------------------------------------------------------------
/Sources/Foundation/Utilities/Accessors/OCAIndexAccessor.m:
--------------------------------------------------------------------------------
1 | //
2 | // OCAIndexAccessor.m
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 17.4.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAIndexAccessor.h"
10 | #import "NSArray+Ordinals.h"
11 |
12 |
13 |
14 |
15 |
16 | @implementation OCAIndexAccessor
17 |
18 |
19 |
20 |
21 |
22 | - (instancetype)initWithIndex:(NSInteger)index {
23 | self = [super init];
24 | if (self) {
25 | self->_index = index;
26 | }
27 | return self;
28 | }
29 |
30 |
31 | - (Class)objectClass {
32 | return [NSArray class];
33 | }
34 |
35 |
36 |
37 |
38 |
39 | - (id)accessObject:(NSArray *)array {
40 | return [array oca_valueAtIndex:self.index];
41 | }
42 |
43 |
44 | - (id)modifyObject:(NSArray *)array withValue:(id)value {
45 | NSMutableArray *mutable = [array mutableCopy];
46 | NSUInteger count = array.count;
47 | NSInteger index = self.index;
48 |
49 | NSInteger realIndex = (index >= 0? index : count + index);
50 | if (realIndex < 0) return array;
51 | if (realIndex >= count) return array;
52 |
53 | [mutable replaceObjectAtIndex:index withObject:(value ?: NSNull.null)];
54 | return mutable;
55 | }
56 |
57 |
58 |
59 |
60 |
61 | @end
62 |
63 |
64 |
--------------------------------------------------------------------------------
/Sources/Foundation/Utilities/NSArray+Ordinals.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSArray+Ordinals.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 10.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 |
12 |
13 |
14 |
15 | @interface NSArray (Ordinals)
16 |
17 |
18 | - (id)oca_valueAtIndex:(NSInteger)index;
19 |
20 |
21 | @end
22 |
23 |
24 |
25 |
26 |
27 | extern NSUInteger OCANormalizeIndex(NSInteger index, NSUInteger length);
28 | extern NSRange OCANormalizeRange(NSRange range, NSUInteger length);
29 |
30 |
31 |
--------------------------------------------------------------------------------
/Sources/Foundation/Utilities/NSArray+Ordinals.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSArray+Ordinals.m
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 10.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "NSArray+Ordinals.h"
10 |
11 |
12 |
13 |
14 |
15 | @implementation NSArray (Ordinals)
16 |
17 |
18 |
19 |
20 |
21 | - (id)oca_valueAtIndex:(NSInteger)index {
22 | NSInteger realIndex = (index >= 0? index : self.count + index);
23 | if (realIndex < 0) return nil;
24 | if (realIndex >= self.count) return nil;
25 |
26 | id value = [self objectAtIndex:realIndex];
27 |
28 | if (value == NSNull.null) return nil;
29 | return value;
30 | }
31 |
32 |
33 |
34 |
35 |
36 | @end
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | NSUInteger OCANormalizeIndex(NSInteger index, NSUInteger length) {
48 |
49 | if (index < 0)
50 | index = length + index;
51 |
52 | if (index < 0)
53 | return 0;
54 |
55 | if (index >= length)
56 | index = length;
57 |
58 | return index;
59 | }
60 |
61 |
62 | NSRange OCANormalizeRange(NSRange range, NSUInteger length) {
63 |
64 | if (range.location > length)
65 | range.location = length;
66 |
67 | NSUInteger end = length - range.location;
68 |
69 | if (range.length > end)
70 | range.length = end;
71 |
72 | return range;
73 | }
74 |
75 |
76 |
--------------------------------------------------------------------------------
/Sources/Foundation/Utilities/NSValue+Boxing.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSValue+Boxing.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 3.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 |
12 |
13 | #define OCABox(VALUE) \
14 | (id)({ \
15 | typeof(VALUE) v = (VALUE); \
16 | [NSValue boxValue:&v objCType:@encode(typeof(v))]; \
17 | }) \
18 |
19 |
20 |
21 | #define OCAUnbox(VALUE, TYPE, REPLACEMENT) \
22 | (TYPE)({ \
23 | TYPE v; \
24 | BOOL s = [(VALUE) unboxValue:&v objCType:@encode(TYPE)]; \
25 | s? v : (REPLACEMENT); \
26 | }) \
27 |
28 |
29 |
30 | #define OCAUnboxPoint(VALUE) OCAUnbox(VALUE, CGPoint, CGPointZero)
31 | #define OCAUnboxSize(VALUE) OCAUnbox(VALUE, CGSize, CGSizeZero)
32 | #define OCAUnboxRect(VALUE) OCAUnbox(VALUE, CGRect, CGRectZero)
33 |
34 |
35 |
36 | @interface NSValue (Boxing)
37 |
38 |
39 | + (id)boxValue:(const void *)buffer objCType:(const char *)type;
40 | - (BOOL)unboxValue:(void *)buffer objCType:(const char *)type;
41 |
42 | + (BOOL)objCTypeIsNumeric:(const char *)type;
43 |
44 |
45 | @end
46 |
--------------------------------------------------------------------------------
/Sources/Foundation/Utilities/NSValue+Boxing.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSValue+Boxing.m
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 3.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "NSValue+Boxing.h"
10 |
11 |
12 |
13 |
14 |
15 | @implementation NSValue (Boxing)
16 |
17 |
18 | //TODO: Something better than macros.
19 |
20 |
21 |
22 |
23 | #define NSValueConditional(TYPE) if (strcmp(type, @encode(TYPE)) == 0)
24 |
25 |
26 | + (id)boxValue:(const void *)buffer objCType:(const char *)type {
27 | #define NSValueConditionalyBoxNumber(TYPE) NSValueConditional(TYPE) return @( * (TYPE *)buffer)
28 |
29 | NSValueConditional(void) return nil;
30 |
31 | NSValueConditionalyBoxNumber(char);
32 | NSValueConditionalyBoxNumber(short);
33 | NSValueConditionalyBoxNumber(int);
34 | NSValueConditionalyBoxNumber(long);
35 | NSValueConditionalyBoxNumber(long long);
36 |
37 | NSValueConditionalyBoxNumber(unsigned char);
38 | NSValueConditionalyBoxNumber(unsigned short);
39 | NSValueConditionalyBoxNumber(unsigned int);
40 | NSValueConditionalyBoxNumber(unsigned long);
41 | NSValueConditionalyBoxNumber(unsigned long long);
42 |
43 | NSValueConditionalyBoxNumber(float);
44 | NSValueConditionalyBoxNumber(double);
45 |
46 | NSValueConditionalyBoxNumber(_Bool);
47 |
48 | return [NSValue valueWithBytes:buffer objCType:type];
49 |
50 | #undef NSValueConditionalyBoxNumber
51 | }
52 |
53 |
54 | - (BOOL)unboxValue:(void *)buffer objCType:(const char *)type {
55 | #define NSValueConditionalyUnboxNumber(TYPE, METHOD) \
56 | NSValueConditional(TYPE) { \
57 | if ([self isKindOfClass:NSNumber.class]) { \
58 | * (TYPE *)buffer = [(NSNumber *)self METHOD]; \
59 | return YES; \
60 | } \
61 | else return NO; \
62 | } \
63 |
64 | NSValueConditional(void) {
65 | return NO;
66 | }
67 |
68 | NSValueConditionalyUnboxNumber(char, charValue);
69 | NSValueConditionalyUnboxNumber(short, shortValue);
70 | NSValueConditionalyUnboxNumber(int, intValue);
71 | NSValueConditionalyUnboxNumber(long, longValue);
72 | NSValueConditionalyUnboxNumber(long long, longLongValue);
73 |
74 | NSValueConditionalyUnboxNumber(unsigned char, unsignedCharValue);
75 | NSValueConditionalyUnboxNumber(unsigned short, unsignedShortValue);
76 | NSValueConditionalyUnboxNumber(unsigned int, unsignedIntValue);
77 | NSValueConditionalyUnboxNumber(unsigned long, unsignedLongValue);
78 | NSValueConditionalyUnboxNumber(unsigned long long, unsignedLongLongValue);
79 |
80 | NSValueConditionalyUnboxNumber(float, floatValue);
81 | NSValueConditionalyUnboxNumber(double, doubleValue);
82 |
83 | NSValueConditionalyUnboxNumber(_Bool, boolValue);
84 |
85 | if (strcmp(type, self.objCType) == 0) {
86 | [self getValue:buffer];
87 | return YES;
88 | }
89 |
90 | return NO;
91 |
92 | #undef NSValueConditionalyUnboxNumber
93 | }
94 |
95 |
96 | + (BOOL)objCTypeIsNumeric:(const char *)type {
97 | if ( ! type) return NO;
98 |
99 | NSValueConditional(char) return YES;
100 | NSValueConditional(short) return YES;
101 | NSValueConditional(int) return YES;
102 | NSValueConditional(long) return YES;
103 | NSValueConditional(long long) return YES;
104 |
105 | NSValueConditional(unsigned char) return YES;
106 | NSValueConditional(unsigned short) return YES;
107 | NSValueConditional(unsigned int) return YES;
108 | NSValueConditional(unsigned long) return YES;
109 | NSValueConditional(unsigned long long) return YES;
110 |
111 | NSValueConditional(float) return YES;
112 | NSValueConditional(double) return YES;
113 |
114 | NSValueConditional(_Bool) return YES;
115 |
116 | return NO;
117 | }
118 |
119 |
120 | #undef NSValueConditional
121 |
122 |
123 |
124 |
125 | @end
126 |
--------------------------------------------------------------------------------
/Sources/Foundation/Utilities/OCADebug.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCADebug.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 3.2.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "OCAProducer.h"
11 |
12 |
13 |
14 | typedef void(^OCADebugBlock)(id);
15 |
16 |
17 |
18 |
19 |
20 | #define OCADebugStop ^(id value) { OCABreakpointStop(value); }
21 | extern void OCABreakpointStop(id value);
22 |
23 |
24 | #define OCADebugSound ^(id value) { OCABreakpointSound(value); }
25 | extern void OCABreakpointSound(id value);
26 |
27 |
28 | #define OCADebugLog(FLAG) ^(id value) { NSLog(@"%@: %@", @#FLAG, value); }
29 |
30 |
31 |
32 |
33 |
34 | @interface OCAProducer (OCADebug)
35 |
36 |
37 | - (OCAProducer *)debug:(OCADebugBlock)block;
38 |
39 |
40 | @end
41 |
42 |
43 |
--------------------------------------------------------------------------------
/Sources/Foundation/Utilities/OCADebug.m:
--------------------------------------------------------------------------------
1 | //
2 | // OCADebug.m
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 3.2.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCADebug.h"
10 | #import "OCABridge.h"
11 | #import "OCATransformer+Core.h"
12 |
13 |
14 |
15 |
16 |
17 | extern void OCABreakpointStop(id value) {
18 | /*
19 | * This function is used for Symbolic Breakpoint.
20 | * If you stopped here, you can see the `value`, that was send from Producer to Consumer.
21 | * You can navigate up in the stack trace and you will see the the place where this happened.
22 | */
23 | }
24 |
25 |
26 | extern void OCABreakpointSound(id value) {
27 | /*
28 | * This function is used for Symbolic Breakpoint.
29 | */
30 | }
31 |
32 |
33 |
34 |
35 |
36 | @implementation OCAProducer (OCADebug)
37 |
38 |
39 |
40 | - (OCAProducer *)debug:(OCADebugBlock)block {
41 | OCABridge *debugBridge = [[OCABridge alloc] initWithTransformer:[OCATransformer sideEffect:block]];
42 | [self addConsumer:debugBridge];
43 | return debugBridge;
44 | }
45 |
46 |
47 |
48 | @end
49 |
50 |
51 |
--------------------------------------------------------------------------------
/Sources/Foundation/Utilities/OCADecomposer.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCADecomposer.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 8.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAObject.h"
10 |
11 |
12 |
13 | typedef void(^OCADecomposerBlock)(__unsafe_unretained id owner);
14 |
15 |
16 |
17 |
18 |
19 | @interface OCADecomposer : OCAObject
20 |
21 |
22 |
23 | #pragma mark Managing Owned Objects
24 |
25 | - (void)addOwnedObject:(id)object cleanup:(OCADecomposerBlock)block;
26 | - (void)removeOwnedObject:(id)object;
27 |
28 | - (NSArray *)ownedObjects;
29 | - (id)findOwnedObjectOfClass:(Class)theClass usingBlock:(BOOL(^)(id ownedObject))filterBlock;
30 |
31 |
32 |
33 | @end
34 |
35 |
36 |
37 |
38 |
39 | @interface NSObject (OCADecomposer)
40 |
41 |
42 | - (OCADecomposer *)decomposer;
43 |
44 |
45 | @end
46 |
47 |
48 |
--------------------------------------------------------------------------------
/Sources/Foundation/Utilities/OCAInvocationCatcher.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCAInvocationCatcher.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 27.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 |
12 |
13 |
14 |
15 | @interface OCAInvocationCatcher : NSProxy
16 |
17 |
18 |
19 | #define OCAInvocationCatch(TARGET, METHOD) \
20 | (OCAInvocation *)({ \
21 | OCAInvocationCatcher *catcher = [[OCAInvocationCatcher alloc] initWithTarget:(TARGET)]; \
22 | [(typeof(TARGET))catcher METHOD]; \
23 | [catcher.invocation retainArguments]; /* This is the reason why you cannot use this invocation with OCAInvoker. */ \
24 | catcher.invocation; \
25 | }) \
26 |
27 |
28 |
29 | - (instancetype)initWithTarget:(id)target;
30 | @property (nonatomic, readonly, strong) id target;
31 |
32 |
33 | - (void)forwardInvocation:(NSInvocation *)invocation;
34 | @property (nonatomic, readonly, strong) NSInvocation *invocation;
35 |
36 | //! Argument are retained by this class, not relying on NSInvocation retain.
37 | @property (nonatomic, readonly, strong) NSArray *retainedArguments;
38 |
39 |
40 |
41 | @end
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | @interface NSInvocation (ObjectArguments)
50 |
51 |
52 | - (void)oca_enumerateObjectArgumentsUsingBlock:(void(^)(NSUInteger index, id argument))block;
53 |
54 |
55 | @end
56 |
57 |
58 |
--------------------------------------------------------------------------------
/Sources/Foundation/Utilities/OCAInvocationCatcher.m:
--------------------------------------------------------------------------------
1 | //
2 | // OCAInvocationCatcher.m
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 27.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAInvocationCatcher.h"
10 |
11 |
12 |
13 |
14 |
15 | @implementation OCAInvocationCatcher
16 |
17 |
18 |
19 |
20 |
21 | - (instancetype)initWithTarget:(id)target {
22 | // NSProxy doesn't have -init
23 | self->_target = target;
24 | return self;
25 | }
26 |
27 |
28 | - (NSMethodSignature *)methodSignatureForSelector:(SEL)selector {
29 | return [self.target methodSignatureForSelector:selector];
30 | }
31 |
32 |
33 | - (void)forwardInvocation:(NSInvocation *)invocation {
34 | [invocation invokeWithTarget:(__nonnull id)nil]; // Ah.
35 | invocation.target = self.target;
36 | self->_invocation = invocation;
37 |
38 | [self retainArguments]; //! Because NSInvocation is fucked up.
39 | }
40 |
41 |
42 | - (void)retainArguments {
43 | NSMutableArray *retainedArguments = [[NSMutableArray alloc] init];
44 | [self.invocation oca_enumerateObjectArgumentsUsingBlock:^(NSUInteger index, id argument) {
45 | if (argument) {
46 | [retainedArguments addObject:argument];
47 | }
48 | }];
49 | self->_retainedArguments = retainedArguments;
50 | }
51 |
52 |
53 |
54 |
55 |
56 | @end
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 | @implementation NSInvocation (ObjectArguments)
67 |
68 |
69 |
70 | - (void)oca_enumerateObjectArgumentsUsingBlock:(void(^)(NSUInteger index, id argument))block {
71 | NSUInteger count = self.methodSignature.numberOfArguments;
72 | for (NSUInteger index = 0; index < count; index++) {
73 |
74 | const char *cType = [self.methodSignature getArgumentTypeAtIndex:index];
75 | if ([@(cType) isEqualToString:@(@encode(id))]) {
76 | // Only objects, including target.
77 |
78 | __unsafe_unretained id argument = nil;
79 | [self getArgument:&argument atIndex:index];
80 |
81 | block(index, argument);
82 | }
83 | }
84 | }
85 |
86 |
87 |
88 | @end
89 |
90 |
91 |
--------------------------------------------------------------------------------
/Sources/Foundation/Utilities/OCAKeyValueChange.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCAKeyValueChange.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 29.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAObject.h"
10 | #import "OCAStructureAccessor.h"
11 | @class OCAKeyValueChangeSetting;
12 | @class OCAKeyValueChangeInsertion;
13 | @class OCAKeyValueChangeRemoval;
14 | @class OCAKeyValueChangeReplacement;
15 | @class OCAProperty;
16 |
17 |
18 |
19 |
20 |
21 | @interface OCAKeyValueChange : OCAObject
22 |
23 |
24 | - (instancetype)initWithObject:(NSObject *)object keyPath:(NSString *)keyPath change:(NSDictionary *)dictionary structureAccessor:(OCAStructureAccessor *)accessor;
25 | @property (nonatomic, readonly, weak) id object;
26 | @property (nonatomic, readonly, copy) NSString *keyPath;
27 | @property (nonatomic, readonly, copy) NSDictionary *changeDictionary;
28 | @property (nonatomic, readonly, strong) OCAStructureAccessor *accessor;
29 |
30 | @property (nonatomic, readonly, strong) id latestValue;
31 | @property (nonatomic, readonly) BOOL isPrior;
32 | @property (nonatomic, readonly) NSKeyValueChange kind;
33 |
34 | - (OCAKeyValueChangeSetting *)asSettingChange;
35 | - (OCAKeyValueChangeInsertion *)asInsertionChange;
36 | - (OCAKeyValueChangeRemoval *)asRemovalChange;
37 | - (OCAKeyValueChangeReplacement *)asReplacementChange;
38 |
39 | - (void)applyToProperty:(OCAProperty *)property;
40 |
41 |
42 | @end
43 |
44 |
45 |
46 |
47 |
48 | @interface OCAKeyValueChangeSetting : OCAKeyValueChange
49 |
50 |
51 | @property (nonatomic, readonly, assign) BOOL isInitial;
52 | @property (nonatomic, readonly) id previousValue; // Do not use to compare.
53 |
54 | - (BOOL)isLatestEqualToPrevious;
55 |
56 | - (instancetype)copyWithTransformedInsertedObjects:(NSValueTransformer *)transformer;
57 |
58 |
59 | @end
60 |
61 |
62 |
63 |
64 |
65 | @interface OCAKeyValueChangeInsertion : OCAKeyValueChange
66 |
67 |
68 | @property (nonatomic, readonly, strong) NSArray *insertedObjects;
69 | @property (nonatomic, readonly, strong) NSIndexSet *insertedIndexes;
70 |
71 | - (instancetype)copyWithTransformedInsertedObjects:(NSValueTransformer *)transformer;
72 |
73 |
74 | @end
75 |
76 |
77 |
78 |
79 |
80 | @interface OCAKeyValueChangeRemoval : OCAKeyValueChange
81 |
82 |
83 | @property (nonatomic, readonly, strong) NSArray *removedObjects;
84 | @property (nonatomic, readonly, strong) NSIndexSet *removedIndexes;
85 |
86 |
87 | @end
88 |
89 |
90 |
91 |
92 |
93 | @interface OCAKeyValueChangeReplacement : OCAKeyValueChange
94 |
95 |
96 | @property (nonatomic, readonly, strong) NSArray *removedObjects;
97 | @property (nonatomic, readonly, strong) NSArray *insertedObjects;
98 | @property (nonatomic, readonly, strong) NSIndexSet *replacedIndexes;
99 |
100 |
101 | - (instancetype)copyWithTransformedInsertedObjects:(NSValueTransformer *)transformer;
102 |
103 |
104 | @end
105 |
106 |
107 |
108 |
109 |
--------------------------------------------------------------------------------
/Sources/Foundation/Utilities/OCAMutableArrayProxy.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCAMutableArrayProxy.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 17.4.15.
6 | // Copyright (c) 2015 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAAccessor.h"
10 |
11 |
12 |
13 |
14 |
15 | @interface OCAMutableArrayProxy : NSProxy
16 |
17 |
18 |
19 | - (instancetype)initWithReceiver:(id)receiver accessor:(OCAAccessor *)accessor;
20 | - (NSMutableArray *)asMutableArray;
21 |
22 | @property (nonatomic, readonly, strong) id receiver;
23 | @property (nonatomic, readonly, strong) OCAAccessor *accessor;
24 |
25 |
26 | @end
27 |
28 |
29 |
--------------------------------------------------------------------------------
/Sources/Foundation/Utilities/OCAMutableArrayProxy.m:
--------------------------------------------------------------------------------
1 | //
2 | // OCAMutableArrayProxy.m
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 17.4.15.
6 | // Copyright (c) 2015 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAMutableArrayProxy.h"
10 |
11 |
12 |
13 |
14 |
15 | @implementation OCAMutableArrayProxy
16 |
17 |
18 |
19 |
20 |
21 | - (instancetype)initWithReceiver:(NSObject *)receiver accessor:(OCAAccessor *)accessor {
22 | self->_receiver = receiver;
23 | self->_accessor = accessor;
24 | return self;
25 | }
26 |
27 |
28 | - (NSMutableArray *)asMutableArray {
29 | return (NSMutableArray *)self;
30 | }
31 |
32 |
33 |
34 |
35 |
36 | + (NSMethodSignature *)methodSignatureForSelector:(SEL)selector {
37 | return [NSMutableArray methodSignatureForSelector:selector];
38 | }
39 |
40 |
41 | - (NSMethodSignature *)methodSignatureForSelector:(SEL)selector {
42 | return [NSMutableArray instanceMethodSignatureForSelector:selector];
43 | }
44 |
45 |
46 | - (void)forwardInvocation:(NSInvocation *)invocation {
47 | NSArray *array = [self.accessor accessObject: self.receiver];
48 | if ( ! [array isKindOfClass:[NSArray class]]) {
49 | array = nil;
50 | }
51 | NSMutableArray *mutableArray = [array mutableCopy];
52 | [invocation invokeWithTarget: mutableArray];
53 | [self.accessor modifyObject: self.receiver withValue: mutableArray];
54 | }
55 |
56 |
57 |
58 |
59 |
60 | @end
61 |
62 |
63 |
--------------------------------------------------------------------------------
/Sources/Foundation/Utilities/OCAPlaceholderObject.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCAPlaceholderObject.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 3.2.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAObject.h"
10 |
11 |
12 |
13 |
14 |
15 | @interface OCAPlaceholderObject : OCAObject
16 |
17 |
18 |
19 | #define OCAPH(CLASS) OCAPlaceholder(CLASS)
20 | #define OCAPlaceholder(CLASS) ((CLASS *)[OCAPlaceholderObject placeholderForClass:[CLASS class]])
21 |
22 | + (instancetype)placeholderForClass:(Class)theClass;
23 |
24 | @property (atomic, readonly, strong) Class representedClass;
25 |
26 |
27 |
28 | @end
29 |
30 |
31 |
--------------------------------------------------------------------------------
/Sources/Foundation/Utilities/OCAPlaceholderObject.m:
--------------------------------------------------------------------------------
1 | //
2 | // OCAPlaceholderObject.m
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 3.2.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAPlaceholderObject.h"
10 | #import
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | @implementation OCAPlaceholderObject
22 |
23 |
24 |
25 |
26 |
27 | + (instancetype)placeholderForClass:(Class)class {
28 | static void *OCAPlaceholderObjectKey = &OCAPlaceholderObjectKey;
29 | OCAPlaceholderObject *placeholder = objc_getAssociatedObject(class, OCAPlaceholderObjectKey);
30 | if (placeholder) return placeholder;
31 |
32 | placeholder = [[self alloc] initWithRepresentedClass:class];
33 | objc_setAssociatedObject(class, OCAPlaceholderObjectKey, placeholder, OBJC_ASSOCIATION_RETAIN);
34 | return placeholder;
35 | }
36 |
37 |
38 | - (instancetype)init {
39 | return [self initWithRepresentedClass:nil];
40 | }
41 |
42 |
43 | - (instancetype)initWithRepresentedClass:(Class)class {
44 | self = [super init];
45 | if (self) {
46 | self->_representedClass = class;
47 | }
48 | return self;
49 | }
50 |
51 |
52 | - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
53 | return [self.representedClass instanceMethodSignatureForSelector:aSelector];
54 | }
55 |
56 |
57 | - (void)forwardInvocation:(NSInvocation *)invocation {
58 | [invocation invokeWithTarget:(__nonnull id)nil]; // Ah.
59 | }
60 |
61 |
62 |
63 |
64 |
65 | @end
66 |
67 |
68 |
--------------------------------------------------------------------------------
/Sources/Foundation/Utilities/OCAQueue.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCAQueue.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 6.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAObject.h"
10 |
11 |
12 |
13 | typedef void (^OCAQueueBlock)(void);
14 |
15 |
16 |
17 |
18 |
19 | @interface OCAQueue : OCAObject
20 |
21 |
22 |
23 | #pragma mark Getting Shared Queues
24 |
25 | + (instancetype)main;
26 | + (instancetype)interactive;
27 | + (instancetype)user;
28 | + (instancetype)utility;
29 | + (instancetype)background;
30 |
31 |
32 | #pragma mark Accessing Current Queue
33 |
34 | + (instancetype)current;
35 |
36 |
37 | #pragma mark Creating Queues
38 |
39 | - (instancetype)initWithName:(NSString *)name concurrent:(BOOL)isConcurrent targetQueue:(OCAQueue *)targetQueue;
40 |
41 | + (instancetype)serialQueue:(NSString *)name;
42 | + (instancetype)concurrentQueue:(NSString *)name;
43 |
44 |
45 | #pragma mark Attributes of Queue
46 |
47 | @property (atomic, readonly, copy) NSString *name;
48 | @property (atomic, readonly, assign) BOOL isConcurrent;
49 | @property (atomic, readonly, strong) dispatch_queue_t dispatchQueue;
50 |
51 |
52 | #pragma mark Adding Blocks to Queue
53 |
54 | - (void)performBlock:(OCAQueueBlock)block;
55 | - (void)performBlockAndWait:(OCAQueueBlock)block;
56 | - (void)performBlockAndTryWait:(OCAQueueBlock)block;
57 |
58 | - (void)performBarrierBlock:(OCAQueueBlock)block;
59 | - (void)performBarrierBlockAndWait:(OCAQueueBlock)block;
60 |
61 | - (void)performAfter:(NSTimeInterval)delay block:(OCAQueueBlock)block;
62 | - (void)performMultiple:(NSUInteger)count blocks:(void(^)(NSUInteger i))block;
63 |
64 |
65 | #pragma mark Accessing Target Queue
66 |
67 | @property (atomic, readonly, strong) OCAQueue *targetQueue;
68 | - (BOOL)isTargetedTo:(OCAQueue *)queue;
69 |
70 |
71 |
72 | @end
73 |
74 |
75 |
--------------------------------------------------------------------------------
/Sources/Foundation/Utilities/OCASemaphore.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCASemaphore.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 31.12.13.
6 | // Copyright © 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAObject.h"
10 |
11 |
12 |
13 |
14 |
15 | /// Simple wrapper of GCD semaphore.
16 | @interface OCASemaphore : OCAObject
17 |
18 |
19 |
20 | - (instancetype)initWithValue:(NSUInteger)integer;
21 |
22 | - (void)signal;
23 |
24 | - (void)wait;
25 | - (BOOL)waitFor:(NSTimeInterval)interval;
26 | - (BOOL)waitUntil:(NSDate *)date;
27 |
28 |
29 |
30 | @end
31 |
--------------------------------------------------------------------------------
/Sources/Foundation/Utilities/OCASemaphore.m:
--------------------------------------------------------------------------------
1 | //
2 | // OCASemaphore.m
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 31.12.13.
6 | // Copyright © 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCASemaphore.h"
10 |
11 |
12 |
13 | @interface OCASemaphore ()
14 |
15 | @property (atomic, readonly, strong) dispatch_semaphore_t semaphore;
16 |
17 | @end
18 |
19 |
20 |
21 |
22 |
23 | @implementation OCASemaphore
24 |
25 |
26 |
27 |
28 |
29 | #pragma mark Creating Semaphore
30 |
31 |
32 | - (instancetype)init {
33 | return [self initWithValue:0];
34 | }
35 |
36 |
37 | - (instancetype)initWithValue:(NSUInteger)integer {
38 | self = [super init];
39 | if (self) {
40 | self->_semaphore = dispatch_semaphore_create(integer);
41 | }
42 | return self;
43 | }
44 |
45 |
46 |
47 |
48 |
49 | #pragma mark Using Semaphore
50 |
51 |
52 | - (void)signal {
53 | dispatch_semaphore_signal(self.semaphore);
54 | }
55 |
56 |
57 | - (void)wait {
58 | dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);
59 | }
60 |
61 |
62 | - (BOOL)waitFor:(NSTimeInterval)interval {
63 | dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, interval * NSEC_PER_SEC);
64 | long timedOut = dispatch_semaphore_wait(self.semaphore, time);
65 | return ! timedOut;
66 | }
67 |
68 |
69 | - (BOOL)waitUntil:(NSDate *)date {
70 | return [self waitFor:date.timeIntervalSinceNow];
71 | }
72 |
73 |
74 |
75 |
76 |
77 | @end
78 |
--------------------------------------------------------------------------------
/Sources/Foundation/Utilities/OCASwizzling.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCASwizzling.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 6.5.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "OCAConsumer.h"
11 |
12 |
13 |
14 |
15 |
16 | @interface NSObject (OCASwizzling)
17 |
18 |
19 | + (void)swizzleSelector:(SEL)original with:(SEL)replacement;
20 |
21 |
22 | + (void)implementOrderedCollectionAccessorsForKey:(NSString *)key;
23 | + (void)implementOrderedCollectionAccessorsForKey:(NSString *)key insertionCallback:(id)insertionCallback removalCallback:(id)removalCallback;
24 |
25 |
26 | @end
27 |
28 |
29 |
--------------------------------------------------------------------------------
/Sources/Foundation/Utilities/OCAVariadic.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCAVariadic.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 1.2.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 |
12 |
13 |
14 |
15 | /// Returns string formatted using variable argument list format. Pass the formattign string as an argument.
16 | #define OCAStringFromFormat(format) \
17 | (NSString *)({ \
18 | va_list __vargs; \
19 | va_start(__vargs, format); \
20 | NSString *__string = [[NSString alloc] initWithFormat:format arguments:__vargs]; \
21 | va_end(__vargs); \
22 | __string; \
23 | })
24 |
25 |
26 |
27 | /// Collects variable argument list that begins with `first` into mutable array. Any arrays found in the list are expanded.
28 | #define OCAArrayFromVariadicArguments(first) \
29 | (NSMutableArray *)({ \
30 | va_list list; \
31 | va_start(list, first); \
32 | NSMutableArray *array = OCAArrayFromVariadicList(first, list); \
33 | va_end(list); \
34 | array; \
35 | })
36 |
37 |
38 |
39 | /// Helper macro for providing an array to variable argument method. Such method must handle these cases, for example using OCAArrayFromVariadicArguments.
40 | #define OCAVariadic(ARRAY) (id)(ARRAY), nil
41 |
42 |
43 |
44 | /// Function that is used by OCAArrayFromVariadicArguments. Collects object from variadic list into mutable array. Any arrays found in the list are epanded.
45 | extern NSMutableArray * OCAArrayFromVariadicList(id first, va_list list);
46 |
47 |
48 |
--------------------------------------------------------------------------------
/Sources/Foundation/Utilities/OCAVariadic.m:
--------------------------------------------------------------------------------
1 | //
2 | // OCAVariadic.m
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 1.2.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAVariadic.h"
10 |
11 |
12 |
13 |
14 |
15 | NSMutableArray * OCAArrayFromVariadicList(id first, va_list list) {
16 | NSMutableArray *array = [[NSMutableArray alloc] init];
17 | id object = first;
18 | while (object) {
19 | if ([object isKindOfClass:[NSArray class]]) {
20 | [array addObjectsFromArray:(NSArray *)object];
21 | }
22 | else {
23 | [array addObject:object];
24 | }
25 | object = va_arg(list, id);
26 | }
27 | return array;
28 | }
29 |
30 |
31 |
--------------------------------------------------------------------------------
/Sources/Geometry/OCAGeometry+Functions.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCAGeometry+Functions.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 27.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 | #import "NSValue+Boxing.h"
12 | #import "OCAObject.h"
13 |
14 | #if OCA_iOS
15 | #import
16 | #endif
17 |
18 |
19 |
20 |
21 |
22 | #pragma mark -
23 | #pragma mark Rounding
24 |
25 | extern CGFloat OCAGeometryDefaultScale(void);
26 | extern CGFloat OCAGeometryRound(CGFloat value, CGFloat scale);
27 | extern CGFloat OCAGeometryFloor(CGFloat value, CGFloat scale);
28 | extern CGFloat OCAGeometryCeil(CGFloat value, CGFloat scale);
29 |
30 |
31 |
32 |
33 |
34 | #pragma mark -
35 | #pragma mark Point
36 |
37 | extern CGPoint OCAPointFromString(NSString *);
38 | extern NSString * OCAStringFromPoint(CGPoint);
39 |
40 | extern CGPoint OCAPointAddPoint(CGPoint, CGPoint);
41 | extern CGPoint OCAPointSubtractPoint(CGPoint, CGPoint);
42 | extern CGPoint OCAPointMultiply(CGPoint point, CGFloat multipler);
43 | extern CGPoint OCAPointNormalize(CGPoint);
44 |
45 | extern CGPoint OCAPointRound(CGPoint point, CGFloat scale);
46 | extern CGPoint OCAPointFloor(CGPoint point, CGFloat scale);
47 | extern CGPoint OCAPointCeil(CGPoint point, CGFloat scale);
48 |
49 | extern CGFloat OCAPointDistanceToPoint(CGPoint, CGPoint);
50 | extern CGFloat OCAPointGetMagnitude(CGPoint);
51 | extern CGFloat OCAPointGetAngle(CGPoint);
52 |
53 |
54 |
55 |
56 |
57 | #pragma mark -
58 | #pragma mark Size
59 |
60 | extern CGSize OCASizeFromString(NSString *);
61 | extern NSString * OCAStringFromSize(CGSize);
62 |
63 | extern CGSize OCASizeExtendBySize(CGSize, CGSize);
64 | extern CGSize OCASizeShrinkBySize(CGSize, CGSize);
65 | extern CGSize OCASizeMultiply(CGSize, CGFloat);
66 | extern CGSize OCASizeStandardize(CGSize size);
67 |
68 | extern CGSize OCASizeRound(CGSize size, CGFloat scale);
69 | extern CGSize OCASizeFloor(CGSize size, CGFloat scale);
70 | extern CGSize OCASizeCeil(CGSize size, CGFloat scale);
71 |
72 | extern CGFloat OCASizeGetArea(CGSize size);
73 | extern CGFloat OCASizeGetRatio(CGSize size);
74 |
75 |
76 |
77 |
78 |
79 | #pragma mark -
80 | #pragma mark Rectangle
81 |
82 | extern CGRect OCARectFromString(NSString *);
83 | extern NSString * OCAStringFromRect(CGRect);
84 |
85 | extern CGRect OCARectRound(CGRect rect, CGFloat scale);
86 | extern CGRect OCARectCeil(CGRect rect, CGFloat scale);
87 | extern CGRect OCARectFloor(CGRect rect, CGFloat scale);
88 |
89 | extern CGPoint OCARectGetRelativePoint(CGRect rect, CGPoint point);
90 | extern CGFloat OCARectGetEdge(CGRect, CGRectEdge);
91 |
92 |
93 |
94 |
95 |
96 | #if OCA_iOS
97 |
98 | #pragma mark -
99 | #pragma mark Edge Insets
100 |
101 | extern UIEdgeInsets OCAEdgeInsetsAddEdgeInsets(UIEdgeInsets, UIEdgeInsets);
102 | extern UIEdgeInsets OCAEdgeInsetsSubtractEdgeInsets(UIEdgeInsets, UIEdgeInsets);
103 | extern UIEdgeInsets OCAEdgeInsetsMultiply(UIEdgeInsets insets, CGFloat multipler);
104 |
105 | extern UIEdgeInsets OCAEdgeInsetsRound(UIEdgeInsets insets, CGFloat scale);
106 | extern UIEdgeInsets OCAEdgeInsetsFloor(UIEdgeInsets insets, CGFloat scale);
107 | extern UIEdgeInsets OCAEdgeInsetsCeil(UIEdgeInsets insets, CGFloat scale);
108 |
109 | #endif
110 |
111 |
112 |
--------------------------------------------------------------------------------
/Sources/Geometry/OCAGeometry.h:
--------------------------------------------------------------------------------
1 | //
2 | // ObjectiveChain.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 30.12.13.
6 | // Copyright © 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 |
10 |
11 | #import "OCAGeometry+Functions.h"
12 |
13 |
14 | #import "OCAGeometry+Functions.h"
15 | #import "OCATransformer+CGPoint.h"
16 | #import "OCATransformer+CGSize.h"
17 | #import "OCATransformer+CGRect.h"
18 | #import "OCATransformer+CGAffineTransform.h"
19 | #import "OCATransformer+UIEdgeInsets.h"
20 | #import "OCATransformer+CATransform3D.h"
21 | //TODO: CGPath
22 |
23 |
24 | #import "OCAPredicate+CGPoint.h"
25 | #import "OCAPredicate+CGSize.h"
26 | #import "OCAPredicate+CGRect.h"
27 | #import "OCAPredicate+CGAffineTransform.h"
28 | #import "OCAPredicate+UIEdgeInsets.h"
29 | #import "OCAPredicate+CATransform3D.h"
30 |
31 |
32 |
--------------------------------------------------------------------------------
/Sources/Geometry/Predicates/OCAPredicate+CATransform3D.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCAPredicate+CATransform3D.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 28.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "OCAPredicate.h"
11 |
12 |
13 |
14 |
15 |
16 | @interface OCAPredicate (CATransform3D)
17 |
18 |
19 |
20 | + (NSPredicate *)predicateForTransform3D:(BOOL(^)(CATransform3D t))block;
21 |
22 | + (NSPredicate *)isTransform3DEqualTo:(CATransform3D)otherTransform3D;
23 | + (NSPredicate *)isTransform3DIdentity;
24 |
25 | + (NSPredicate *)isTransform3DAffineTransform;
26 |
27 |
28 |
29 | @end
30 |
31 |
32 |
--------------------------------------------------------------------------------
/Sources/Geometry/Predicates/OCAPredicate+CATransform3D.m:
--------------------------------------------------------------------------------
1 | //
2 | // OCAPredicate+CATransform3D.m
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 28.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAPredicate+CATransform3D.h"
10 | #import "OCAGeometry+Functions.h"
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | @implementation OCAPredicate (CATransform3D)
22 |
23 |
24 |
25 |
26 |
27 | + (NSPredicate *)predicateForTransform3D:(BOOL(^)(CATransform3D t))block {
28 | return [OCAPredicate predicateForClass:[NSValue class] block:^BOOL(NSValue *value) {
29 | CATransform3D t;
30 | BOOL success = [value unboxValue:&t objCType:@encode(CATransform3D)];
31 | if ( ! success) return NO;
32 |
33 | return block(t);
34 | }];
35 | }
36 |
37 |
38 | + (NSPredicate *)isTransform3DEqualTo:(CATransform3D)otherTransform3D {
39 | return [OCAPredicate predicateForTransform3D:^BOOL(CATransform3D t) {
40 | return CATransform3DEqualToTransform(t, otherTransform3D);
41 | }];
42 | }
43 |
44 |
45 | + (NSPredicate *)isTransform3DIdentity {
46 | return [OCAPredicate predicateForTransform3D:^BOOL(CATransform3D t) {
47 | return CATransform3DIsIdentity(t);
48 | }];
49 | }
50 |
51 |
52 | + (NSPredicate *)isTransform3DAffineTransform {
53 | return [OCAPredicate predicateForTransform3D:^BOOL(CATransform3D t) {
54 | return CATransform3DIsAffine(t);
55 | }];
56 | }
57 |
58 |
59 |
60 |
61 |
62 | @end
63 |
64 |
65 |
--------------------------------------------------------------------------------
/Sources/Geometry/Predicates/OCAPredicate+CGAffineTransform.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCAPredicate+CGAffineTransform.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 28.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "OCAPredicate.h"
11 |
12 |
13 |
14 |
15 |
16 | @interface OCAPredicate (CGAffineTransform)
17 |
18 |
19 |
20 | + (NSPredicate *)predicateForAffineTransform:(BOOL(^)(CGAffineTransform t))block;
21 |
22 | + (NSPredicate *)isAffineTransformEqualTo:(CGAffineTransform)otherAffineTransform;
23 | + (NSPredicate *)isAffineTransformIdentity;
24 |
25 |
26 |
27 | @end
28 |
29 |
30 |
--------------------------------------------------------------------------------
/Sources/Geometry/Predicates/OCAPredicate+CGAffineTransform.m:
--------------------------------------------------------------------------------
1 | //
2 | // OCAPredicate+CGAffineTransform.m
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 28.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAPredicate+CGAffineTransform.h"
10 | #import "OCAGeometry+Functions.h"
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | @implementation OCAPredicate (CGAffineTransform)
22 |
23 |
24 |
25 |
26 |
27 | + (NSPredicate *)predicateForAffineTransform:(BOOL(^)(CGAffineTransform t))block {
28 | return [OCAPredicate predicateForClass:[NSValue class] block:^BOOL(NSValue *value) {
29 | CGAffineTransform t;
30 | BOOL success = [value unboxValue:&t objCType:@encode(CGAffineTransform)];
31 | if ( ! success) return NO;
32 |
33 | return block(t);
34 | }];
35 | }
36 |
37 |
38 | + (NSPredicate *)isAffineTransformIdentity {
39 | return [OCAPredicate predicateForAffineTransform:^BOOL(CGAffineTransform t) {
40 | return CGAffineTransformIsIdentity(t);
41 | }];
42 | }
43 |
44 |
45 | + (NSPredicate *)isAffineTransformEqualTo:(CGAffineTransform)otherAffineTransform {
46 | return [OCAPredicate predicateForAffineTransform:^BOOL(CGAffineTransform t) {
47 | return CGAffineTransformEqualToTransform(t, otherAffineTransform);
48 | }];
49 | }
50 |
51 |
52 |
53 |
54 |
55 | @end
56 |
--------------------------------------------------------------------------------
/Sources/Geometry/Predicates/OCAPredicate+CGPoint.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCAPredicate+CGPoint.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 28.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "OCAPredicate.h"
11 |
12 |
13 |
14 |
15 |
16 | @interface OCAPredicate (CGPoint)
17 |
18 |
19 |
20 | + (NSPredicate *)predicateForPoint:(BOOL(^)(CGPoint point))block;
21 |
22 | + (NSPredicate *)isPointEqualTo:(CGPoint)otherPoint;
23 | + (NSPredicate *)isPointZero;
24 |
25 | + (NSPredicate *)isPointFurtherFrom:(CGPoint)otherPoint than:(CGFloat)distance;
26 | + (NSPredicate *)isPointCloserTo:(CGPoint)otherPoint than:(CGFloat)distance;
27 |
28 | + (NSPredicate *)isPointContainedInRect:(CGRect)rect;
29 |
30 |
31 |
32 | @end
33 |
34 |
35 |
--------------------------------------------------------------------------------
/Sources/Geometry/Predicates/OCAPredicate+CGPoint.m:
--------------------------------------------------------------------------------
1 | //
2 | // OCAPredicate+CGPoint.m
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 28.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAPredicate+CGPoint.h"
10 | #import "OCAGeometry+Functions.h"
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | @implementation OCAPredicate (CGPoint)
22 |
23 |
24 |
25 |
26 |
27 | + (NSPredicate *)predicateForPoint:(BOOL(^)(CGPoint point))block {
28 | return [OCAPredicate predicateForClass:[NSValue class] block:^BOOL(NSValue *value) {
29 | CGPoint point;
30 | BOOL success = [value unboxValue:&point objCType:@encode(CGPoint)];
31 | if ( ! success) return NO;
32 |
33 | return block(point);
34 | }];
35 | }
36 |
37 |
38 | + (NSPredicate *)isPointEqualTo:(CGPoint)otherPoint {
39 | return [OCAPredicate predicateForPoint:^BOOL(CGPoint point) {
40 | return CGPointEqualToPoint(point, otherPoint);
41 | }];
42 | }
43 |
44 |
45 | + (NSPredicate *)isPointZero {
46 | return [OCAPredicate isPointEqualTo:CGPointZero];
47 | }
48 |
49 |
50 | + (NSPredicate *)isPointFurtherFrom:(CGPoint)otherPoint than:(CGFloat)distance {
51 | return [OCAPredicate predicateForPoint:^BOOL(CGPoint point) {
52 | return (OCAPointDistanceToPoint(point, otherPoint) >= distance);
53 | }];
54 | }
55 |
56 |
57 | + (NSPredicate *)isPointCloserTo:(CGPoint)otherPoint than:(CGFloat)distance {
58 | return [OCAPredicate predicateForPoint:^BOOL(CGPoint point) {
59 | return (OCAPointDistanceToPoint(point, otherPoint) <= distance);
60 | }];
61 | }
62 |
63 |
64 | + (NSPredicate *)isPointContainedInRect:(CGRect)rect {
65 | return [OCAPredicate predicateForPoint:^BOOL(CGPoint point) {
66 | return CGRectContainsPoint(rect, point);
67 | }];
68 | }
69 |
70 |
71 |
72 |
73 |
74 | @end
75 |
76 |
77 |
--------------------------------------------------------------------------------
/Sources/Geometry/Predicates/OCAPredicate+CGRect.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCAPredicate+CGRect.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 28.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "OCAPredicate.h"
11 |
12 |
13 |
14 |
15 |
16 | @interface OCAPredicate (CGRect)
17 |
18 |
19 |
20 | + (NSPredicate *)predicateForRect:(BOOL(^)(CGRect rect))block;
21 |
22 | + (NSPredicate *)isRectEqualTo:(CGRect)otherRect;
23 | + (NSPredicate *)isRectZero;
24 | + (NSPredicate *)isRectEmpty;
25 | + (NSPredicate *)isRectNull;
26 | + (NSPredicate *)isRectInfinite;
27 |
28 | + (NSPredicate *)isRectContainsPoint:(CGPoint)point;
29 | + (NSPredicate *)isRectContainsRect:(CGRect)otherRect;
30 | + (NSPredicate *)isRectContainedInRect:(CGRect)otherRect;
31 | + (NSPredicate *)isRectIntersects:(CGRect)otherRect;
32 |
33 |
34 |
35 | @end
36 |
37 |
38 |
--------------------------------------------------------------------------------
/Sources/Geometry/Predicates/OCAPredicate+CGRect.m:
--------------------------------------------------------------------------------
1 | //
2 | // OCAPredicate+CGRect.m
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 28.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAPredicate+CGRect.h"
10 | #import "OCAGeometry+Functions.h"
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | @implementation OCAPredicate (CGRect)
22 |
23 |
24 |
25 |
26 |
27 | + (NSPredicate *)predicateForRect:(BOOL(^)(CGRect rect))block {
28 | return [OCAPredicate predicateForClass:[NSValue class] block:^BOOL(NSValue *value) {
29 | CGRect rect;
30 | BOOL success = [value unboxValue:&rect objCType:@encode(CGRect)];
31 | if ( ! success) return NO;
32 |
33 | return block(rect);
34 | }];
35 | }
36 |
37 |
38 | + (NSPredicate *)isRectEqualTo:(CGRect)otherRect {
39 | return [OCAPredicate predicateForRect:^BOOL(CGRect rect) {
40 | return CGRectEqualToRect(rect, otherRect);
41 | }];
42 | }
43 |
44 |
45 | + (NSPredicate *)isRectZero {
46 | return [OCAPredicate isRectEqualTo:CGRectZero];
47 | }
48 |
49 |
50 | + (NSPredicate *)isRectEmpty {
51 | return [OCAPredicate predicateForRect:^BOOL(CGRect rect) {
52 | return CGRectIsEmpty(rect);
53 | }];
54 | }
55 |
56 |
57 | + (NSPredicate *)isRectNull {
58 | return [OCAPredicate predicateForRect:^BOOL(CGRect rect) {
59 | return CGRectIsNull(rect);
60 | }];
61 | }
62 |
63 |
64 | + (NSPredicate *)isRectInfinite {
65 | return [OCAPredicate predicateForRect:^BOOL(CGRect rect) {
66 | return CGRectIsInfinite(rect);
67 | }];
68 | }
69 |
70 |
71 | + (NSPredicate *)isRectContainsPoint:(CGPoint)point {
72 | return [OCAPredicate predicateForRect:^BOOL(CGRect rect) {
73 | return CGRectContainsPoint(rect, point);
74 | }];
75 | }
76 |
77 |
78 | + (NSPredicate *)isRectContainsRect:(CGRect)otherRect {
79 | return [OCAPredicate predicateForRect:^BOOL(CGRect rect) {
80 | return CGRectContainsRect(rect, otherRect);
81 | }];
82 | }
83 |
84 |
85 | + (NSPredicate *)isRectContainedInRect:(CGRect)otherRect {
86 | return [OCAPredicate predicateForRect:^BOOL(CGRect rect) {
87 | return CGRectContainsRect(otherRect, rect);
88 | }];
89 | }
90 |
91 |
92 | + (NSPredicate *)isRectIntersects:(CGRect)otherRect {
93 | return [OCAPredicate predicateForRect:^BOOL(CGRect rect) {
94 | return CGRectIntersectsRect(rect, otherRect);
95 | }];
96 | }
97 |
98 |
99 |
100 |
101 |
102 | @end
103 |
104 |
105 |
--------------------------------------------------------------------------------
/Sources/Geometry/Predicates/OCAPredicate+CGSize.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCAPredicate+CGSize.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 28.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "OCAPredicate.h"
11 |
12 |
13 |
14 |
15 |
16 | @interface OCAPredicate (CGSize)
17 |
18 |
19 |
20 | + (NSPredicate *)predicateForSize:(BOOL(^)(CGSize size))block;
21 |
22 | + (NSPredicate *)isSizeEqualTo:(CGSize)otherSize;
23 | + (NSPredicate *)isSizeZero;
24 |
25 |
26 |
27 | @end
28 |
29 |
30 |
--------------------------------------------------------------------------------
/Sources/Geometry/Predicates/OCAPredicate+CGSize.m:
--------------------------------------------------------------------------------
1 | //
2 | // OCAPredicate+CGSize.m
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 28.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAPredicate+CGSize.h"
10 | #import "OCAGeometry+Functions.h"
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | @implementation OCAPredicate (CGSize)
22 |
23 |
24 |
25 |
26 |
27 | + (NSPredicate *)predicateForSize:(BOOL(^)(CGSize size))block {
28 | return [OCAPredicate predicateForClass:[NSValue class] block:^BOOL(NSValue *value) {
29 | CGSize size;
30 | BOOL success = [value unboxValue:&size objCType:@encode(CGSize)];
31 | if ( ! success) return NO;
32 |
33 | return block(size);
34 | }];
35 | }
36 |
37 |
38 | + (NSPredicate *)isSizeEqualTo:(CGSize)otherSize {
39 | return [OCAPredicate predicateForSize:^BOOL(CGSize size) {
40 | return CGSizeEqualToSize(size, otherSize);
41 | }];
42 | }
43 |
44 |
45 | + (NSPredicate *)isSizeZero {
46 | return [OCAPredicate isSizeEqualTo:CGSizeZero];
47 | }
48 |
49 |
50 |
51 |
52 |
53 | @end
54 |
55 |
56 |
--------------------------------------------------------------------------------
/Sources/Geometry/Predicates/OCAPredicate+UIEdgeInsets.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCAPredicate+UIEdgeInsets.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 28.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAPredicate.h"
10 |
11 |
12 | #if OCA_iOS
13 |
14 | #import
15 |
16 |
17 |
18 |
19 |
20 | @interface OCAPredicate (UIEdgeInsets)
21 |
22 |
23 |
24 | + (NSPredicate *)predicateForEdgeInsets:(BOOL(^)(UIEdgeInsets insets))block;
25 |
26 | + (NSPredicate *)isEdgeInsetsEqualTo:(UIEdgeInsets)otherInsets;
27 | + (NSPredicate *)isEdgeInsetsZero;
28 |
29 |
30 |
31 | @end
32 |
33 | #endif
34 |
35 |
36 |
--------------------------------------------------------------------------------
/Sources/Geometry/Predicates/OCAPredicate+UIEdgeInsets.m:
--------------------------------------------------------------------------------
1 | //
2 | // OCAPredicate+UIEdgeInsets.m
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 28.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAPredicate+UIEdgeInsets.h"
10 | #import "OCAGeometry+Functions.h"
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | #if OCA_iOS
22 |
23 |
24 | @implementation OCAPredicate (UIEdgeInsets)
25 |
26 |
27 |
28 |
29 |
30 | + (NSPredicate *)predicateForEdgeInsets:(BOOL(^)(UIEdgeInsets insets))block {
31 | return [OCAPredicate predicateForClass:[NSValue class] block:^BOOL(NSValue *value) {
32 | UIEdgeInsets insets;
33 | BOOL success = [value unboxValue:&insets objCType:@encode(UIEdgeInsets)];
34 | if ( ! success) return NO;
35 |
36 | return block(insets);
37 | }];
38 | }
39 |
40 |
41 | + (NSPredicate *)isEdgeInsetsEqualTo:(UIEdgeInsets)otherInsets {
42 | return [OCAPredicate predicateForEdgeInsets:^BOOL(UIEdgeInsets insets) {
43 | return UIEdgeInsetsEqualToEdgeInsets(insets, otherInsets);
44 | }];
45 | }
46 |
47 |
48 | + (NSPredicate *)isEdgeInsetsZero {
49 | return [OCAPredicate predicateForEdgeInsets:^BOOL(UIEdgeInsets insets) {
50 | return UIEdgeInsetsEqualToEdgeInsets(insets, UIEdgeInsetsZero);
51 | }];
52 | }
53 |
54 |
55 |
56 |
57 |
58 | @end
59 |
60 |
61 | #endif
62 |
63 |
64 |
--------------------------------------------------------------------------------
/Sources/Geometry/Transformers/OCATransformer+CATransform3D.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCATransformer+CATransform3D.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 13.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "OCATransformer+Base.h"
11 |
12 |
13 |
14 |
15 |
16 | @interface OCATransformer (CATransform3D)
17 |
18 |
19 |
20 | #pragma mark Creating 3D Transforms
21 |
22 | + (OCATransformer *)transform3DFromScaleWithZ:(CGFloat)zScale;
23 | + (OCATransformer *)transform3DFromXRotation;
24 | + (OCATransformer *)transform3DFromYRotation;
25 | + (OCATransformer *)transform3DFromZRotation;
26 | + (OCATransformer *)transform3DFromTranslationWithZ:(CGFloat)zTranslation;
27 | + (OCATransformer *)transform3DFromAffineTransform;
28 |
29 |
30 | #pragma mark Modifying 3D Transforms
31 |
32 | + (OCATransformer *)modifyTransform3D:(CATransform3D(^)(CATransform3D t))block;
33 | + (OCATransformer *)concatTransform3D:(CATransform3D)otherTransform3D;
34 |
35 |
36 | #pragma mark Disposing 3D Transforms
37 |
38 | + (OCATransformer *)affineTransformFromTransform3D;
39 |
40 |
41 |
42 | @end
43 |
44 |
45 |
--------------------------------------------------------------------------------
/Sources/Geometry/Transformers/OCATransformer+CGAffineTransform.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCATransformer+CGAffineTransform.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 13.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "OCATransformer+Base.h"
11 |
12 |
13 |
14 |
15 |
16 | @interface OCATransformer (CGAffineTransform)
17 |
18 |
19 |
20 | #pragma mark Creating Affine Transforms
21 |
22 | + (OCATransformer *)affineTransformFromScale;
23 | + (OCATransformer *)affineTransformFromScales;
24 | + (OCATransformer *)affineTransformFromRotation;
25 | + (OCATransformer *)affineTransformFromTranslation;
26 | #if OCA_iOS
27 | + (OCATransformer *)affineTransformFromString;
28 | #endif
29 |
30 |
31 | #pragma mark Modifying Affine Transforms
32 |
33 | + (OCATransformer *)modifyAffineTransform:(CGAffineTransform(^)(CGAffineTransform t))block;
34 | + (OCATransformer *)modifyAffineTransform:(CGAffineTransform(^)(CGAffineTransform t))block reverse:(CGAffineTransform(^)(CGAffineTransform t))reverseBlock;
35 | + (OCATransformer *)concatAffineTransform:(CGAffineTransform)otherAffineTransform;
36 | + (OCATransformer *)affineTransformScale:(CGSize)scale;
37 | + (OCATransformer *)affineTransformRotate:(CGFloat)rotation;
38 | + (OCATransformer *)affineTransformTranslate:(CGPoint)translation;
39 | + (OCATransformer *)invertAffineTransform;
40 |
41 |
42 |
43 | @end
44 |
45 |
46 |
--------------------------------------------------------------------------------
/Sources/Geometry/Transformers/OCATransformer+CGPoint.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCATransformer+CGPoint.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 13.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 | #import "OCATransformer+Base.h"
12 |
13 |
14 |
15 |
16 |
17 | @interface OCATransformer (CGPoint)
18 |
19 |
20 |
21 |
22 |
23 | #pragma mark Creating Points
24 |
25 | + (OCATransformer *)pointFromString;
26 | + (OCATransformer *)makePoint;
27 | + (OCATransformer *)makePointWithX:(CGFloat)x;
28 | + (OCATransformer *)makePointWithY:(CGFloat)y;
29 |
30 |
31 | #pragma mark Modifying Points
32 |
33 | + (OCATransformer *)modifyPoint:(CGPoint(^)(CGPoint point))block;
34 | + (OCATransformer *)modifyPoint:(CGPoint(^)(CGPoint point))block reverse:(CGPoint(^)(CGPoint point))reverseBlock;
35 | + (OCATransformer *)addPoint:(CGPoint)otherPoint;
36 | + (OCATransformer *)subtractPoint:(CGPoint)otherPoint;
37 | + (OCATransformer *)multiplyPointBy:(CGFloat)multiplier;
38 | + (OCATransformer *)transformPoint:(CGAffineTransform)affineTransform;
39 | + (OCATransformer *)roundPointTo:(CGFloat)scale;
40 | + (OCATransformer *)floorPointTo:(CGFloat)scale;
41 | + (OCATransformer *)ceilPointTo:(CGFloat)scale;
42 | + (OCATransformer *)normalizePoint;
43 |
44 |
45 | #pragma mark Disposing Points
46 |
47 | + (OCATransformer *)stringFromPoint;
48 | + (OCATransformer *)distanceToPoint:(CGPoint)otherPoint;
49 | + (OCATransformer *)pointMagnitude;
50 | + (OCATransformer *)pointAngle;
51 |
52 |
53 |
54 |
55 |
56 | @end
57 |
58 |
59 |
--------------------------------------------------------------------------------
/Sources/Geometry/Transformers/OCATransformer+CGRect.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCATransformer+CGRect.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 13.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 | #import "OCATransformer+Base.h"
12 |
13 | #if OCA_iOS
14 | #import
15 | #endif
16 |
17 |
18 |
19 |
20 |
21 | @interface OCATransformer (CGRect)
22 |
23 |
24 |
25 |
26 |
27 | #pragma mark -
28 | #pragma mark Transformers
29 | #pragma mark -
30 |
31 |
32 | #pragma mark Creating Rectangles
33 |
34 | + (OCATransformer *)rectFromString;
35 | + (OCATransformer *)rectFromSizeWith:(CGPoint)origin;
36 | + (OCATransformer *)rectFromPointWith:(CGSize)size;
37 |
38 |
39 | #pragma mark Modifying Rectangles
40 |
41 | + (OCATransformer *)modifyRect:(CGRect(^)(CGRect rect))block;
42 | + (OCATransformer *)modifyRect:(CGRect(^)(CGRect rect))block reverse:(CGRect(^)(CGRect rect))reverseBlock;
43 | #if OCA_iOS
44 | + (OCATransformer *)insetRect:(UIEdgeInsets)insets;
45 | #endif
46 | + (OCATransformer *)transformRect:(CGAffineTransform)affineTransform;
47 | + (OCATransformer *)roundRectTo:(CGFloat)scale;
48 | + (OCATransformer *)floorRectTo:(CGFloat)scale;
49 | + (OCATransformer *)ceilRectTo:(CGFloat)scale;
50 | + (OCATransformer *)unionWith:(CGRect)otherRect;
51 | + (OCATransformer *)intersectionWith:(CGRect)otherRect;
52 | + (OCATransformer *)standardizeRect;
53 |
54 |
55 | #pragma mark Disposing Rectangles
56 |
57 | + (OCATransformer *)stringFromRect;
58 | + (OCATransformer *)rectRelativePoint:(CGPoint)relativePoint;
59 | + (OCATransformer *)rectCenter;
60 | + (OCATransformer *)rectEdge:(CGRectEdge)edge;
61 |
62 |
63 |
64 |
65 |
66 | @end
67 |
68 |
69 |
--------------------------------------------------------------------------------
/Sources/Geometry/Transformers/OCATransformer+CGSize.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCATransformer+CGSize.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 13.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 | #import "OCATransformer+Base.h"
12 |
13 |
14 |
15 |
16 |
17 | @interface OCATransformer (CGSize)
18 |
19 |
20 |
21 |
22 |
23 | #pragma mark Creating Sizes
24 |
25 | + (OCATransformer *)sizeFromString;
26 | + (OCATransformer *)makeSize;
27 | + (OCATransformer *)makeSizeWithWidth:(CGFloat)width;
28 | + (OCATransformer *)makeSizeWithHeight:(CGFloat)height;
29 |
30 |
31 | #pragma mark Modifying Sizes
32 |
33 | + (OCATransformer *)modifySize:(CGSize(^)(CGSize size))block;
34 | + (OCATransformer *)extendSizeBy:(CGSize)otherSize;
35 | + (OCATransformer *)shrinkSizeBy:(CGSize)otherSize;
36 | + (OCATransformer *)multiplySizeBy:(CGFloat)multiplier;
37 | + (OCATransformer *)transformSize:(CGAffineTransform)affineTransform;
38 | + (OCATransformer *)roundSizeTo:(CGFloat)scale;
39 | + (OCATransformer *)floorSizeTo:(CGFloat)scale;
40 | + (OCATransformer *)ceilSizeTo:(CGFloat)scale;
41 | + (OCATransformer *)standardizeSize;
42 |
43 |
44 | #pragma mark Disposing Sizes
45 |
46 | + (OCATransformer *)stringFromSize;
47 | + (OCATransformer *)sizeArea;
48 | + (OCATransformer *)sizeRatio;
49 |
50 |
51 |
52 |
53 |
54 | @end
55 |
56 |
57 |
--------------------------------------------------------------------------------
/Sources/Geometry/Transformers/OCATransformer+UIEdgeInsets.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCATransformer+UIEdgeInsets.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 13.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 |
10 | #import "OCATransformer+Base.h"
11 |
12 |
13 | #if OCA_iOS
14 |
15 | #import
16 |
17 |
18 |
19 |
20 |
21 |
22 | @interface OCATransformer (UIEdgeInsets)
23 |
24 |
25 |
26 | #pragma mark Creating Edge Insets
27 |
28 | + (OCATransformer *)edgeInsetsFromEdges:(UIRectEdge)edges;
29 | + (OCATransformer *)edgeInsetsFromString;
30 |
31 |
32 | #pragma mark Modifying Edge Insets
33 |
34 | + (OCATransformer *)modifyEdgeInsets:(UIEdgeInsets(^)(UIEdgeInsets insets))block;
35 | + (OCATransformer *)modifyEdgeInsets:(UIEdgeInsets(^)(UIEdgeInsets insets))block reverse:(UIEdgeInsets(^)(UIEdgeInsets insets))reverseBlock;
36 | + (OCATransformer *)addEdgeInsets:(UIEdgeInsets)otherInsets;
37 | + (OCATransformer *)subtractEdgeInsets:(UIEdgeInsets)otherInsets;
38 | + (OCATransformer *)multiplyEdgeInsets:(CGFloat)multiplier;
39 | + (OCATransformer *)roundEdgeInsetsTo:(CGFloat)scale;
40 | + (OCATransformer *)ceilEdgeInsetsTo:(CGFloat)scale;
41 | + (OCATransformer *)floorEdgeInsetsTo:(CGFloat)scale;
42 |
43 |
44 | #pragma mark Disposing Edge Insets
45 |
46 | + (OCATransformer *)stringFromEdgeInsets;
47 | + (OCATransformer *)edgeInsetsGetHorizontal;
48 | + (OCATransformer *)edgeInsetsGetVertical;
49 |
50 |
51 |
52 | @end
53 |
54 | #endif // OCA_iOS
55 |
56 |
57 |
--------------------------------------------------------------------------------
/Sources/ObjectiveChain.h:
--------------------------------------------------------------------------------
1 | //
2 | // ObjectiveChain.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 30.12.13.
6 | // Copyright © 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 |
10 | #import "OCAFoundation.h"
11 | #import "OCAGeometry.h"
12 | #if OCA_iOS
13 | #import "OCAUIKit.h"
14 | #endif
15 |
16 |
17 |
--------------------------------------------------------------------------------
/Sources/README.md:
--------------------------------------------------------------------------------
1 | **Objective-Chain** is made up of *Foundation* and additional libraries that are built on top of it:
2 |
3 | ## [Foundation](./Foundation)
4 | - Defines abstract ***Producer*** and ***Consumer*** as well as some of their basic concrete subclasses: *Command*, *Bridge*, *Hub*, *Subscriber*.
5 | - Factories for the most essential ***Transformers*** and ***Predicates***.
6 | - Provides ***Accessor*** classes for accessing and modifying key-paths and structure members.
7 | - Implementes ***Property Bridge***, one of the main *Producers / Consumers* which uses KVO and KVC.
8 | - Wrapper for GCD queues as a ***Queue*** class, which is used by *Connections*.
9 | - Includes some utility categories and classes that are used in other classes.
10 | - Provides a set of ***Math*** transformers for doing arithmetic, rounding or trigonometry.
11 |
12 | ## [Geometry](./Geometry)
13 | - Provides ***Transformers*** and ***Predicates*** for working with geometric structures like *Point*, *Size*, *Rectangle*, *Affine Transfrom* and *Edge Insets* for iOS targets.
14 |
15 | ## UIKit
16 | *To be implemented…*
17 |
--------------------------------------------------------------------------------
/Sources/UIKit/Consumers/OCAUIKit+UIButton.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCAUIKit+UIButton.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 15.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #import "OCAObject.h"
12 | #import "OCATransformer.h"
13 | #import "OCASubscriber.h"
14 |
15 |
16 |
17 |
18 |
19 | @interface OCAUIKit : OCAObject
20 |
21 |
22 |
23 | #pragma mark UIButton
24 |
25 | + (id)setTitleOfButton:(UIButton *)button forControlState:(UIControlState)state;
26 | + (id)setAttributedTitleOfButton:(UIButton *)button forControlState:(UIControlState)state;
27 | + (id)setTitleColorOfButton:(UIButton *)button forControlState:(UIControlState)state;
28 | + (id)setTitleShadowColorOfButton:(UIButton *)button forControlState:(UIControlState)state;
29 | + (id)setImageOfButton:(UIButton *)button forControlState:(UIControlState)state;
30 | + (id)setBackgroundImageOfButton:(UIButton *)button forControlState:(UIControlState)state;
31 |
32 |
33 |
34 | @end
35 |
36 |
37 |
--------------------------------------------------------------------------------
/Sources/UIKit/Consumers/OCAUIKit+UIButton.m:
--------------------------------------------------------------------------------
1 | //
2 | // OCAUIKit+Base.m
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 15.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAUIKit+UIButton.h"
10 |
11 |
12 |
13 |
14 |
15 | @implementation OCAUIKit
16 |
17 |
18 |
19 |
20 |
21 | #pragma mark UIButton
22 |
23 |
24 | + (id)setTitleOfButton:(UIButton *)button forControlState:(UIControlState)state {
25 | return [OCASubscriber subscribeForClass:[NSString class] handler:^(NSString *input) {
26 | [button setTitle:input forState:state];
27 | }];
28 | }
29 |
30 |
31 | + (id)setAttributedTitleOfButton:(UIButton *)button forControlState:(UIControlState)state {
32 | return [OCASubscriber subscribeForClass:[NSAttributedString class] handler:^(NSAttributedString *input) {
33 | [button setAttributedTitle:input forState:state];
34 | }];
35 | }
36 |
37 |
38 | + (id)setTitleColorOfButton:(UIButton *)button forControlState:(UIControlState)state {
39 | return [OCASubscriber subscribeForClass:[UIColor class] handler:^(UIColor *input) {
40 | [button setTitleColor:input forState:state];
41 | }];
42 | }
43 |
44 |
45 | + (id)setTitleShadowColorOfButton:(UIButton *)button forControlState:(UIControlState)state {
46 | return [OCASubscriber subscribeForClass:[UIColor class] handler:^(UIColor *input) {
47 | [button setTitleShadowColor:input forState:state];
48 | }];
49 | }
50 |
51 |
52 | + (id)setImageOfButton:(UIButton *)button forControlState:(UIControlState)state {
53 | return [OCASubscriber subscribeForClass:[UIImage class] handler:^(UIImage *input) {
54 | [button setImage:input forState:state];
55 | }];
56 | }
57 |
58 |
59 | + (id)setBackgroundImageOfButton:(UIButton *)button forControlState:(UIControlState)state {
60 | return [OCASubscriber subscribeForClass:[UIImage class] handler:^(UIImage *input) {
61 | [button setBackgroundImage:input forState:state];
62 | }];
63 | }
64 |
65 |
66 |
67 |
68 |
69 | @end
70 |
71 |
72 |
--------------------------------------------------------------------------------
/Sources/UIKit/Mediators/OCAContext+UIKit.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCAContext+UIKit.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 15.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #import "OCAContext.h"
12 |
13 |
14 |
15 |
16 |
17 | @interface OCAContext (UIKit)
18 |
19 |
20 |
21 | #pragma mark View Animations
22 |
23 | + (OCAContext *)noAnimations;
24 | + (OCAContext *)animateWithDuration:(NSTimeInterval)duration;
25 | + (OCAContext *)animateWithDelay:(NSTimeInterval)delay duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options;
26 | //TODO: Animate with spring animation
27 | //TODO: Animate with System animation
28 | + (OCAContext *)transitionWithView:(UIView *)view duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options;
29 | + (OCAContext *)crossDissolveView:(UIView *)view duration:(NSTimeInterval)duration;
30 |
31 |
32 |
33 | #pragma mark Core Animation
34 |
35 | + (OCAContext *)disableImplicitAnimations;
36 |
37 |
38 |
39 | @end
40 |
41 |
42 |
--------------------------------------------------------------------------------
/Sources/UIKit/Mediators/OCAContext+UIKit.m:
--------------------------------------------------------------------------------
1 | //
2 | // OCAContext+UIKit.m
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 15.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAContext+UIKit.h"
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | @implementation OCAContext (UIKit)
21 |
22 |
23 |
24 |
25 |
26 | #pragma mark View Animations
27 |
28 |
29 | + (OCAContext *)noAnimations {
30 | return [[self alloc] initWithDefinitionBlock:^(OCAContextExecutionBlock executionBlock) {
31 | [UIView performWithoutAnimation:executionBlock];
32 | }];
33 | }
34 |
35 |
36 | + (OCAContext *)animateWithDuration:(NSTimeInterval)duration {
37 | return [[self alloc] initWithDefinitionBlock:^(OCAContextExecutionBlock executionBlock) {
38 | [UIView animateWithDuration:duration animations:executionBlock];
39 | }];
40 | }
41 |
42 |
43 | + (OCAContext *)animateWithDelay:(NSTimeInterval)delay duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options {
44 | return [[self alloc] initWithDefinitionBlock:^(OCAContextExecutionBlock executionBlock) {
45 | [UIView animateWithDuration:duration delay:delay options:options animations:executionBlock completion:nil];
46 | }];
47 | }
48 |
49 |
50 | + (OCAContext *)transitionWithView:(UIView *)view duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options {
51 | return [[self alloc] initWithDefinitionBlock:^(OCAContextExecutionBlock executionBlock) {
52 | [UIView transitionWithView:view duration:duration options:options animations:executionBlock completion:nil];
53 | }];
54 | }
55 |
56 |
57 | + (OCAContext *)crossDissolveView:(UIView *)view duration:(NSTimeInterval)duration {
58 | return [self transitionWithView:view duration:duration options:UIViewAnimationOptionTransitionCrossDissolve];
59 | }
60 |
61 |
62 |
63 |
64 |
65 | #pragma mark Core Animation
66 |
67 |
68 | + (OCAContext *)disableImplicitAnimations {
69 | return [[self alloc] initWithDefinitionBlock:^(OCAContextExecutionBlock executionBlock) {
70 | [CATransaction begin];
71 | [CATransaction setDisableActions:YES];
72 |
73 | executionBlock();
74 |
75 | [CATransaction commit];
76 | }];
77 | }
78 |
79 |
80 |
81 |
82 |
83 | @end
84 |
85 |
86 |
--------------------------------------------------------------------------------
/Sources/UIKit/Mediators/OCAFader.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCAFader.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 16.5.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "OCAMediator.h"
11 |
12 |
13 |
14 |
15 |
16 | @interface OCAFader : OCAMediator
17 |
18 |
19 | - (instancetype)initWithView:(UIView *)view visiblePredicate:(NSPredicate *)predicate duration:(NSTimeInterval)duration;
20 | + (instancetype)fade:(UIView *)view duration:(NSTimeInterval)duration;
21 | + (instancetype)fade:(UIView *)view visible:(NSPredicate *)predicate duration:(NSTimeInterval)duration;
22 |
23 | @property (atomic, readonly, weak) UIView *view;
24 | @property (atomic, readonly, strong) NSPredicate *visiblePredicate;
25 | @property (atomic, readonly, assign) NSTimeInterval duration;
26 |
27 |
28 | @end
29 |
30 |
31 |
--------------------------------------------------------------------------------
/Sources/UIKit/Mediators/OCAFader.m:
--------------------------------------------------------------------------------
1 | //
2 | // OCAFader.m
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 16.5.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAFader.h"
10 | #import "OCAProducer+Subclass.h"
11 | #import "OCADecomposer.h"
12 | #import "OCAPredicate.h"
13 |
14 |
15 |
16 |
17 |
18 | @implementation OCAFader
19 |
20 |
21 |
22 |
23 |
24 | - (instancetype)initWithView:(UIView *)view visiblePredicate:(NSPredicate *)predicate duration:(NSTimeInterval)duration {
25 | self = [super initWithValueClass:nil];
26 | if (self) {
27 | self->_view = view;
28 | [view.decomposer addOwnedObject:self cleanup:nil];
29 |
30 | self->_visiblePredicate = predicate ?: [[OCAPredicate isEmpty] negate];
31 | self->_duration = duration;
32 | }
33 | return self;
34 | }
35 |
36 |
37 | + (instancetype)fade:(UIView *)view duration:(NSTimeInterval)duration {
38 | return [[self alloc] initWithView:view visiblePredicate:nil duration:duration];
39 | }
40 |
41 |
42 | + (instancetype)fade:(UIView *)view visible:(NSPredicate *)predicate duration:(NSTimeInterval)duration {
43 | return [[self alloc] initWithView:view visiblePredicate:predicate duration:duration];
44 | }
45 |
46 |
47 | - (void)consumeValue:(id)value {
48 | BOOL isVisible = [self.visiblePredicate evaluateWithObject:value];
49 |
50 | if (isVisible) [self produceValue:value];
51 |
52 | [UIView animateWithDuration:self.duration
53 | delay:0
54 | options:(UIViewAnimationOptionBeginFromCurrentState)
55 | animations:^{
56 | self.view.alpha = (isVisible? 1 : 0);
57 | }
58 | completion:^(BOOL finished) {
59 | if ( ! isVisible) [self produceValue:value];
60 | }];
61 | }
62 |
63 |
64 | - (void)finishConsumingWithError:(NSError *)error {
65 |
66 | }
67 |
68 |
69 |
70 |
71 |
72 | @end
73 |
74 |
75 |
--------------------------------------------------------------------------------
/Sources/UIKit/OCAUIKit.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCAUIKit.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 15.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 |
10 |
11 | #import "OCATargetter.h"
12 | #import "UIView+tintColor.h"
13 | #import "UITextField+editedText.h"
14 | #import "UIView+Gestures.h"
15 |
16 | #import "OCAContext+UIKit.h"
17 | #import "OCAFader.h"
18 |
19 | #import "OCAUIKit+UIButton.h" //TODO: Replace with Button State Consumer
20 |
21 | #import "OCATransformer+UIColor.h"
22 | #import "OCATransformer+UIImage.h"
23 |
24 | #import "OCAErrorRecoveryAttempter.h"
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Sources/UIKit/Producers/OCATargetter.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCATargetter.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 15.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "OCAProducer.h"
11 |
12 |
13 |
14 |
15 |
16 | @interface OCATargetter : OCAProducer
17 |
18 |
19 |
20 | - (instancetype)initWithOwner:(id)owner;
21 |
22 | + (instancetype)targetForControl:(UIControl *)control events:(UIControlEvents)events;
23 | + (instancetype)targetForBarButtonItem:(UIBarButtonItem *)barButtonItem;
24 | + (instancetype)targetGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer;
25 |
26 | @property (atomic, readonly, weak) id owner;
27 |
28 | @property (atomic, readonly, assign) SEL action;
29 |
30 |
31 |
32 | @end
33 |
34 |
35 |
36 |
37 |
38 | @interface UIControl (OCATargetter)
39 |
40 | - (OCATargetter *)producerForEvent:(UIControlEvents)event;
41 |
42 | @end
43 |
44 |
45 |
46 |
47 |
48 | @interface UIButton (OCATargetter)
49 |
50 | - (OCATargetter *)producer;
51 |
52 | @end
53 |
54 |
55 |
56 |
57 |
58 | @interface UIBarButtonItem (OCATargetter)
59 |
60 | - (OCATargetter *)producer;
61 |
62 | @end
63 |
64 |
65 |
66 |
67 |
68 | @interface UIGestureRecognizer (OCATargetter)
69 |
70 | - (OCATargetter *)producer;
71 | - (OCAProducer *)producerForState:(UIGestureRecognizerState)state;
72 | - (OCAProducer *)callback; // Recognized state.
73 |
74 | @end
75 |
76 |
77 |
78 |
79 |
80 | @interface UITextField (OCATargetter)
81 |
82 | - (OCAProducer *)producerForText;
83 |
84 | - (OCAProducer *)producerForEndEditing;
85 |
86 | @end
87 |
88 |
89 |
90 |
91 |
92 | @interface UISlider (OCATargetter)
93 |
94 | - (OCAProducer *)producerForValue;
95 |
96 | @end
97 |
98 |
99 |
100 |
101 |
102 | @interface UIStepper (OCATargetter)
103 |
104 | - (OCAProducer *)producerForValue;
105 |
106 | @end
107 |
108 |
109 |
--------------------------------------------------------------------------------
/Sources/UIKit/Producers/UITextField+editedText.h:
--------------------------------------------------------------------------------
1 | //
2 | // UITextField+editedText.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 6.5.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 |
12 |
13 |
14 |
15 | @interface UITextField (editedText)
16 |
17 |
18 | @property (nonatomic, readwrite, copy) NSString *editedText;
19 |
20 |
21 | @end
22 |
23 |
--------------------------------------------------------------------------------
/Sources/UIKit/Producers/UITextField+editedText.m:
--------------------------------------------------------------------------------
1 | //
2 | // UITextField+editedText.m
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 6.5.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "OCASwizzling.h"
11 | #import "UITextField+editedText.h"
12 | #import "OCATargetter.h"
13 | #import "OCAProperty.h"
14 | #import "OCAHub.h"
15 |
16 |
17 |
18 |
19 |
20 | @implementation UITextField (editedText)
21 |
22 |
23 |
24 |
25 | + (void)load {
26 | static dispatch_once_t onceToken;
27 | dispatch_once(&onceToken, ^{
28 | [self swizzleSelector:@selector(initWithFrame:)
29 | with:@selector(initWithFrame_oca:)];
30 | });
31 | }
32 |
33 |
34 | //! Method should begin with “init”, so ARC understands the semantics.
35 | - (instancetype)initWithFrame_oca:(CGRect)frame {
36 | self = [self initWithFrame_oca:frame];
37 | if (self) {
38 |
39 | OCAWeakify(self);
40 |
41 | [[OCAHub merge:
42 | [self producerForEvent:UIControlEventEditingChanged],
43 | OCAProperty(self, text, NSString),
44 | nil] subscribe:^{
45 | OCAStrongify(self);
46 |
47 | self.editedText = self.text;
48 | }];
49 | }
50 | return self;
51 | }
52 |
53 |
54 | - (NSString *)editedText {
55 | return objc_getAssociatedObject(self, _cmd);
56 | }
57 |
58 |
59 | - (void)setEditedText:(NSString *)editedText {
60 | objc_setAssociatedObject(self, @selector(editedText), editedText, OBJC_ASSOCIATION_COPY_NONATOMIC);
61 |
62 | if ( ! OCAEqual(editedText, self.text)) {
63 | self.text = editedText;
64 | }
65 | }
66 |
67 |
68 |
69 |
70 |
71 | @end
72 |
73 |
74 |
--------------------------------------------------------------------------------
/Sources/UIKit/Producers/UIView+Gestures.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+Gestures.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 4.12.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "OCATargetter.h"
11 |
12 |
13 |
14 |
15 |
16 | @interface UIView (Gestures)
17 |
18 |
19 | - (OCAProducer *)onTap;
20 | - (OCAProducer *)onDoubleTap;
21 | - (OCAProducer *)onTwinTap;
22 | - (OCAProducer *)callbackForTaps:(NSUInteger)taps touches:(NSUInteger)touches;
23 |
24 | - (OCAProducer *)onSwipeUp;
25 | - (OCAProducer *)onSwipeDown;
26 | - (OCAProducer *)onSwipeLeft;
27 | - (OCAProducer *)onSwipeRight;
28 | - (OCAProducer *)callbackForSwipe:(UISwipeGestureRecognizerDirection)direction touches:(NSUInteger)touches;
29 |
30 | - (OCAProducer *)onHold;
31 | - (OCAProducer *)onTapAndHold;
32 | - (OCAProducer *)onHoldFor:(NSTimeInterval)duration;
33 | - (OCAProducer *)callbackForHold:(NSTimeInterval)duration taps:(NSUInteger)taps touches:(NSUInteger)touches movement:(CGFloat)allowable;
34 |
35 | - (OCAProducer *)onZoomIn;
36 | - (OCAProducer *)onZoomOut;
37 | - (OCAProducer *)onZoomAbove:(CGFloat)scale;
38 | - (OCAProducer *)onZoomBelow:(CGFloat)scale;
39 | - (OCAProducer *)callbackForZoomWithPredicate:(NSPredicate *)predicate;
40 |
41 | - (OCAProducer *)onRotateLeft;
42 | - (OCAProducer *)onRotateRight;
43 | - (OCAProducer *)onRotateLeft:(CGFloat)degrees;
44 | - (OCAProducer *)onRotateRight:(CGFloat)degrees;
45 | - (OCAProducer *)callbackForRotationWithPredicate:(NSPredicate *)predicate;
46 |
47 |
48 | @end
49 |
50 |
51 |
--------------------------------------------------------------------------------
/Sources/UIKit/Producers/UIView+tintColor.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+tintColor.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 17.4.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "OCAProducer.h"
11 |
12 |
13 |
14 |
15 | @interface UIView (tintColor)
16 |
17 |
18 | @property (nonatomic, readonly, strong) OCAProducer *tintColorProducer;
19 |
20 |
21 | @end
22 |
23 |
24 |
--------------------------------------------------------------------------------
/Sources/UIKit/Producers/UIView+tintColor.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+tintColor.m
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 17.4.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "UIView+tintColor.h"
11 | #import "OCASwizzling.h"
12 | #import "OCACommand.h"
13 |
14 |
15 |
16 |
17 |
18 | @implementation UIView (tintColor)
19 |
20 |
21 |
22 |
23 |
24 | + (void)load {
25 | static dispatch_once_t onceToken;
26 | dispatch_once(&onceToken, ^{
27 | [self swizzleSelector:@selector(tintColorDidChange)
28 | with:@selector(oca_tintColorDidChange)];
29 | });
30 | }
31 |
32 |
33 | - (void)oca_tintColorDidChange {
34 | [self oca_tintColorDidChange]; // Calling original implementation.
35 |
36 | OCACommand *command = [self oca_tintColorCommandAndCreateIfNone:NO];
37 | [command sendValue:self.tintColor];
38 | }
39 |
40 |
41 | - (OCACommand *)oca_tintColorCommandAndCreateIfNone:(BOOL)create {
42 | OCACommand *command = objc_getAssociatedObject(self, _cmd);
43 |
44 | if ( ! command && create) {
45 | command = [OCACommand commandForClass:[UIColor class]];
46 | [command sendValue:self.tintColor]; // Initial value.
47 | objc_setAssociatedObject(self, _cmd, command, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
48 | }
49 | return command;
50 | }
51 |
52 |
53 | - (OCAProducer *)tintColorProducer {
54 | return [self oca_tintColorCommandAndCreateIfNone:YES];
55 | }
56 |
57 |
58 |
59 |
60 |
61 | @end
62 |
63 |
64 |
--------------------------------------------------------------------------------
/Sources/UIKit/Transformers/OCATransformer+UIColor.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCATransformer+UIColor.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 15.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "OCATransformer+Base.h"
11 |
12 |
13 |
14 |
15 |
16 | @interface OCATransformer (UIColor)
17 |
18 |
19 |
20 | + (OCATransformer *)colorFromCGColor;
21 | + (OCATransformer *)colorGetCGColor;
22 |
23 | + (OCATransformer *)colorWithAlpha:(CGFloat)alpha;
24 |
25 |
26 |
27 | @end
28 |
29 |
30 |
--------------------------------------------------------------------------------
/Sources/UIKit/Transformers/OCATransformer+UIColor.m:
--------------------------------------------------------------------------------
1 | //
2 | // OCATransformer+UIColor.m
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 15.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCATransformer+UIColor.h"
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | @implementation OCATransformer (UIColor)
21 |
22 |
23 |
24 |
25 |
26 | + (OCATransformer *)colorFromCGColor {
27 | return [[OCATransformer colorGetCGColor] reversed];
28 | }
29 |
30 |
31 | + (OCATransformer *)colorGetCGColor {
32 | return [[OCATransformer fromClass:[UIColor class] toClass:nil
33 | transform:^id(UIColor *input) {
34 |
35 | return (id)input.CGColor;
36 |
37 | } reverse:^UIColor *(id input) {
38 |
39 | CGColorRef color = (__bridge CGColorRef)input;
40 | return [UIColor colorWithCGColor:color];
41 | }]
42 | describe:@"CGColor from UIColor"
43 | reverse:@"UIColor from CGColor"];
44 | }
45 |
46 |
47 | + (OCATransformer *)colorWithAlpha:(CGFloat)alpha {
48 | return [[OCATransformer fromClass:[UIColor class] toClass:[UIColor class]
49 | transform:^UIColor *(UIColor *input) {
50 | return [input colorWithAlphaComponent:alpha];
51 |
52 | } reverse:OCATransformationPass]
53 | describe:[NSString stringWithFormat:@"Color with aplha %@", @(alpha)]
54 | reverse:@"pass"];
55 | }
56 |
57 |
58 |
59 |
60 |
61 | @end
62 |
63 |
64 |
--------------------------------------------------------------------------------
/Sources/UIKit/Transformers/OCATransformer+UIImage.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCATransformer+UIImage.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 12.5.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 | #import
12 | #import "OCATransformer+Base.h"
13 |
14 |
15 |
16 |
17 |
18 | @interface OCATransformer (UIImage)
19 |
20 |
21 |
22 | + (OCATransformer *)resizeImageTo:(CGSize)size scale:(CGFloat)scale;
23 | //TODO: +resizeImageTo:mode: with UIViewContentMode
24 |
25 | + (OCATransformer *)clipImageTo:(UIBezierPath *)path;
26 | + (OCATransformer *)clipImageToCircle;
27 |
28 | + (OCATransformer *)setImageRenderingMode:(UIImageRenderingMode)mode;
29 |
30 | + (OCATransformer *)filterImage:(CIFilter *)filter, ... NS_REQUIRES_NIL_TERMINATION;
31 |
32 |
33 |
34 | @end
35 |
36 |
37 |
--------------------------------------------------------------------------------
/Sources/UIKit/Utilities/OCAErrorRecoveryAttempter.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCAErrorRecoveryAttempter.h
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 24.4.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAObject.h"
10 | #import "OCAProducer.h"
11 | #import "OCATransformer.h"
12 |
13 |
14 | //! Inspired by https://github.com/realmacsoftware/RMErrorRecoveryAttempter
15 |
16 |
17 |
18 | @interface OCAErrorRecoveryAttempter : OCAObject
19 |
20 |
21 |
22 | @property (atomic, readwrite, copy) NSString *failureReason;
23 | @property (atomic, readwrite, copy) NSString *recoverySuggestion;
24 |
25 | - (OCAProducer *)addRecoveryOptionWithTitle:(NSString *)title;
26 | - (OCAProducer *)recoveryOptionAtIndex:(NSUInteger)index;
27 |
28 | - (NSString *)recoveryOptionTitles;
29 |
30 | - (NSError *)recoverableError:(NSError *)error;
31 |
32 |
33 |
34 | @end
35 |
36 |
37 |
--------------------------------------------------------------------------------
/Sources/UIKit/Utilities/OCAErrorRecoveryAttempter.m:
--------------------------------------------------------------------------------
1 | //
2 | // OCAErrorRecoveryAttempter.m
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 24.4.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAErrorRecoveryAttempter.h"
10 | #import "OCACommand.h"
11 | @import ObjectiveC.message;
12 |
13 |
14 |
15 |
16 |
17 | @interface OCAErrorRecoveryAttempter ()
18 |
19 | @property (atomic, readonly, strong) NSMutableArray *titles;
20 | @property (atomic, readonly, strong) NSMutableArray *options;
21 |
22 | @end
23 |
24 |
25 |
26 |
27 |
28 | @implementation OCAErrorRecoveryAttempter
29 |
30 |
31 |
32 |
33 |
34 | - (instancetype)init {
35 | self = [super init];
36 | if (self) {
37 | self->_titles = [[NSMutableArray alloc] init];
38 | self->_options = [[NSMutableArray alloc] init];
39 | }
40 | return self;
41 | }
42 |
43 |
44 |
45 |
46 |
47 | - (OCAProducer *)addRecoveryOptionWithTitle:(NSString *)title {
48 | OCACommand *option = [OCACommand commandForClass:[NSError class]];
49 | [self.titles addObject:title];
50 | [self.options addObject:option];
51 | return option;
52 | }
53 |
54 |
55 | - (OCAProducer *)recoveryOptionAtIndex:(NSUInteger)index {
56 | return [self.options objectAtIndex:index];
57 | }
58 |
59 |
60 |
61 |
62 |
63 | - (NSString *)recoveryOptionTitles {
64 | return [self.titles copy];
65 | }
66 |
67 |
68 | - (NSError *)recoverableError:(NSError *)error {
69 | NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithDictionary:error.userInfo];
70 | [userInfo setObject:self forKey:NSRecoveryAttempterErrorKey];
71 | [userInfo setObject:[self recoveryOptionTitles] forKey:NSLocalizedRecoveryOptionsErrorKey];
72 | if (self.failureReason.length) [userInfo setObject:self.failureReason forKey:NSLocalizedFailureReasonErrorKey];
73 | if (self.recoverySuggestion.length) [userInfo setObject:self.recoverySuggestion forKey:NSLocalizedRecoverySuggestionErrorKey];
74 | return [NSError errorWithDomain:error.domain code:error.code userInfo:userInfo];
75 | }
76 |
77 |
78 |
79 |
80 |
81 | - (BOOL)attemptRecoveryFromError:(NSError *)error optionIndex:(NSUInteger)recoveryOptionIndex {
82 | OCACommand *option = [self.options objectAtIndex:recoveryOptionIndex];
83 | [option sendValue:error];
84 |
85 | return YES; // We don't have mechanism to report this.
86 | }
87 |
88 |
89 | - (void)attemptRecoveryFromError:(NSError *)error optionIndex:(NSUInteger)recoveryOptionIndex delegate:(id)delegate didRecoverSelector:(SEL)didRecoverSelector contextInfo:(void *)contextInfo {
90 | OCACommand *option = [self.options objectAtIndex:recoveryOptionIndex];
91 | [option sendValue:error];
92 |
93 | void (*didRecoverMessage)(id, SEL, BOOL, void *) = (typeof(didRecoverMessage))objc_msgSend;
94 | didRecoverMessage(delegate, didRecoverSelector, YES, contextInfo);
95 | // ... don't ask me.
96 | }
97 |
98 |
99 |
100 |
101 |
102 | @end
103 |
104 |
105 |
--------------------------------------------------------------------------------
/Tests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundlePackageType
14 | BNDL
15 | CFBundleShortVersionString
16 | 1.0
17 | CFBundleSignature
18 | ????
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/Tests/OCAFilterTest.m:
--------------------------------------------------------------------------------
1 | //
2 | // OCAFilterTest.m
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 2.2.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAFilter.h"
10 | #import "OCACommand.h"
11 | #import "OCASubscriber.h"
12 | #import "OCAPredicate.h"
13 |
14 |
15 |
16 |
17 |
18 | @interface OCAFilterTest : XCTestCase
19 |
20 |
21 | @property (nonatomic, readwrite, strong) OCACommand *command;
22 | @property (nonatomic, readwrite, strong) OCASubscriber *subscriber;
23 | @property (nonatomic, readwrite, strong) NSMutableArray *received;
24 |
25 |
26 | @end
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 | @implementation OCAFilterTest
38 |
39 |
40 |
41 |
42 | - (void)setUp {
43 | [super setUp];
44 |
45 | self.command = [OCACommand commandForClass:[NSString class]];
46 | NSMutableArray *received = [[NSMutableArray alloc] init];
47 | self.received = received;
48 | self.subscriber = [OCASubscriber subscribeForClass:[NSString class] handler:^(NSString *value) {
49 | [received addObject:value];
50 | }];
51 | }
52 |
53 |
54 | - (void)test_simplePredicate {
55 | [[self.command
56 | filterValues:[OCAPredicate beginsWith:@"A"]]
57 | connectTo:self.subscriber];
58 |
59 | [self.command sendValues:@[ @"Hello", @"Aloha", @"Hi", @"Ahoy" ]];
60 |
61 | NSArray *expected = @[ @"Aloha", @"Ahoy" ];
62 | XCTAssertEqualObjects(self.received, expected);
63 | }
64 |
65 |
66 | - (void)test_skipFirst {
67 | [[self.command
68 | skipFirst:2]
69 | connectTo:self.subscriber];
70 |
71 | [self.command sendValues:@[ @"Hello", @"Aloha", @"Hi", @"Ahoy" ]];
72 |
73 | NSArray *expected = @[ @"Hi", @"Ahoy" ];
74 | XCTAssertEqualObjects(self.received, expected);
75 | }
76 |
77 |
78 | - (void)test_skipEqual {
79 | [[self.command
80 | skipEqual]
81 | connectTo:self.subscriber];
82 |
83 | [self.command sendValues:@[ @"Hello", @"Hello", @"Hi", @"Hello", @"Hi", @"Hi" ]];
84 |
85 | NSArray *expected = @[ @"Hello", @"Hi", @"Hello", @"Hi" ];
86 | XCTAssertEqualObjects(self.received, expected);
87 | }
88 |
89 |
90 |
91 |
92 | @end
93 |
94 |
95 |
--------------------------------------------------------------------------------
/Tests/OCAHubTest.m:
--------------------------------------------------------------------------------
1 | //
2 | // OCAHubTest.m
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 1.2.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAHub.h"
10 | #import "OCACommand.h"
11 | #import "OCASubscriber.h"
12 | #import "OCAVariadic.h"
13 |
14 |
15 |
16 |
17 |
18 | @interface OCAHubTest : XCTestCase
19 |
20 | @property (nonatomic, readwrite, strong) OCACommand *commandA;
21 | @property (nonatomic, readwrite, strong) OCACommand *commandB;
22 | @property (nonatomic, readwrite, strong) OCACommand *commandC;
23 | @property (nonatomic, readwrite, strong) NSArray *commands;
24 |
25 | @end
26 |
27 |
28 |
29 |
30 |
31 | @implementation OCAHubTest
32 |
33 |
34 |
35 |
36 |
37 | - (void)setUp {
38 | [super setUp];
39 |
40 | self.commandA = [OCACommand commandForClass:[NSString class]];
41 | self.commandB = [OCACommand commandForClass:[NSString class]];
42 | self.commandC = [OCACommand commandForClass:[NSString class]];
43 | self.commands = @[ self.commandA, self.commandB, self.commandC ];
44 | }
45 |
46 |
47 | - (void)test_merge {
48 | OCAHub *hubMerge = [OCAHub merge:OCAVariadic(self.commands)];
49 | XCTAssertEqualObjects(hubMerge.valueClass, [NSString class], @"Merging hub should know class.");
50 |
51 | NSMutableArray *received = [NSMutableArray array];
52 | [hubMerge subscribeForClass:[NSString class] handler:^(id value) {
53 | [received addObject:value];
54 | }];
55 |
56 | [self.commandA sendValue:@"A"];
57 | [self.commandB sendValue:@"B"];
58 | [self.commandC sendValue:@"C"];
59 |
60 | NSArray *expected = @[ @"A", @"B", @"C" ];
61 | XCTAssertEqualObjects(received, expected);
62 | }
63 |
64 |
65 | - (void)test_combine {
66 | OCAHub *hubCombine = [OCAHub combine:OCAVariadic(self.commands)];
67 | XCTAssertEqualObjects(hubCombine.valueClass, [NSArray class], @"Combining hub must produce arrays.");
68 |
69 | NSMutableArray *received = [NSMutableArray array];
70 | [hubCombine subscribeForClass:[NSArray class] handler:^(id value) {
71 | [received addObject:value];
72 | }];
73 |
74 | [self.commandA sendValue:@"A"];
75 | [self.commandB sendValue:@"B"];
76 | [self.commandC sendValue:@"C"];
77 |
78 | NSArray *expected = @[ @[ @"A", NSNull.null, NSNull.null ],
79 | @[ @"A", @"B", NSNull.null ],
80 | @[ @"A", @"B", @"C" ] ];
81 | XCTAssertEqualObjects(received, expected);
82 | }
83 |
84 |
85 | - (void)test_dependency {
86 | OCAHub *hubDependency = [self.commandA dependOn:self.commandB, self.commandC, nil];
87 | XCTAssertEqualObjects(hubDependency.valueClass, [NSString class], @"Dependency hub should know class.");
88 |
89 | NSMutableArray *received = [NSMutableArray array];
90 | [hubDependency subscribeForClass:[NSString class] handler:^(id value) {
91 | [received addObject:value];
92 | }];
93 |
94 | [self.commandA sendValue:@"A"];
95 | [self.commandB sendValue:@"B"];
96 | [self.commandC sendValue:@"C"];
97 |
98 | NSArray *expected = @[ @"A", @"A", @"A" ];
99 | XCTAssertEqualObjects(received, expected);
100 | }
101 |
102 |
103 | //TODO: Test finishing.
104 |
105 |
106 |
107 |
108 |
109 | @end
110 |
111 |
112 |
--------------------------------------------------------------------------------
/Tests/OCAInterpolatorTest.m:
--------------------------------------------------------------------------------
1 | //
2 | // OCAInterpolatorTest.m
3 | // Objective-Chain
4 | //
5 | // Created by Juraj Homola on 26.2.2014.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAInterpolator.h"
10 | #import "OCAQueue.h"
11 | #import "OCAContext.h"
12 | #import "OCASemaphore.h"
13 |
14 | @interface OCAInterpolatorTest : XCTestCase
15 |
16 | @end
17 |
18 |
19 | @implementation OCAInterpolatorTest
20 |
21 |
22 | - (void)test_correctOrder {
23 |
24 | NSMutableArray *array = [[NSMutableArray alloc] init];
25 |
26 | OCASemaphore *semaphore = [[OCASemaphore alloc] initWithValue:0];
27 | [[OCAQueue background] performBlockAndWait:^{
28 |
29 | [[OCAInterpolator interpolatorWithDuration:1 frequency:10] subscribeForClass:[NSNumber class] handler:^(NSNumber *value) {
30 | [array addObject:value];
31 | } finish:^(NSError *error) {
32 | [semaphore signal];
33 | }];
34 | }];
35 |
36 | BOOL signaled = [semaphore waitFor:2];
37 | XCTAssertTrue(signaled);
38 | NSArray *sortedArray = [array sortedArrayUsingSelector:@selector(compare:)];
39 | XCTAssertTrue(array.count == 11);
40 | XCTAssertEqualObjects(sortedArray, array);
41 | }
42 |
43 |
44 | - (void)test_durationZero {
45 |
46 | NSMutableArray *array = [[NSMutableArray alloc] init];
47 |
48 | OCASemaphore *semaphore = [[OCASemaphore alloc] initWithValue:0];
49 | [[OCAQueue background] performBlockAndWait:^{
50 |
51 | [[OCAInterpolator interpolatorWithDuration:0 frequency:100] subscribeForClass:[NSNumber class] handler:^(NSNumber *value) {
52 | [array addObject:value];
53 | } finish:^(NSError *error) {
54 | [semaphore signal];
55 | }];
56 | }];
57 |
58 | BOOL signaled = [semaphore waitFor:3];
59 | XCTAssertTrue(signaled);
60 | XCTAssertTrue(array.count == 1);
61 |
62 | NSArray *expected = @[ @1 ];
63 | XCTAssertEqualObjects(array, expected);
64 | }
65 |
66 |
67 | - (void)test_frequencyZero {
68 | NSMutableArray *array = [[NSMutableArray alloc] init];
69 |
70 | OCASemaphore *semaphore = [[OCASemaphore alloc] initWithValue:0];
71 | [[OCAQueue background] performBlockAndWait:^{
72 |
73 | [[OCAInterpolator interpolatorWithDuration:2 frequency:0] subscribeForClass:[NSNumber class] handler:^(NSNumber *value) {
74 | [array addObject:value];
75 | } finish:^(NSError *error) {
76 | [semaphore signal];
77 | }];
78 | }];
79 |
80 | BOOL signaled = [semaphore waitFor:3];
81 | XCTAssertTrue(signaled);
82 | XCTAssertTrue(array.count == 2);
83 |
84 | NSArray *expected = @[ @0, @1 ];
85 | XCTAssertEqualObjects(array, expected);
86 | }
87 |
88 |
89 | - (void)test_correctOrderCustom {
90 | NSMutableArray *array = [[NSMutableArray alloc] init];
91 |
92 | OCASemaphore *semaphore = [[OCASemaphore alloc] initWithValue:0];
93 | [[OCAQueue background] performBlockAndWait:^{
94 |
95 | [[OCAInterpolator interpolatorWithDuration:1 frequency:3 fromValue:3.2 toValue:-4.5]
96 | subscribeForClass:[NSNumber class]
97 | handler:^(NSNumber *value) {
98 | [array addObject:value];
99 | } finish:^(NSError *error) {
100 | [semaphore signal];
101 | }];
102 | }];
103 |
104 | BOOL signaled = [semaphore waitFor:2];
105 | XCTAssertTrue(signaled);
106 | NSArray *sortedArray = [array sortedArrayUsingDescriptors:@[ [NSSortDescriptor sortDescriptorWithKey:@"self" ascending:NO] ]];
107 | XCTAssertTrue(array.count == 4);
108 | XCTAssertEqualObjects(sortedArray, array);
109 | }
110 |
111 |
112 | @end
113 |
--------------------------------------------------------------------------------
/Tests/OCAInvokerTest.m:
--------------------------------------------------------------------------------
1 | //
2 | // OCAInvokerTest.m
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 3.2.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAInvoker.h"
10 | #import "OCACommand.h"
11 | #import "OCAInvocationCatcher.h"
12 |
13 |
14 |
15 |
16 |
17 | @interface OCAInvokerTest : XCTestCase
18 |
19 |
20 | @property (atomic, readwrite, strong) NSString *value;
21 |
22 |
23 | @end
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | @implementation OCAInvokerTest
35 |
36 |
37 |
38 |
39 |
40 | - (void)setUp {
41 | [super setUp];
42 |
43 | self.value = nil;
44 | }
45 |
46 |
47 | - (void)test_simple {
48 | OCACommand *command = [OCACommand commandForClass:nil];
49 | [command invoke:OCAInvocation(self, setValue:@"ABC")];
50 | [command sendValue:nil];
51 | XCTAssertEqualObjects(self.value, @"ABC");
52 | }
53 |
54 |
55 | - (void)test_placeholders {
56 | OCACommand *command = [OCACommand commandForClass:[NSArray class]];
57 |
58 | @autoreleasepool {
59 | //! Autorelease pool causes the placeholders to be released, so they must be retained by the Invoker.
60 | [command invoke:OCAInvocation( OCAPH(OCAInvokerTest), setValue: OCAPH(NSString) )];
61 | }
62 |
63 | [command sendValue:@[ self, @"ABC" ]];
64 | XCTAssertEqualObjects(self.value, @"ABC");
65 | }
66 |
67 |
68 | - (void)test_nilTarget {
69 | id coolObject = nil;
70 | XCTAssertNoThrow(OCAInvocation(coolObject, test_nilTarget), "Macro should return nil when the target is nil.");
71 | }
72 |
73 |
74 |
75 |
76 |
77 | @end
78 |
79 |
80 |
--------------------------------------------------------------------------------
/Tests/OCAMathTest.m:
--------------------------------------------------------------------------------
1 | //
2 | // OCAMathTest.m
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 2.1.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAMath.h"
10 |
11 |
12 |
13 | @interface OCAMathTest : XCTestCase
14 |
15 | @end
16 |
17 |
18 |
19 |
20 |
21 | @implementation OCAMathTest
22 |
23 |
24 |
25 |
26 |
27 | - (void)test_generic {
28 | OCATransformer *t = [OCAMath transform:^OCAReal(OCAReal x) {
29 | return (x * 4 - 5) / 3;
30 | } reverse:^OCAReal(OCAReal x) {
31 | return (x * 3 + 5) / 4;
32 | }];
33 |
34 | XCTAssertEqualObjects([t transformedValue:@8], @9);
35 | XCTAssertEqualObjects([t reverseTransformedValue:@9], @8);
36 | }
37 |
38 |
39 | - (void)test_function {
40 | OCATransformer *cosine = [OCAMath function:&cos reverse:&acos];
41 | XCTAssertEqualObjects([cosine transformedValue:@0], @1);
42 | XCTAssertEqualObjects([cosine reverseTransformedValue:@1], @0);
43 | }
44 |
45 |
46 | - (void)test_basicOperations {
47 | OCATransformer *t = [OCATransformer sequence:@[
48 | [OCAMath add:3],
49 | [OCAMath multiplyBy:4],
50 | [OCAMath divideBy:2],
51 | [OCAMath subtract:5],
52 | ]];
53 | XCTAssertEqualObjects([t transformedValue:@8], @17);
54 | XCTAssertEqualObjects([t reverseTransformedValue:@17], @8);
55 | }
56 |
57 |
58 | - (void)test_advancedOperations {
59 | OCATransformer *t = [OCATransformer sequence:@[
60 | [OCAMath powerBy:4],
61 | [OCAMath rootOf:2],
62 | [OCAMath logarithmWithBase:10],
63 | ]];
64 | XCTAssertEqualObjects([t transformedValue:@10], @2);
65 | XCTAssertEqualObjects([t reverseTransformedValue:@2], @10);
66 | }
67 |
68 |
69 | - (void)test_trigonometry {
70 | OCATransformer *t = [OCATransformer sequence:@[
71 | [OCAMath toRadians],
72 | [OCAMath sine],
73 | [OCAMath powerBy:2],
74 | ]];
75 | const OCAReal accuracy = 1e-14; // May need increase for more lossy calculations.
76 | XCTAssertEqualWithAccuracy([[t transformedValue:@45] doubleValue], 0.5, accuracy);
77 | XCTAssertEqualWithAccuracy([[t reverseTransformedValue:@0.5] doubleValue], 45, accuracy);
78 | }
79 |
80 |
81 |
82 |
83 |
84 | @end
85 |
86 |
87 |
--------------------------------------------------------------------------------
/Tests/OCAObjectTest.m:
--------------------------------------------------------------------------------
1 | //
2 | // OCAObjectTest.m
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 30.12.13.
6 | // Copyright © 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAObject.h"
10 | #import "ObjectiveChain.h"
11 |
12 |
13 |
14 | @interface OCAObjectTest : XCTestCase
15 |
16 |
17 | @property (nonatomic, readwrite, strong) id lazyProperty;
18 |
19 |
20 | @end
21 |
22 |
23 |
24 |
25 |
26 | @implementation OCAObjectTest
27 |
28 |
29 |
30 |
31 |
32 | - (void)setUp {
33 | [super setUp];
34 | }
35 |
36 |
37 | - (void)tearDown{
38 | [super tearDown];
39 | }
40 |
41 |
42 |
43 |
44 |
45 | #pragma mark OCAssert
46 |
47 |
48 | - (void)test_OCAAssert_executeAppendedCode {
49 | #if defined(NS_BLOCK_ASSERTIONS)
50 | BOOL condition = NO;
51 | BOOL executed = NO;
52 |
53 | OCAAssert(condition, @"Condition is not met.") executed = YES;
54 |
55 | XCTAssertTrue(executed, @"Didn't execute appended code.");
56 | #else
57 | XCTFail(@"Foundation assertions are enabled.");
58 | #endif
59 |
60 | }
61 |
62 |
63 |
64 | - (void)test_validateClass_nilAlwaysPasses {
65 | id object = nil;
66 | XCTAssertTrue([OCAObject validateObject:&object ofClass:[NSMetadataQueryAttributeValueTuple class]], @"Nil must pass any class validation.");
67 | XCTAssertTrue([OCAObject validateObject:&object ofClass:nil], @"Nil must pass any class validation.");
68 | object = @"test";
69 | XCTAssertTrue([OCAObject validateObject:&object ofClass:[NSString class]]);
70 | XCTAssertTrue([OCAObject validateObject:&object ofClass:nil], @"Anything must pass for Nil class validation.");
71 | }
72 |
73 |
74 | - (void)test_findingCommonClass {
75 | NSArray *classes = @[ NSString.class, NSMutableString.class, NSString.class ];
76 | XCTAssertEqualObjects([OCAObject valueClassForClasses:classes], NSString.class, @"Should be highest of all concrete classes.");
77 | }
78 |
79 |
80 | - (void)test_deallocation {
81 | __block BOOL passed = NO;
82 | NSBlockOperation *something = [[NSBlockOperation alloc] init];
83 |
84 | [something.decomposer addOwnedObject:self cleanup:^(__unsafe_unretained NSBlockOperation *owner){
85 | [owner.decomposer removeOwnedObject:self]; // This line should not crash.
86 |
87 | passed = YES;
88 | }];
89 | something = nil; // Should dealloc.
90 |
91 | XCTAssertTrue(passed, @"Block associated with decomposer should be invoked when owner is deallocated.");
92 | }
93 |
94 |
95 |
96 |
97 |
98 | @end
99 |
100 |
101 |
--------------------------------------------------------------------------------
/Tests/OCASwitchTest.m:
--------------------------------------------------------------------------------
1 | //
2 | // OCASwitchTest.m
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 4.2.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCASwitch.h"
10 | #import "OCACommand.h"
11 | #import "OCASubscriber.h"
12 | #import "OCAPredicate.h"
13 |
14 |
15 |
16 |
17 |
18 | @interface OCASwitchTest : XCTestCase
19 |
20 | @end
21 |
22 |
23 |
24 |
25 |
26 | @implementation OCASwitchTest
27 |
28 |
29 |
30 |
31 |
32 | - (void)test_ {
33 | __block NSNumber *result = nil;
34 | OCACommand *command = [OCACommand commandForClass:[NSString class]];
35 | [command switchIf:[OCAPredicate beginsWith:@"A"]
36 | then:[OCASubscriber subscribe:
37 | ^{
38 | result = @YES;
39 | }]
40 | else:[OCASubscriber subscribe:
41 | ^{
42 | result = @NO;
43 | }]];
44 | [command sendValue:@"Aloha"];
45 | XCTAssertTrue(result.boolValue);
46 |
47 | [command sendValue:@"Hello"];
48 | XCTAssertFalse(result.boolValue);
49 | }
50 |
51 |
52 |
53 |
54 |
55 | @end
56 |
57 |
58 |
--------------------------------------------------------------------------------
/Tests/OCAThrottleTest.m:
--------------------------------------------------------------------------------
1 | //
2 | // OCAThrottleTest.m
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 2.2.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAThrottle.h"
10 | #import "OCACommand.h"
11 | #import "OCASubscriber.h"
12 | #import "OCAQueue.h"
13 | #import "OCASemaphore.h"
14 |
15 |
16 |
17 |
18 |
19 | @interface OCAThrottleTest : XCTestCase
20 |
21 | @end
22 |
23 |
24 |
25 |
26 |
27 | @implementation OCAThrottleTest
28 |
29 |
30 |
31 |
32 | - (void)test_nonContinuousThrottle {
33 | OCACommand *command = [OCACommand commandForClass:[NSNumber class]];
34 |
35 | NSMutableArray *received = [[NSMutableArray alloc] init];
36 | [[command throttle:0.05]
37 | subscribeForClass:[NSNumber class] handler:^(NSNumber *value) {
38 | @synchronized(received) {
39 | [received addObject:value];
40 | }
41 | }];
42 | OCASemaphore *semaphore = [[OCASemaphore alloc] initWithValue:0];
43 |
44 | [[OCAQueue background] performBlockAndWait:^{
45 | for (NSUInteger index = 0; index <= 100; index++) {
46 | [command sendValue:@(index)];
47 | [NSThread sleepForTimeInterval:0.01];
48 | }
49 | [[OCAQueue background] performAfter:0.1 block:^{
50 | [semaphore signal];
51 | }];
52 | }];
53 |
54 | BOOL signaled = [semaphore waitFor:2];
55 | XCTAssertTrue(signaled, @"Task didn't finish in time.");
56 |
57 | NSArray *expected = @[ @100 ];
58 | XCTAssertEqualObjects(received, expected, @"Should receive only last value.");
59 | }
60 |
61 |
62 | - (void)test_continuousThrottle {
63 | OCACommand *command = [OCACommand commandForClass:[NSNumber class]];
64 |
65 | NSMutableArray *received = [[NSMutableArray alloc] init];
66 | [[command throttleContinuous:0.1]
67 | subscribeForClass:[NSNumber class] handler:^(NSNumber *value) {
68 | @synchronized(received) {
69 | [received addObject:value];
70 | }
71 | }];
72 | OCASemaphore *semaphore = [[OCASemaphore alloc] initWithValue:0];
73 |
74 | [[OCAQueue background] performBlockAndWait:^{
75 | for (NSUInteger index = 0; index <= 100; index++) {
76 | [command sendValue:@(index)];
77 | [NSThread sleepForTimeInterval:0.01 + 0.0001]; // Give him some more time to have exactly 10th values.
78 | }
79 | [[OCAQueue background] performAfter:0.1 block:^{
80 | [semaphore signal];
81 | }];
82 | }];
83 |
84 | BOOL signaled = [semaphore waitFor:2];
85 | XCTAssertTrue(signaled, @"Task didn't finish in time.");
86 |
87 | NSArray *expected = @[ @0, @10, @20, @30, @40, @50, @60, @70, @80, @90, @100 ];
88 | XCTAssertEqualObjects(received, expected, @"Should receive a value every 0.1s, so every 10th.");
89 | }
90 |
91 |
92 |
93 |
94 | @end
95 |
96 |
97 |
--------------------------------------------------------------------------------
/Tests/OCAVariadicTest.m:
--------------------------------------------------------------------------------
1 | //
2 | // OCAVariadicTest.m
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 1.2.14.
6 | // Copyright (c) 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import "OCAVariadic.h"
10 |
11 |
12 |
13 |
14 | @interface OCAVariadicTest : XCTestCase
15 |
16 | @end
17 |
18 |
19 |
20 |
21 |
22 | @implementation OCAVariadicTest
23 |
24 |
25 |
26 |
27 |
28 | - (void)test_stringFormatting {
29 | NSString *result = [self format:@"A %@ %@", @"B", @"C"];
30 | XCTAssertEqualObjects(result, @"A B C");
31 | }
32 |
33 |
34 | - (NSString *)format:(NSString *)format, ... NS_FORMAT_ARGUMENT(1) {
35 | return OCAStringFromFormat(format);
36 | }
37 |
38 |
39 |
40 |
41 |
42 | - (void)test_variadic_simple {
43 | NSArray *result = [self variadic:@"A", @"B", nil];
44 | NSArray *expected = @[ @"A", @"B" ];
45 | XCTAssertEqualObjects(result, expected);
46 | }
47 |
48 |
49 | - (void)test_variadic_array {
50 | NSArray *expected = @[ @"A", @"B" ];
51 | NSArray *result = [self variadic:OCAVariadic(expected)];
52 | XCTAssertEqualObjects(result, expected);
53 | }
54 |
55 |
56 | - (void)test_variadic_mixed {
57 | NSArray *tail = @[ @"C", @"D" ];
58 | NSArray *result = [self variadic:@"A", @"B", OCAVariadic(tail)];
59 | NSArray *expected = @[ @"A", @"B", @"C", @"D" ];
60 | XCTAssertEqualObjects(result, expected);
61 | }
62 |
63 |
64 | - (NSArray *)variadic:(NSString *)string, ... NS_REQUIRES_NIL_TERMINATION {
65 | return OCAArrayFromVariadicArguments(string);
66 | }
67 |
68 |
69 |
70 |
71 |
72 | @end
73 |
74 |
75 |
--------------------------------------------------------------------------------
/Tests/Prefix.pch:
--------------------------------------------------------------------------------
1 | //
2 | // Prefix.pch
3 | // Objective-Chain
4 | //
5 | // Created by Martin Kiss on 30.12.13.
6 | // Copyright 2014 Martin Kiss. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
--------------------------------------------------------------------------------