- Fix
This commit is contained in:
parent
5ffa592404
commit
2bc7881ba0
@ -1,14 +1,17 @@
|
||||
PODS:
|
||||
- Expecta (1.0.5)
|
||||
- Expecta+Snapshots (2.0.0):
|
||||
- Expecta+Snapshots (3.0.0):
|
||||
- Expecta (~> 1.0)
|
||||
- FBSnapshotTestCase/Core (~> 2.0.3)
|
||||
- FBSnapshotTestCase (2.0.7):
|
||||
- FBSnapshotTestCase/SwiftSupport (= 2.0.7)
|
||||
- FBSnapshotTestCase/Core (2.0.7)
|
||||
- FBSnapshotTestCase/SwiftSupport (2.0.7):
|
||||
- FBSnapshotTestCase/Core (~> 2.0)
|
||||
- Specta (~> 1.0)
|
||||
- FBSnapshotTestCase (2.1.0):
|
||||
- FBSnapshotTestCase/SwiftSupport (= 2.1.0)
|
||||
- FBSnapshotTestCase/Core (2.1.0)
|
||||
- FBSnapshotTestCase/SwiftSupport (2.1.0):
|
||||
- FBSnapshotTestCase/Core
|
||||
- PNGradientView (0.1.0)
|
||||
- PNGradientView (0.1.5):
|
||||
- RZDataBinding
|
||||
- RZDataBinding (2.0.3)
|
||||
- Specta (1.0.5)
|
||||
|
||||
DEPENDENCIES:
|
||||
@ -20,15 +23,14 @@ DEPENDENCIES:
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
PNGradientView:
|
||||
:path: "../"
|
||||
:path: ../
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
Expecta: e1c022fcd33910b6be89c291d2775b3fe27a89fe
|
||||
Expecta+Snapshots: 29b38dd695bc72a0ed2bea833937d78df41943ba
|
||||
FBSnapshotTestCase: 7e85180d0d141a0cf472352edda7e80d7eaeb547
|
||||
PNGradientView: 21d127e76f77674eecfa0dc9859751004f485e38
|
||||
Expecta+Snapshots: c343f410c7a6392f3e22e78f94c44b6c0749a516
|
||||
FBSnapshotTestCase: 366ecd378511d7716c79991cd8067d1eed23578d
|
||||
PNGradientView: e8b91f023a3037ba0442f76ddb1724a8c8635c64
|
||||
RZDataBinding: 00d468ebe667f02c2bd5416f87b4b5d826188c4d
|
||||
Specta: ac94d110b865115fe60ff2c6d7281053c6f8e8a2
|
||||
|
||||
PODFILE CHECKSUM: cd7860932a2fb17c979c3a4af42606b114244376
|
||||
|
||||
COCOAPODS: 1.0.0.beta.2
|
||||
COCOAPODS: 0.39.0
|
||||
|
||||
@ -1,11 +1,3 @@
|
||||
//
|
||||
// EXPMatchers+FBSnapshotTest.h
|
||||
// Artsy
|
||||
//
|
||||
// Created by Daniel Doubrovkine on 1/14/14.
|
||||
// Copyright (c) 2014 Artsy Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Expecta/Expecta.h>
|
||||
#import "ExpectaObject+FBSnapshotTest.h"
|
||||
|
||||
|
||||
@ -1,11 +1,3 @@
|
||||
//
|
||||
// EXPMatchers+FBSnapshotTest.h
|
||||
// Artsy
|
||||
//
|
||||
// Created by Daniel Doubrovkine on 1/14/14.
|
||||
// Copyright (c) 2014 Artsy Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#import "EXPMatchers+FBSnapshotTest.h"
|
||||
#import <Expecta/EXPMatcherHelpers.h>
|
||||
#import <FBSnapshotTestCase/FBSnapshotTestController.h>
|
||||
@ -102,11 +94,6 @@ void setGlobalReferenceImageDir(char *reference) {
|
||||
@end
|
||||
|
||||
|
||||
|
||||
// If you're bringing in Speca via CocoaPods
|
||||
// use the test path to get the test's image file URL
|
||||
|
||||
#if __has_include(<Specta/Specta.h>)
|
||||
#import <Specta/Specta.h>
|
||||
#import <Specta/SpectaUtility.h>
|
||||
#import <Specta/SPTExample.h>
|
||||
@ -130,6 +117,11 @@ NSString *sanitizedTestPath(){
|
||||
EXPMatcherImplementationBegin(haveValidSnapshot, (void)){
|
||||
__block NSError *error = nil;
|
||||
|
||||
prerequisite(^BOOL{
|
||||
return actual;
|
||||
});
|
||||
|
||||
|
||||
match(^BOOL{
|
||||
NSString *referenceImageDir = [self _getDefaultReferenceDirectory];
|
||||
NSString *name = sanitizedTestPath();
|
||||
@ -144,6 +136,10 @@ EXPMatcherImplementationBegin(haveValidSnapshot, (void)){
|
||||
});
|
||||
|
||||
failureMessageForTo(^NSString *{
|
||||
if (!actual) {
|
||||
return [EXPExpectFBSnapshotTest combinedError:@"Nil was passed into haveValidSnapshot." test:sanitizedTestPath() error:nil];
|
||||
}
|
||||
|
||||
return [EXPExpectFBSnapshotTest combinedError:@"expected a matching snapshot in" test:sanitizedTestPath() error:error];
|
||||
});
|
||||
|
||||
@ -159,7 +155,7 @@ EXPMatcherImplementationBegin(recordSnapshot, (void)) {
|
||||
BOOL actualIsViewLayerOrViewController = ([actual isKindOfClass:UIView.class] || [actual isKindOfClass:CALayer.class] || [actual isKindOfClass:UIViewController.class]);
|
||||
|
||||
prerequisite(^BOOL{
|
||||
return actualIsViewLayerOrViewController;
|
||||
return actual && actualIsViewLayerOrViewController;
|
||||
});
|
||||
|
||||
match(^BOOL{
|
||||
@ -178,6 +174,10 @@ EXPMatcherImplementationBegin(recordSnapshot, (void)) {
|
||||
});
|
||||
|
||||
failureMessageForTo(^NSString *{
|
||||
if (!actual) {
|
||||
return [EXPExpectFBSnapshotTest combinedError:@"Nil was passed into recordSnapshot." test:sanitizedTestPath() error:nil];
|
||||
}
|
||||
|
||||
if (!actualIsViewLayerOrViewController) {
|
||||
return [EXPExpectFBSnapshotTest combinedError:@"Expected a View, Layer or View Controller." test:sanitizedTestPath() error:nil];
|
||||
}
|
||||
@ -198,54 +198,12 @@ EXPMatcherImplementationBegin(recordSnapshot, (void)) {
|
||||
}
|
||||
EXPMatcherImplementationEnd
|
||||
|
||||
#else
|
||||
|
||||
// If you don't have Speca stub the functions
|
||||
|
||||
EXPMatcherImplementationBegin(haveValidSnapshot, (void)){
|
||||
|
||||
prerequisite(^BOOL{
|
||||
return NO;
|
||||
});
|
||||
|
||||
failureMessageForTo(^NSString *{
|
||||
return @"you need Specta installed via CocoaPods to use haveValidSnapshot, use haveValidSnapshotNamed instead";
|
||||
});
|
||||
|
||||
failureMessageForNotTo(^NSString *{
|
||||
return @"you need Specta installed via CocoaPods to use haveValidSnapshot, use haveValidSnapshotNamed instead";
|
||||
});
|
||||
}
|
||||
EXPMatcherImplementationEnd
|
||||
|
||||
|
||||
EXPMatcherImplementationBegin(recordSnapshot, (void)) {
|
||||
|
||||
prerequisite(^BOOL{
|
||||
return NO;
|
||||
});
|
||||
|
||||
failureMessageForTo(^NSString *{
|
||||
return @"you need Specta installed via CocoaPods to use recordSnapshot, use recordSnapshotNamed instead";
|
||||
});
|
||||
|
||||
failureMessageForNotTo(^NSString *{
|
||||
return @"you need Specta installed via CocoaPods to use recordSnapshot, use recordSnapshotNamed instead";
|
||||
});
|
||||
}
|
||||
EXPMatcherImplementationEnd
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
EXPMatcherImplementationBegin(haveValidSnapshotNamed, (NSString *snapshot)){
|
||||
BOOL snapshotIsNil = (snapshot == nil);
|
||||
__block NSError *error = nil;
|
||||
|
||||
prerequisite(^BOOL{
|
||||
return !(snapshotIsNil);
|
||||
return actual && !(snapshotIsNil);
|
||||
});
|
||||
|
||||
match(^BOOL{
|
||||
@ -260,6 +218,10 @@ EXPMatcherImplementationBegin(haveValidSnapshotNamed, (NSString *snapshot)){
|
||||
});
|
||||
|
||||
failureMessageForTo(^NSString *{
|
||||
if (!actual) {
|
||||
return [EXPExpectFBSnapshotTest combinedError:@"Nil was passed into haveValidSnapshotNamed." test:sanitizedTestPath() error:nil];
|
||||
}
|
||||
|
||||
return [EXPExpectFBSnapshotTest combinedError:@"expected a matching snapshot named" test:snapshot error:error];
|
||||
|
||||
});
|
||||
@ -295,6 +257,9 @@ EXPMatcherImplementationBegin(recordSnapshotNamed, (NSString *snapshot)) {
|
||||
});
|
||||
|
||||
failureMessageForTo(^NSString *{
|
||||
if (!actual) {
|
||||
return [EXPExpectFBSnapshotTest combinedError:@"Nil was passed into recordSnapshotNamed." test:sanitizedTestPath() error:nil];
|
||||
}
|
||||
if (!actualIsViewLayerOrViewController) {
|
||||
return [EXPExpectFBSnapshotTest combinedError:@"Expected a View, Layer or View Controller." test:snapshot error:nil];
|
||||
}
|
||||
|
||||
20
Example/Pods/FBSnapshotTestCase/FBSnapshotTestCase/Categories/UIApplication+StrictKeyWindow.h
generated
Normal file
20
Example/Pods/FBSnapshotTestCase/FBSnapshotTestCase/Categories/UIApplication+StrictKeyWindow.h
generated
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface UIApplication (StrictKeyWindow)
|
||||
|
||||
/**
|
||||
@return The receiver's @c keyWindow. Raises an assertion if @c nil.
|
||||
*/
|
||||
- (UIWindow *)fb_strictKeyWindow;
|
||||
|
||||
@end
|
||||
27
Example/Pods/FBSnapshotTestCase/FBSnapshotTestCase/Categories/UIApplication+StrictKeyWindow.m
generated
Normal file
27
Example/Pods/FBSnapshotTestCase/FBSnapshotTestCase/Categories/UIApplication+StrictKeyWindow.m
generated
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#import <FBSnapshotTestCase/UIApplication+StrictKeyWindow.h>
|
||||
|
||||
@implementation UIApplication (StrictKeyWindow)
|
||||
|
||||
- (UIWindow *)fb_strictKeyWindow
|
||||
{
|
||||
UIWindow *keyWindow = [UIApplication sharedApplication].keyWindow;
|
||||
if (!keyWindow) {
|
||||
[NSException raise:@"FBSnapshotTestCaseNilKeyWindowException"
|
||||
format:@"Snapshot tests must be hosted by an application with a key window. Please ensure your test"
|
||||
" host sets up a key window at launch (either via storyboards or programmatically) and doesn't"
|
||||
" do anything to remove it while snapshot tests are running."];
|
||||
}
|
||||
return keyWindow;
|
||||
}
|
||||
|
||||
@end
|
||||
@ -9,6 +9,7 @@
|
||||
*/
|
||||
|
||||
#import <FBSnapshotTestCase/UIImage+Snapshot.h>
|
||||
#import <FBSnapshotTestCase/UIApplication+StrictKeyWindow.h>
|
||||
|
||||
@implementation UIImage (Snapshot)
|
||||
|
||||
@ -43,11 +44,16 @@
|
||||
NSAssert1(CGRectGetWidth(bounds), @"Zero width for view %@", view);
|
||||
NSAssert1(CGRectGetHeight(bounds), @"Zero height for view %@", view);
|
||||
|
||||
UIWindow *window = view.window;
|
||||
if (window == nil) {
|
||||
window = [[UIWindow alloc] initWithFrame:bounds];
|
||||
// If the input view is already a UIWindow, then just use that. Otherwise wrap in a window.
|
||||
UIWindow *window = [view isKindOfClass:[UIWindow class]] ? (UIWindow *)view : view.window;
|
||||
BOOL removeFromSuperview = NO;
|
||||
if (!window) {
|
||||
window = [[UIApplication sharedApplication] fb_strictKeyWindow];
|
||||
}
|
||||
|
||||
if (!view.window && view != window) {
|
||||
[window addSubview:view];
|
||||
[window makeKeyAndVisible];
|
||||
removeFromSuperview = YES;
|
||||
}
|
||||
|
||||
UIGraphicsBeginImageContextWithOptions(bounds.size, NO, 0);
|
||||
@ -56,6 +62,11 @@
|
||||
|
||||
UIImage *snapshot = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
|
||||
if (removeFromSuperview) {
|
||||
[view removeFromSuperview];
|
||||
}
|
||||
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
*/
|
||||
|
||||
#import <FBSnapshotTestCase/FBSnapshotTestCasePlatform.h>
|
||||
#import <FBSnapshotTestCase/FBSnapshotTestController.h>
|
||||
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
|
||||
@ -48,7 +49,7 @@
|
||||
/**
|
||||
Similar to our much-loved XCTAssert() macros. Use this to perform your test. No need to write an explanation, though.
|
||||
@param layer The layer to snapshot
|
||||
@param identifier An optional identifier, used is there are multiple snapshot tests in a given -test method.
|
||||
@param identifier An optional identifier, used if there are multiple snapshot tests in a given -test method.
|
||||
@param suffixes An NSOrderedSet of strings for the different suffixes
|
||||
@param tolerance The percentage of pixels that can differ and still count as an 'identical' layer
|
||||
*/
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
*/
|
||||
|
||||
#import <FBSnapshotTestCase/FBSnapshotTestCasePlatform.h>
|
||||
#import <FBSnapshotTestCase/UIApplication+StrictKeyWindow.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
BOOL FBSnapshotTestCaseIs64Bit(void)
|
||||
@ -34,7 +35,8 @@ NSOrderedSet *FBSnapshotTestCaseDefaultSuffixes(void)
|
||||
NSString *FBDeviceAgnosticNormalizedFileName(NSString *fileName)
|
||||
{
|
||||
UIDevice *device = [UIDevice currentDevice];
|
||||
CGSize screenSize = [[UIApplication sharedApplication] keyWindow].bounds.size;
|
||||
UIWindow *keyWindow = [[UIApplication sharedApplication] fb_strictKeyWindow];
|
||||
CGSize screenSize = keyWindow.bounds.size;
|
||||
NSString *os = device.systemVersion;
|
||||
|
||||
fileName = [NSString stringWithFormat:@"%@_%@%@_%.0fx%.0f", fileName, device.model, os, screenSize.width, screenSize.height];
|
||||
|
||||
@ -28,6 +28,21 @@ extern NSString *const FBSnapshotTestControllerErrorDomain;
|
||||
*/
|
||||
extern NSString *const FBReferenceImageFilePathKey;
|
||||
|
||||
/**
|
||||
Errors returned by the methods of FBSnapshotTestController sometimes contain this key in the `userInfo` dictionary.
|
||||
*/
|
||||
extern NSString *const FBReferenceImageKey;
|
||||
|
||||
/**
|
||||
Errors returned by the methods of FBSnapshotTestController sometimes contain this key in the `userInfo` dictionary.
|
||||
*/
|
||||
extern NSString *const FBCapturedImageKey;
|
||||
|
||||
/**
|
||||
Errors returned by the methods of FBSnapshotTestController sometimes contain this key in the `userInfo` dictionary.
|
||||
*/
|
||||
extern NSString *const FBDiffedImageKey;
|
||||
|
||||
/**
|
||||
Provides the heavy-lifting for FBSnapshotTestCase. It loads and saves images, along with performing the actual pixel-
|
||||
by-pixel comparison of images.
|
||||
|
||||
@ -18,6 +18,9 @@
|
||||
|
||||
NSString *const FBSnapshotTestControllerErrorDomain = @"FBSnapshotTestControllerErrorDomain";
|
||||
NSString *const FBReferenceImageFilePathKey = @"FBReferenceImageFilePathKey";
|
||||
NSString *const FBReferenceImageKey = @"FBReferenceImageKey";
|
||||
NSString *const FBCapturedImageKey = @"FBCapturedImageKey";
|
||||
NSString *const FBDiffedImageKey = @"FBDiffedImageKey";
|
||||
|
||||
typedef NS_ENUM(NSUInteger, FBTestSnapshotFileNameType) {
|
||||
FBTestSnapshotFileNameTypeReference,
|
||||
@ -126,25 +129,25 @@ typedef NS_ENUM(NSUInteger, FBTestSnapshotFileNameType) {
|
||||
tolerance:(CGFloat)tolerance
|
||||
error:(NSError **)errorPtr
|
||||
{
|
||||
if (CGSizeEqualToSize(referenceImage.size, image.size)) {
|
||||
BOOL imagesEqual = [referenceImage fb_compareWithImage:image tolerance:tolerance];
|
||||
if (NULL != errorPtr) {
|
||||
*errorPtr = [NSError errorWithDomain:FBSnapshotTestControllerErrorDomain
|
||||
code:FBSnapshotTestControllerErrorCodeImagesDifferent
|
||||
userInfo:@{
|
||||
NSLocalizedDescriptionKey: @"Images different",
|
||||
}];
|
||||
}
|
||||
return imagesEqual;
|
||||
BOOL sameImageDimensions = CGSizeEqualToSize(referenceImage.size, image.size);
|
||||
if (sameImageDimensions && [referenceImage fb_compareWithImage:image tolerance:tolerance]) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
if (NULL != errorPtr) {
|
||||
NSString *errorDescription = sameImageDimensions ? @"Images different" : @"Images different sizes";
|
||||
NSString *errorReason = sameImageDimensions ? [NSString stringWithFormat:@"image pixels differed by more than %.2f%% from the reference image", tolerance * 100]
|
||||
: [NSString stringWithFormat:@"referenceImage:%@, image:%@", NSStringFromCGSize(referenceImage.size), NSStringFromCGSize(image.size)];
|
||||
FBSnapshotTestControllerErrorCode errorCode = sameImageDimensions ? FBSnapshotTestControllerErrorCodeImagesDifferent : FBSnapshotTestControllerErrorCodeImagesDifferentSizes;
|
||||
|
||||
*errorPtr = [NSError errorWithDomain:FBSnapshotTestControllerErrorDomain
|
||||
code:FBSnapshotTestControllerErrorCodeImagesDifferentSizes
|
||||
code:errorCode
|
||||
userInfo:@{
|
||||
NSLocalizedDescriptionKey: @"Images different sizes",
|
||||
NSLocalizedFailureReasonErrorKey: [NSString stringWithFormat:@"referenceImage:%@, image:%@",
|
||||
NSStringFromCGSize(referenceImage.size),
|
||||
NSStringFromCGSize(image.size)],
|
||||
NSLocalizedDescriptionKey: errorDescription,
|
||||
NSLocalizedFailureReasonErrorKey: errorReason,
|
||||
FBReferenceImageKey: referenceImage,
|
||||
FBCapturedImageKey: image,
|
||||
FBDiffedImageKey: [referenceImage fb_diffWithImage:image],
|
||||
}];
|
||||
}
|
||||
return NO;
|
||||
@ -279,11 +282,10 @@ typedef NS_ENUM(NSUInteger, FBTestSnapshotFileNameType) {
|
||||
UIImage *snapshot = [self _imageForViewOrLayer:viewOrLayer];
|
||||
BOOL imagesSame = [self compareReferenceImage:referenceImage toImage:snapshot tolerance:tolerance error:errorPtr];
|
||||
if (!imagesSame) {
|
||||
[self saveFailedReferenceImage:referenceImage
|
||||
testImage:snapshot
|
||||
selector:selector
|
||||
identifier:identifier
|
||||
error:errorPtr];
|
||||
NSError *saveError = nil;
|
||||
if ([self saveFailedReferenceImage:referenceImage testImage:snapshot selector:selector identifier:identifier error:&saveError] == NO) {
|
||||
NSLog(@"Error saving test images: %@", saveError);
|
||||
}
|
||||
}
|
||||
return imagesSame;
|
||||
}
|
||||
|
||||
@ -9,15 +9,15 @@
|
||||
*/
|
||||
|
||||
public extension FBSnapshotTestCase {
|
||||
public func FBSnapshotVerifyView(view: UIView, identifier: String = "", suffixes: NSOrderedSet = FBSnapshotTestCaseDefaultSuffixes(), file: String = __FILE__, line: UInt = __LINE__) {
|
||||
FBSnapshotVerifyViewOrLayer(view, identifier: identifier, suffixes: suffixes)
|
||||
public func FBSnapshotVerifyView(view: UIView, identifier: String = "", suffixes: NSOrderedSet = FBSnapshotTestCaseDefaultSuffixes(), tolerance: CGFloat = 0, file: StaticString = #file, line: UInt = #line) {
|
||||
FBSnapshotVerifyViewOrLayer(view, identifier: identifier, suffixes: suffixes, tolerance: tolerance, file: file, line: line)
|
||||
}
|
||||
|
||||
public func FBSnapshotVerifyLayer(layer: CALayer, identifier: String = "", suffixes: NSOrderedSet = FBSnapshotTestCaseDefaultSuffixes(), file: String = __FILE__, line: UInt = __LINE__) {
|
||||
FBSnapshotVerifyViewOrLayer(layer, identifier: identifier, suffixes: suffixes)
|
||||
public func FBSnapshotVerifyLayer(layer: CALayer, identifier: String = "", suffixes: NSOrderedSet = FBSnapshotTestCaseDefaultSuffixes(), tolerance: CGFloat = 0, file: StaticString = #file, line: UInt = #line) {
|
||||
FBSnapshotVerifyViewOrLayer(layer, identifier: identifier, suffixes: suffixes, tolerance: tolerance, file: file, line: line)
|
||||
}
|
||||
|
||||
private func FBSnapshotVerifyViewOrLayer(viewOrLayer: AnyObject, identifier: String = "", suffixes: NSOrderedSet = FBSnapshotTestCaseDefaultSuffixes(), file: String = __FILE__, line: UInt = __LINE__) {
|
||||
private func FBSnapshotVerifyViewOrLayer(viewOrLayer: AnyObject, identifier: String = "", suffixes: NSOrderedSet = FBSnapshotTestCaseDefaultSuffixes(), tolerance: CGFloat = 0, file: StaticString = #file, line: UInt = #line) {
|
||||
let envReferenceImageDirectory = self.getReferenceImageDirectoryWithDefault(FB_REFERENCE_IMAGE_DIR)
|
||||
var error: NSError?
|
||||
var comparisonSuccess = false
|
||||
@ -27,7 +27,7 @@ public extension FBSnapshotTestCase {
|
||||
let referenceImagesDirectory = "\(envReferenceImageDirectory)\(suffix)"
|
||||
if viewOrLayer.isKindOfClass(UIView) {
|
||||
do {
|
||||
try compareSnapshotOfView(viewOrLayer as! UIView, referenceImagesDirectory: referenceImagesDirectory, identifier: identifier, tolerance: 0)
|
||||
try compareSnapshotOfView(viewOrLayer as! UIView, referenceImagesDirectory: referenceImagesDirectory, identifier: identifier, tolerance: tolerance)
|
||||
comparisonSuccess = true
|
||||
} catch let error1 as NSError {
|
||||
error = error1
|
||||
@ -35,7 +35,7 @@ public extension FBSnapshotTestCase {
|
||||
}
|
||||
} else if viewOrLayer.isKindOfClass(CALayer) {
|
||||
do {
|
||||
try compareSnapshotOfLayer(viewOrLayer as! CALayer, referenceImagesDirectory: referenceImagesDirectory, identifier: identifier, tolerance: 0)
|
||||
try compareSnapshotOfLayer(viewOrLayer as! CALayer, referenceImagesDirectory: referenceImagesDirectory, identifier: identifier, tolerance: tolerance)
|
||||
comparisonSuccess = true
|
||||
} catch let error1 as NSError {
|
||||
error = error1
|
||||
@ -58,7 +58,7 @@ public extension FBSnapshotTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
func assert(assertion: Bool, message: String, file: String, line: UInt) {
|
||||
func assert(assertion: Bool, message: String, file: StaticString, line: UInt) {
|
||||
if !assertion {
|
||||
XCTFail(message, file: file, line: line)
|
||||
}
|
||||
|
||||
1
Example/Pods/Headers/Private/Expecta+Snapshots/EXPMatchers+FBSnapshotTest.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Expecta+Snapshots/EXPMatchers+FBSnapshotTest.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Expecta+Snapshots/EXPMatchers+FBSnapshotTest.h
|
||||
1
Example/Pods/Headers/Private/Expecta+Snapshots/ExpectaObject+FBSnapshotTest.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Expecta+Snapshots/ExpectaObject+FBSnapshotTest.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Expecta+Snapshots/ExpectaObject+FBSnapshotTest.h
|
||||
1
Example/Pods/Headers/Private/Expecta/EXPBlockDefinedMatcher.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Expecta/EXPBlockDefinedMatcher.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Expecta/Expecta/EXPBlockDefinedMatcher.h
|
||||
1
Example/Pods/Headers/Private/Expecta/EXPDefines.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Expecta/EXPDefines.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Expecta/Expecta/EXPDefines.h
|
||||
1
Example/Pods/Headers/Private/Expecta/EXPDoubleTuple.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Expecta/EXPDoubleTuple.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Expecta/Expecta/EXPDoubleTuple.h
|
||||
1
Example/Pods/Headers/Private/Expecta/EXPExpect.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Expecta/EXPExpect.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Expecta/Expecta/EXPExpect.h
|
||||
1
Example/Pods/Headers/Private/Expecta/EXPFloatTuple.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Expecta/EXPFloatTuple.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Expecta/Expecta/EXPFloatTuple.h
|
||||
1
Example/Pods/Headers/Private/Expecta/EXPMatcher.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Expecta/EXPMatcher.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Expecta/Expecta/EXPMatcher.h
|
||||
1
Example/Pods/Headers/Private/Expecta/EXPMatcherHelpers.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Expecta/EXPMatcherHelpers.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Expecta/Expecta/Matchers/EXPMatcherHelpers.h
|
||||
1
Example/Pods/Headers/Private/Expecta/EXPMatchers+beCloseTo.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Expecta/EXPMatchers+beCloseTo.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Expecta/Expecta/Matchers/EXPMatchers+beCloseTo.h
|
||||
1
Example/Pods/Headers/Private/Expecta/EXPMatchers+beFalsy.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Expecta/EXPMatchers+beFalsy.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Expecta/Expecta/Matchers/EXPMatchers+beFalsy.h
|
||||
1
Example/Pods/Headers/Private/Expecta/EXPMatchers+beGreaterThan.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Expecta/EXPMatchers+beGreaterThan.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Expecta/Expecta/Matchers/EXPMatchers+beGreaterThan.h
|
||||
1
Example/Pods/Headers/Private/Expecta/EXPMatchers+beGreaterThanOrEqualTo.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Expecta/EXPMatchers+beGreaterThanOrEqualTo.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Expecta/Expecta/Matchers/EXPMatchers+beGreaterThanOrEqualTo.h
|
||||
1
Example/Pods/Headers/Private/Expecta/EXPMatchers+beIdenticalTo.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Expecta/EXPMatchers+beIdenticalTo.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Expecta/Expecta/Matchers/EXPMatchers+beIdenticalTo.h
|
||||
1
Example/Pods/Headers/Private/Expecta/EXPMatchers+beInTheRangeOf.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Expecta/EXPMatchers+beInTheRangeOf.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Expecta/Expecta/Matchers/EXPMatchers+beInTheRangeOf.h
|
||||
1
Example/Pods/Headers/Private/Expecta/EXPMatchers+beInstanceOf.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Expecta/EXPMatchers+beInstanceOf.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Expecta/Expecta/Matchers/EXPMatchers+beInstanceOf.h
|
||||
1
Example/Pods/Headers/Private/Expecta/EXPMatchers+beKindOf.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Expecta/EXPMatchers+beKindOf.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Expecta/Expecta/Matchers/EXPMatchers+beKindOf.h
|
||||
1
Example/Pods/Headers/Private/Expecta/EXPMatchers+beLessThan.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Expecta/EXPMatchers+beLessThan.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Expecta/Expecta/Matchers/EXPMatchers+beLessThan.h
|
||||
1
Example/Pods/Headers/Private/Expecta/EXPMatchers+beLessThanOrEqualTo.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Expecta/EXPMatchers+beLessThanOrEqualTo.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Expecta/Expecta/Matchers/EXPMatchers+beLessThanOrEqualTo.h
|
||||
1
Example/Pods/Headers/Private/Expecta/EXPMatchers+beNil.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Expecta/EXPMatchers+beNil.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Expecta/Expecta/Matchers/EXPMatchers+beNil.h
|
||||
1
Example/Pods/Headers/Private/Expecta/EXPMatchers+beSubclassOf.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Expecta/EXPMatchers+beSubclassOf.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Expecta/Expecta/Matchers/EXPMatchers+beSubclassOf.h
|
||||
1
Example/Pods/Headers/Private/Expecta/EXPMatchers+beSupersetOf.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Expecta/EXPMatchers+beSupersetOf.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Expecta/Expecta/Matchers/EXPMatchers+beSupersetOf.h
|
||||
1
Example/Pods/Headers/Private/Expecta/EXPMatchers+beTruthy.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Expecta/EXPMatchers+beTruthy.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Expecta/Expecta/Matchers/EXPMatchers+beTruthy.h
|
||||
1
Example/Pods/Headers/Private/Expecta/EXPMatchers+beginWith.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Expecta/EXPMatchers+beginWith.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Expecta/Expecta/Matchers/EXPMatchers+beginWith.h
|
||||
1
Example/Pods/Headers/Private/Expecta/EXPMatchers+conformTo.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Expecta/EXPMatchers+conformTo.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Expecta/Expecta/Matchers/EXPMatchers+conformTo.h
|
||||
1
Example/Pods/Headers/Private/Expecta/EXPMatchers+contain.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Expecta/EXPMatchers+contain.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Expecta/Expecta/Matchers/EXPMatchers+contain.h
|
||||
1
Example/Pods/Headers/Private/Expecta/EXPMatchers+endWith.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Expecta/EXPMatchers+endWith.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Expecta/Expecta/Matchers/EXPMatchers+endWith.h
|
||||
1
Example/Pods/Headers/Private/Expecta/EXPMatchers+equal.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Expecta/EXPMatchers+equal.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Expecta/Expecta/Matchers/EXPMatchers+equal.h
|
||||
1
Example/Pods/Headers/Private/Expecta/EXPMatchers+haveCountOf.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Expecta/EXPMatchers+haveCountOf.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Expecta/Expecta/Matchers/EXPMatchers+haveCountOf.h
|
||||
1
Example/Pods/Headers/Private/Expecta/EXPMatchers+match.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Expecta/EXPMatchers+match.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Expecta/Expecta/Matchers/EXPMatchers+match.h
|
||||
1
Example/Pods/Headers/Private/Expecta/EXPMatchers+postNotification.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Expecta/EXPMatchers+postNotification.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Expecta/Expecta/Matchers/EXPMatchers+postNotification.h
|
||||
1
Example/Pods/Headers/Private/Expecta/EXPMatchers+raise.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Expecta/EXPMatchers+raise.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Expecta/Expecta/Matchers/EXPMatchers+raise.h
|
||||
1
Example/Pods/Headers/Private/Expecta/EXPMatchers+raiseWithReason.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Expecta/EXPMatchers+raiseWithReason.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Expecta/Expecta/Matchers/EXPMatchers+raiseWithReason.h
|
||||
1
Example/Pods/Headers/Private/Expecta/EXPMatchers+respondTo.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Expecta/EXPMatchers+respondTo.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Expecta/Expecta/Matchers/EXPMatchers+respondTo.h
|
||||
1
Example/Pods/Headers/Private/Expecta/EXPMatchers.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Expecta/EXPMatchers.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Expecta/Expecta/Matchers/EXPMatchers.h
|
||||
1
Example/Pods/Headers/Private/Expecta/EXPUnsupportedObject.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Expecta/EXPUnsupportedObject.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Expecta/Expecta/EXPUnsupportedObject.h
|
||||
1
Example/Pods/Headers/Private/Expecta/Expecta.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Expecta/Expecta.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Expecta/Expecta/Expecta.h
|
||||
1
Example/Pods/Headers/Private/Expecta/ExpectaObject.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Expecta/ExpectaObject.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Expecta/Expecta/ExpectaObject.h
|
||||
1
Example/Pods/Headers/Private/Expecta/ExpectaSupport.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Expecta/ExpectaSupport.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Expecta/Expecta/ExpectaSupport.h
|
||||
1
Example/Pods/Headers/Private/Expecta/NSObject+Expecta.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Expecta/NSObject+Expecta.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Expecta/Expecta/NSObject+Expecta.h
|
||||
1
Example/Pods/Headers/Private/Expecta/NSValue+Expecta.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Expecta/NSValue+Expecta.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Expecta/Expecta/NSValue+Expecta.h
|
||||
1
Example/Pods/Headers/Private/FBSnapshotTestCase/FBSnapshotTestCase.h
generated
Symbolic link
1
Example/Pods/Headers/Private/FBSnapshotTestCase/FBSnapshotTestCase.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../FBSnapshotTestCase/FBSnapshotTestCase/FBSnapshotTestCase.h
|
||||
1
Example/Pods/Headers/Private/FBSnapshotTestCase/FBSnapshotTestCasePlatform.h
generated
Symbolic link
1
Example/Pods/Headers/Private/FBSnapshotTestCase/FBSnapshotTestCasePlatform.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../FBSnapshotTestCase/FBSnapshotTestCase/FBSnapshotTestCasePlatform.h
|
||||
1
Example/Pods/Headers/Private/FBSnapshotTestCase/FBSnapshotTestController.h
generated
Symbolic link
1
Example/Pods/Headers/Private/FBSnapshotTestCase/FBSnapshotTestController.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../FBSnapshotTestCase/FBSnapshotTestCase/FBSnapshotTestController.h
|
||||
1
Example/Pods/Headers/Private/FBSnapshotTestCase/UIApplication+StrictKeyWindow.h
generated
Symbolic link
1
Example/Pods/Headers/Private/FBSnapshotTestCase/UIApplication+StrictKeyWindow.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../FBSnapshotTestCase/FBSnapshotTestCase/Categories/UIApplication+StrictKeyWindow.h
|
||||
1
Example/Pods/Headers/Private/FBSnapshotTestCase/UIImage+Compare.h
generated
Symbolic link
1
Example/Pods/Headers/Private/FBSnapshotTestCase/UIImage+Compare.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../FBSnapshotTestCase/FBSnapshotTestCase/Categories/UIImage+Compare.h
|
||||
1
Example/Pods/Headers/Private/FBSnapshotTestCase/UIImage+Diff.h
generated
Symbolic link
1
Example/Pods/Headers/Private/FBSnapshotTestCase/UIImage+Diff.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../FBSnapshotTestCase/FBSnapshotTestCase/Categories/UIImage+Diff.h
|
||||
1
Example/Pods/Headers/Private/FBSnapshotTestCase/UIImage+Snapshot.h
generated
Symbolic link
1
Example/Pods/Headers/Private/FBSnapshotTestCase/UIImage+Snapshot.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../FBSnapshotTestCase/FBSnapshotTestCase/Categories/UIImage+Snapshot.h
|
||||
1
Example/Pods/Headers/Private/PNGradientView/PNGradientView.h
generated
Symbolic link
1
Example/Pods/Headers/Private/PNGradientView/PNGradientView.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../../../Pod/Classes/PNGradientView.h
|
||||
1
Example/Pods/Headers/Private/RZDataBinding/NSObject+RZDataBinding.h
generated
Symbolic link
1
Example/Pods/Headers/Private/RZDataBinding/NSObject+RZDataBinding.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../RZDataBinding/RZDataBinding/NSObject+RZDataBinding.h
|
||||
1
Example/Pods/Headers/Private/RZDataBinding/RZDBCoalesce.h
generated
Symbolic link
1
Example/Pods/Headers/Private/RZDataBinding/RZDBCoalesce.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../RZDataBinding/RZDataBinding/RZDBCoalesce.h
|
||||
1
Example/Pods/Headers/Private/RZDataBinding/RZDBMacros.h
generated
Symbolic link
1
Example/Pods/Headers/Private/RZDataBinding/RZDBMacros.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../RZDataBinding/RZDataBinding/RZDBMacros.h
|
||||
1
Example/Pods/Headers/Private/RZDataBinding/RZDBTransforms.h
generated
Symbolic link
1
Example/Pods/Headers/Private/RZDataBinding/RZDBTransforms.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../RZDataBinding/RZDataBinding/RZDBTransforms.h
|
||||
1
Example/Pods/Headers/Private/RZDataBinding/RZDataBinding.h
generated
Symbolic link
1
Example/Pods/Headers/Private/RZDataBinding/RZDataBinding.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../RZDataBinding/RZDataBinding/RZDataBinding.h
|
||||
1
Example/Pods/Headers/Private/Specta/SPTCallSite.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Specta/SPTCallSite.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Specta/Specta/Specta/SPTCallSite.h
|
||||
1
Example/Pods/Headers/Private/Specta/SPTCompiledExample.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Specta/SPTCompiledExample.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Specta/Specta/Specta/SPTCompiledExample.h
|
||||
1
Example/Pods/Headers/Private/Specta/SPTExample.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Specta/SPTExample.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Specta/Specta/Specta/SPTExample.h
|
||||
1
Example/Pods/Headers/Private/Specta/SPTExampleGroup.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Specta/SPTExampleGroup.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Specta/Specta/Specta/SPTExampleGroup.h
|
||||
1
Example/Pods/Headers/Private/Specta/SPTExcludeGlobalBeforeAfterEach.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Specta/SPTExcludeGlobalBeforeAfterEach.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Specta/Specta/Specta/SPTExcludeGlobalBeforeAfterEach.h
|
||||
1
Example/Pods/Headers/Private/Specta/SPTGlobalBeforeAfterEach.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Specta/SPTGlobalBeforeAfterEach.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Specta/Specta/Specta/SPTGlobalBeforeAfterEach.h
|
||||
1
Example/Pods/Headers/Private/Specta/SPTSharedExampleGroups.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Specta/SPTSharedExampleGroups.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Specta/Specta/Specta/SPTSharedExampleGroups.h
|
||||
1
Example/Pods/Headers/Private/Specta/SPTSpec.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Specta/SPTSpec.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Specta/Specta/Specta/SPTSpec.h
|
||||
1
Example/Pods/Headers/Private/Specta/SPTTestSuite.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Specta/SPTTestSuite.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Specta/Specta/Specta/SPTTestSuite.h
|
||||
1
Example/Pods/Headers/Private/Specta/Specta.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Specta/Specta.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Specta/Specta/Specta/Specta.h
|
||||
1
Example/Pods/Headers/Private/Specta/SpectaDSL.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Specta/SpectaDSL.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Specta/Specta/Specta/SpectaDSL.h
|
||||
1
Example/Pods/Headers/Private/Specta/SpectaTypes.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Specta/SpectaTypes.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Specta/Specta/Specta/SpectaTypes.h
|
||||
1
Example/Pods/Headers/Private/Specta/SpectaUtility.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Specta/SpectaUtility.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Specta/Specta/Specta/SpectaUtility.h
|
||||
1
Example/Pods/Headers/Private/Specta/XCTest+Private.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Specta/XCTest+Private.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Specta/Specta/Specta/XCTest+Private.h
|
||||
1
Example/Pods/Headers/Private/Specta/XCTestCase+Specta.h
generated
Symbolic link
1
Example/Pods/Headers/Private/Specta/XCTestCase+Specta.h
generated
Symbolic link
@ -0,0 +1 @@
|
||||
../../../Specta/Specta/Specta/XCTestCase+Specta.h
|
||||
@ -1,15 +1,15 @@
|
||||
{
|
||||
"name": "PNGradientView",
|
||||
"version": "0.1.0",
|
||||
"version": "0.1.5",
|
||||
"summary": "PNGradientView is a UIView subclassing with gradient support",
|
||||
"homepage": "https://github.com/<GITHUB_USERNAME>/PNGradientView",
|
||||
"homepage": "https://github.com/giuseppenucifora/PNGradientView",
|
||||
"license": "MIT",
|
||||
"authors": {
|
||||
"Giuseppe Nucifora": "me@giuseppenucifora.com"
|
||||
},
|
||||
"source": {
|
||||
"git": "https://github.com/<GITHUB_USERNAME>/PNGradientView.git",
|
||||
"tag": "0.1.0"
|
||||
"git": "https://github.com/giuseppenucifora/PNGradientView.git",
|
||||
"tag": "0.1.5"
|
||||
},
|
||||
"platforms": {
|
||||
"ios": "7.0"
|
||||
@ -21,5 +21,10 @@
|
||||
"Pod/Assets/*.png"
|
||||
]
|
||||
},
|
||||
"frameworks": "QuartzCore"
|
||||
"frameworks": "QuartzCore",
|
||||
"dependencies": {
|
||||
"RZDataBinding": [
|
||||
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
30
Example/Pods/Manifest.lock
generated
30
Example/Pods/Manifest.lock
generated
@ -1,14 +1,17 @@
|
||||
PODS:
|
||||
- Expecta (1.0.5)
|
||||
- Expecta+Snapshots (2.0.0):
|
||||
- Expecta+Snapshots (3.0.0):
|
||||
- Expecta (~> 1.0)
|
||||
- FBSnapshotTestCase/Core (~> 2.0.3)
|
||||
- FBSnapshotTestCase (2.0.7):
|
||||
- FBSnapshotTestCase/SwiftSupport (= 2.0.7)
|
||||
- FBSnapshotTestCase/Core (2.0.7)
|
||||
- FBSnapshotTestCase/SwiftSupport (2.0.7):
|
||||
- FBSnapshotTestCase/Core (~> 2.0)
|
||||
- Specta (~> 1.0)
|
||||
- FBSnapshotTestCase (2.1.0):
|
||||
- FBSnapshotTestCase/SwiftSupport (= 2.1.0)
|
||||
- FBSnapshotTestCase/Core (2.1.0)
|
||||
- FBSnapshotTestCase/SwiftSupport (2.1.0):
|
||||
- FBSnapshotTestCase/Core
|
||||
- PNGradientView (0.1.0)
|
||||
- PNGradientView (0.1.5):
|
||||
- RZDataBinding
|
||||
- RZDataBinding (2.0.3)
|
||||
- Specta (1.0.5)
|
||||
|
||||
DEPENDENCIES:
|
||||
@ -20,15 +23,14 @@ DEPENDENCIES:
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
PNGradientView:
|
||||
:path: "../"
|
||||
:path: ../
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
Expecta: e1c022fcd33910b6be89c291d2775b3fe27a89fe
|
||||
Expecta+Snapshots: 29b38dd695bc72a0ed2bea833937d78df41943ba
|
||||
FBSnapshotTestCase: 7e85180d0d141a0cf472352edda7e80d7eaeb547
|
||||
PNGradientView: 21d127e76f77674eecfa0dc9859751004f485e38
|
||||
Expecta+Snapshots: c343f410c7a6392f3e22e78f94c44b6c0749a516
|
||||
FBSnapshotTestCase: 366ecd378511d7716c79991cd8067d1eed23578d
|
||||
PNGradientView: e8b91f023a3037ba0442f76ddb1724a8c8635c64
|
||||
RZDataBinding: 00d468ebe667f02c2bd5416f87b4b5d826188c4d
|
||||
Specta: ac94d110b865115fe60ff2c6d7281053c6f8e8a2
|
||||
|
||||
PODFILE CHECKSUM: cd7860932a2fb17c979c3a4af42606b114244376
|
||||
|
||||
COCOAPODS: 1.0.0.beta.2
|
||||
COCOAPODS: 0.39.0
|
||||
|
||||
9576
Example/Pods/Pods.xcodeproj/project.pbxproj
generated
9576
Example/Pods/Pods.xcodeproj/project.pbxproj
generated
File diff suppressed because it is too large
Load Diff
@ -14,7 +14,7 @@
|
||||
buildForArchiving = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = 'primary'
|
||||
BlueprintIdentifier = '963AFB80CB68E667D89A4C7B'
|
||||
BlueprintIdentifier = 'A51FCBC4CED1FD3D48C2F214'
|
||||
BlueprintName = 'PNGradientView'
|
||||
ReferencedContainer = 'container:Pods.xcodeproj'
|
||||
BuildableName = 'PNGradientView.framework'>
|
||||
|
||||
22
Example/Pods/RZDataBinding/LICENSE
generated
Normal file
22
Example/Pods/RZDataBinding/LICENSE
generated
Normal file
@ -0,0 +1,22 @@
|
||||
|
||||
Copyright 2014 Raizlabs and other contributors
|
||||
http://raizlabs.com/
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
172
Example/Pods/RZDataBinding/README.md
generated
Normal file
172
Example/Pods/RZDataBinding/README.md
generated
Normal file
@ -0,0 +1,172 @@
|
||||
# RZDataBinding
|
||||
|
||||
[](http://cocoadocs.org/docsets/RZDataBinding)
|
||||
|
||||
<p align="center">
|
||||
<img src="http://cl.ly/image/1r0I0x401W2m/chain.png"
|
||||
alt="RZDataBinding">
|
||||
</p>
|
||||
## Overview
|
||||
RZDataBinding is a framework designed to help maintain data integrity in your iOS or OS X app. It is built using the standard Key-Value Observation (KVO) framework, but is safer and provides additional functionality. Like KVO, RZDataBinding helps to avoid endless delegate chains by establishing direct callbacks for when an object changes state.
|
||||
|
||||
## Installation
|
||||
Install using [CocoaPods](http://cocoapods.org) (recommended) by adding the following line to your Podfile:
|
||||
|
||||
`pod "RZDataBinding"`
|
||||
|
||||
Alternatively, download the repository and add the contents of the RZDataBinding directory to your project.
|
||||
|
||||
## Demo Project
|
||||
An example project is available in the Example directory. You can quickly check it out with
|
||||
|
||||
`pod try RZDataBinding`
|
||||
|
||||
Or download the zip from github and run it manually.
|
||||
|
||||
<p align="center">
|
||||
<img src="http://cl.ly/image/152x112l0i2n/rzdb.gif"
|
||||
alt="RZDataBinding">
|
||||
</p>
|
||||
|
||||
The demo shows a basic usage of RZDataBinding, but is by no means the canonical or most advanced use case.
|
||||
|
||||
##Usage
|
||||
**Register a callback for when the keypath of an object changes:**
|
||||
``` obj-c
|
||||
// Register a selector to be called on a given target whenever keyPath changes on the receiver.
|
||||
// Action must take either zero or exactly one parameter, an NSDictionary.
|
||||
// If the method has a parameter, the dictionary will contain values for the appropriate
|
||||
// RZDBChangeKeys. If keys are absent, they can be assumed to be nil. Values will not be NSNull.
|
||||
- (void)rz_addTarget:(id)target
|
||||
action:(SEL)action
|
||||
forKeyPathChange:(NSString *)keyPath;
|
||||
```
|
||||
|
||||
**Bind values of two objects together either directly or with a function:**
|
||||
``` obj-c
|
||||
// Binds the value of a given key of the receiver to the value of a key path of another object.
|
||||
// When the key path of the object changes, the bound key of the receiver is also changed.
|
||||
- (void)rz_bindKey:(NSString *)key
|
||||
toKeyPath:(NSString *)foreignKeyPath
|
||||
ofObject:(id)object;
|
||||
|
||||
// Same as the above method, but the binding function is first applied
|
||||
// to the changed value before setting the value of the bound key.
|
||||
// If nil, the identity function is assumed, making it identical to regular rz_bindKey.
|
||||
- (void)rz_bindKey:(NSString *)key
|
||||
toKeyPath:(NSString *)foreignKeyPath
|
||||
ofObject:(id)object
|
||||
withFunction:(RZDBKeyBindingFunction)bindingFunction;
|
||||
```
|
||||
Targets can be removed and keys unbound with corresponding removal methods, but unlike with standard KVO, you are not obligated to do so. RZDataBinding will automatically cleanup observers before objects are deallocated.
|
||||
|
||||
## Why not use plain KVO?
|
||||
Consider the following code, which calls `nameChanged:` when a user object's name changes, and reload a collection view when the user's preferences change:
|
||||
|
||||
**Using KVO:**
|
||||
``` obj-c
|
||||
static void* const MyKVOContext = (void *)&MyKVOContext;
|
||||
|
||||
- (void)setupKVO
|
||||
{
|
||||
[self.user addObserver:self
|
||||
forKeyPath:@"name"
|
||||
options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew
|
||||
context:MyKVOContext];
|
||||
|
||||
[self.user addObserver:self
|
||||
forKeyPath:@"preferences"
|
||||
options:kNilOptions
|
||||
context:MyKVOContext];
|
||||
}
|
||||
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath
|
||||
ofObject:(id)object change:(NSDictionary *)change
|
||||
context:(void *)context
|
||||
{
|
||||
if ( context == MyKVOContext ) {
|
||||
if ( [object isEqual:self.user] ) {
|
||||
if ( [keyPath isEqualToString:@"name"] ) {
|
||||
[self nameChanged:change];
|
||||
}
|
||||
else if ( [keyPath isEqualToString:@"preferences"] ) {
|
||||
[self.collectionView reloadData];
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[self.user removeObserver:self forKeyPath:@"name" context:MyKVOContext];
|
||||
[self.user removeObserver:self forKeyPath:@"preferences" context:MyKVOContext];
|
||||
}
|
||||
```
|
||||
|
||||
**Using RZDataBinding:**
|
||||
``` obj-c
|
||||
- (void)setupKVO
|
||||
{
|
||||
[self.user rz_addTarget:self
|
||||
action:@selector(nameChanged:)
|
||||
forKeyPathChange:@"name"];
|
||||
|
||||
[self.user rz_addTarget:self.collectionView
|
||||
action:@selector(reloadData)
|
||||
forKeyPathChange:@"preferences"];
|
||||
}
|
||||
```
|
||||
Aside from the obvious reduction in code, the RZDataBinding implementation demonstrates several other wins:
|
||||
|
||||
1. No need to manage different KVO contexts and check which object/keypath changed
|
||||
2. No need to implement an instance method, meaning *any* object can be added as a target
|
||||
3. No need to teardown before deallocation (standard KVO crashes if you fail to do this)
|
||||
|
||||
## Safe Keypaths
|
||||
|
||||
RZDataBinding also provides [several convenience macros](RZDataBinding/RZDBMacros.h) to create type-safe keypaths. When running in `DEBUG` mode, invalid keypaths will generate a compiler error:
|
||||
|
||||
``` obj-c
|
||||
// Creates the keypath @"text", ensuring it exists on objects of type UILabel
|
||||
RZDB_KP(UILabel, text);
|
||||
|
||||
// Creates @"layer.cornerRadius", ensuring the keypath exists on myView
|
||||
RZDB_KP_OBJ(myView, layer.cornerRadius);
|
||||
|
||||
// Creates @"session.user.name", ensuring the keypath exists on self
|
||||
RZDB_KP_SELF(session.user.name);
|
||||
```
|
||||
|
||||
You should *always* use these macros instead of literal strings, because of the additional type checks they provide. Note that in production these macros simplify to literal string generation to avoid any additional overhead.
|
||||
|
||||
## Callback Coalescing (Advanced)
|
||||
|
||||
RZDataBinding also provides a coalescing mechanism for fine-tuning areas of your application that receive or send a high number of KVO notifications, which may incur a performance cost. For example, a complex view might trigger an expensive layout operation whenever one of several properties changes. Or, some work may require changing properties several times before they settle to final values. In these cases, it may be beneficial to have RZDataBinding treat a block of work as an "atomic" event. That is, supported callbacks should be coalesced and sent once, when the work completes.
|
||||
|
||||
[`RZDBCoalesce`](RZDataBinding/RZDBCoalesce.h) provides a block interface:
|
||||
|
||||
``` obj-c
|
||||
[RZDBCoalesce coalesceBlock:^{
|
||||
// Callbacks within this block are coalesced,
|
||||
// and sent only once, after the block completes
|
||||
}];
|
||||
```
|
||||
|
||||
Callbacks are not coalesced by default, even within an `RZDBCoalesce` event. The `rz_addTarget:action:` methods can opt in to support coalescing by specifying a coalesce proxy as the callback target:
|
||||
|
||||
``` obj-c
|
||||
[object rz_addTarget:[self rz_coalesceProxy]
|
||||
action:@selector(expensiveCallback)
|
||||
forKeyPathChange:RZDB_KP_OBJ(object, key.path)];
|
||||
```
|
||||
|
||||
In this example, the intended target is `self`, but if a coalesce event is in progress these messages will be coalesced and deferred until the event completes. Note that only `rz_addTarget:action:` callbacks may support coalescing; bindings established with the `rz_bindKey:` methods will never be coalesced.
|
||||
|
||||
## Author
|
||||
Rob Visentin, rob.visentin@raizlabs.com
|
||||
|
||||
## License
|
||||
RZDataBinding is available under the MIT license. See the LICENSE file for more info.
|
||||
192
Example/Pods/RZDataBinding/RZDataBinding/NSObject+RZDataBinding.h
generated
Normal file
192
Example/Pods/RZDataBinding/RZDataBinding/NSObject+RZDataBinding.h
generated
Normal file
@ -0,0 +1,192 @@
|
||||
//
|
||||
// NSObject+RZDataBinding.h
|
||||
//
|
||||
// Created by Rob Visentin on 9/17/14.
|
||||
|
||||
// Copyright 2014 Raizlabs and other contributors
|
||||
// http://raizlabs.com/
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
#import "RZDBTransforms.h"
|
||||
|
||||
#pragma mark - Constants and Definitions
|
||||
|
||||
/**
|
||||
* The value for this key is the object that changed. This key is always present.
|
||||
*/
|
||||
OBJC_EXTERN NSString* const kRZDBChangeKeyObject;
|
||||
|
||||
/**
|
||||
* If present, the value for this key is the previous value on a key path change.
|
||||
*/
|
||||
OBJC_EXTERN NSString* const kRZDBChangeKeyOld;
|
||||
|
||||
/**
|
||||
* If present, the value for this key is the new value on a key path change, or the exisiting value for the key path for the initial call.
|
||||
*/
|
||||
OBJC_EXTERN NSString* const kRZDBChangeKeyNew;
|
||||
|
||||
/**
|
||||
* The value for this key is the key path that changed value. This key is always present.
|
||||
*/
|
||||
OBJC_EXTERN NSString* const kRZDBChangeKeyKeyPath;
|
||||
|
||||
/**
|
||||
* Set this to 1 (recommended) to enable automatic cleanup of observers on object deallocation.
|
||||
* If enabled, it is safe to observe or bind to weak references, and there is no need to call rz_removeTarget
|
||||
* or rz_unbindKey before targets or observed objects are deallocated. To achieve automatic cleanup,
|
||||
* RZDB swizzles the dealloc method to ensure observers are properly invalidated. There are other ways of implementing similar
|
||||
* behavior, but this has been found to be both the safest and most reliable in production.
|
||||
*
|
||||
* If set to 0 (not recommended), objects MUST remove themselves as targets and unbind their keys from any observed objects before being deallocated.
|
||||
* Failure to do so will result in crashes (just like standard KVO). Additionally, you should not add a target to or bind keys to
|
||||
* objects without first establishing a strong reference. Otherwise, the foreign object might be deallocated before the observer, causing in a crash.
|
||||
* If you choose to disable global automatic cleanup by setting this to 0, you must cleanup observers manually.
|
||||
*
|
||||
* @see rz_cleanupObservers
|
||||
*/
|
||||
#ifndef RZDB_AUTOMATIC_CLEANUP
|
||||
#define RZDB_AUTOMATIC_CLEANUP 1
|
||||
#endif
|
||||
|
||||
#pragma mark - NSObject+RZDataBinding interface
|
||||
|
||||
@interface NSObject (RZDataBinding)
|
||||
|
||||
/**
|
||||
* Register a selector to be called on a given target whenever keyPath changes on the receiver. The selector is not called immediately.
|
||||
*
|
||||
* @param target The object on which to call the action selector. Must be non-nil. This object is not retained.
|
||||
* @param action The selector to call on the target. Must not be NULL. The method must take either zero or exactly one parameter, an NSDictionary, and have a void return type. If the method has an NSDictionary parameter, the dictionary will contain values for the appropriate RZDBChangeKeys. If keys are absent, they can be assumed to be nil. Values will not be NSNull.
|
||||
* @param keyPath The key path of the receiver for which changes should trigger an action. Must be KVC compliant.
|
||||
*
|
||||
* @see RZDB_KP macro for creating keypaths.
|
||||
*/
|
||||
- (void)rz_addTarget:(id)target action:(SEL)action forKeyPathChange:(NSString *)keyPath;
|
||||
|
||||
/**
|
||||
* Register a selector to be called on a given target whenever keyPath changes on the receiver.
|
||||
*
|
||||
* @param target The object on which to call the action selector. Must be non-nil. This object is not retained.
|
||||
* @param action The selector to call on the target. Must not be NULL. The method must take either zero or exactly one parameter, an NSDictionary, and have a void return type. If the method has an NSDictionary parameter, the dictionary will contain values for the appropriate RZDBChangeKeys. If keys are absent, they can be assumed to be nil. Values will not be NSNull.
|
||||
* @param keyPath The key path of the receiver for which changes should trigger an action. Must be KVC compliant.
|
||||
* @param callImmediately If YES, the action is also called immediately before this method returns. In this case the change dictionary, if present, will not contain a value for kRZDBChangeKeyOld.
|
||||
*
|
||||
* @see RZDB_KP macro for creating keypaths.
|
||||
*/
|
||||
- (void)rz_addTarget:(id)target action:(SEL)action forKeyPathChange:(NSString *)keyPath callImmediately:(BOOL)callImmediately;
|
||||
|
||||
/**
|
||||
* A convenience method that calls rz_addTarget:action:forKeyPathChange: for each keyPath in the keyPaths array.
|
||||
*
|
||||
* @param target The object on which to call the action selector. Must be non-nil. This object is not retained.
|
||||
* @param action The selector to call on the target. Must not be NULL. See rz_addTarget documentation for more details.
|
||||
* @param keyPaths An array of key paths that should trigger an action. Each key path must be KVC compliant.
|
||||
*
|
||||
* @note The action is not called immediately.
|
||||
*
|
||||
* @see RZDB_KP macro for creating keypaths.
|
||||
*/
|
||||
- (void)rz_addTarget:(id)target action:(SEL)action forKeyPathChanges:(NSArray *)keyPaths;
|
||||
|
||||
/**
|
||||
* A convenience method that calls rz_addTarget:action:forKeyPathChange: for each keyPath in the keyPaths array.
|
||||
*
|
||||
* @param target The object on which to call the action selector. Must be non-nil. This object is not retained.
|
||||
* @param action The selector to call on the target. Must not be NULL. See rz_addTarget documentation for more details.
|
||||
* @param keyPaths An array of key paths that should trigger an action. Each key path must be KVC compliant.
|
||||
* @param callImmediately If YES, the action is also called immediately before this method returns. If the action takes no arguments, it will be called once. If the action takes a change dictonary parameter, it will be called once for each keypath, with the appropriate change dict. Note that in this case the dictionary will not contain a value for kRZDBChangeKeyOld.
|
||||
*
|
||||
* @see RZDB_KP macro for creating keypaths.
|
||||
*/
|
||||
- (void)rz_addTarget:(id)target action:(SEL)action forKeyPathChanges:(NSArray *)keyPaths callImmediately:(BOOL)callImmediately;
|
||||
|
||||
/**
|
||||
* Removes previously registered target/action pairs so that the actions are no longer called when the receiver changes value for keyPath.
|
||||
*
|
||||
* @param target The target to remove. Must be non-nil.
|
||||
* @param action The action to remove. Pass NULL to remove all actions registered for the target.
|
||||
* @param keyPath The key path to remove the target/action pair for.
|
||||
*
|
||||
* @note If RZDB_AUTOMATIC_CLEANUP is enabled, then there is obligation to call this method before either the target or receiver are deallocated.
|
||||
*
|
||||
* @see RZDB_KP macro for creating keypaths.
|
||||
*/
|
||||
- (void)rz_removeTarget:(id)target action:(SEL)action forKeyPathChange:(NSString *)keyPath;
|
||||
|
||||
/**
|
||||
* Binds the value of a given key of the receiver to the value of a key path of another object. When the key path of the object changes, the bound key of the receiver is set to the same value. The receiver's value for the key will match the value for the object's foreign key path before this method returns.
|
||||
*
|
||||
* @param key The receiver's key whose value should be bound to the value of a foreign key path. Must be KVC compliant.
|
||||
* @param foreignKeyPath A key path of another object to which the receiver's key value should be bound. Must be KVC compliant.
|
||||
* @param object An object with a key path that the receiver should bind to.
|
||||
*
|
||||
* @note If binding a primitive-type key to a keypath that may hit a nil object, you MUST use
|
||||
* rz_bindKey:toKeyPath:ofObject:withTransform: instead. This is because attempting to set a nil
|
||||
* value to a primitive-type using KVC causes a crash. In this case it may be helpful to use
|
||||
* one of the default RZDBTransforms.
|
||||
*
|
||||
* @see RZDB_KP macro for creating keypaths.
|
||||
*/
|
||||
- (void)rz_bindKey:(NSString *)key toKeyPath:(NSString *)foreignKeyPath ofObject:(id)object;
|
||||
|
||||
/**
|
||||
* Binds the value of a given key of the receiver to the value of a key path of another object. When the key path of the object changes, the binding transform is invoked and the bound key of the receiver is set to the transform's return value. The receiver's value for the key will be set before this method returns.
|
||||
*
|
||||
* @param key The receiver's key whose value should be bound to the value of a foreign key path. Must be KVC compliant.
|
||||
* @param foreignKeyPath A key path of another object to which the receiver's key value should be bound. Must be KVC compliant.
|
||||
* @param object An object with a key path that the receiver should bind to.
|
||||
* @param bindingTransform The transform to apply to changed values before setting the value of the bound key. If nil, the identity transform is assumed, making this method identical to regular rz_bindKey:.
|
||||
* You may use the constant RZDBTransforms provided for convenience.
|
||||
*
|
||||
* @see RZDB_KP macro for creating keypaths, and RZDBTransforms for constant transforms.
|
||||
*/
|
||||
- (void)rz_bindKey:(NSString *)key toKeyPath:(NSString *)foreignKeyPath ofObject:(id)object withTransform:(RZDBKeyBindingTransform)bindingTransform;
|
||||
|
||||
/**
|
||||
* Unbinds the given key of the receiver from the key path of another object.
|
||||
*
|
||||
* @param key The key to unbind.
|
||||
* @param foreignKeyPath The key path that the key should be unbound from.
|
||||
* @param object The object that the receiver should be unbound from.
|
||||
*
|
||||
* @note If RZDB_AUTOMATIC_CLEANUP is enabled, then there is no obligation to call this method before either the receiver or the foreign object are deallocated.
|
||||
*
|
||||
* @see RZDB_KP macro for creating keypaths.
|
||||
*/
|
||||
- (void)rz_unbindKey:(NSString *)key fromKeyPath:(NSString *)foreignKeyPath ofObject:(id)object;
|
||||
|
||||
#if !RZDB_AUTOMATIC_CLEANUP
|
||||
/**
|
||||
* Removes all callbacks and bindings both to and from the receiver.
|
||||
* This method essentially resets the receiver to a pristine state with respect to RZDataBinding.
|
||||
*
|
||||
* If RZDB_AUTOMATIC_CLEANUP is not enabled, you MUST call this method on any
|
||||
* observing or observed object it is deallocated. Failure to do so will result in a crash (just like standard KVO).
|
||||
*
|
||||
* @note This method breaks all bindings and callbacks on the receiver, including those created
|
||||
* by other clients. Therefore it is only safe to call this method from the receiver's dealloc method.
|
||||
*/
|
||||
- (void)rz_cleanupObservers;
|
||||
#endif
|
||||
|
||||
@end
|
||||
515
Example/Pods/RZDataBinding/RZDataBinding/NSObject+RZDataBinding.m
generated
Normal file
515
Example/Pods/RZDataBinding/RZDataBinding/NSObject+RZDataBinding.m
generated
Normal file
@ -0,0 +1,515 @@
|
||||
//
|
||||
// NSObject+RZDataBinding.m
|
||||
//
|
||||
// Created by Rob Visentin on 9/17/14.
|
||||
|
||||
// Copyright 2014 Raizlabs and other contributors
|
||||
// http://raizlabs.com/
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
#import <objc/runtime.h>
|
||||
#import <objc/message.h>
|
||||
|
||||
#import "NSObject+RZDataBinding.h"
|
||||
#import "RZDBMacros.h"
|
||||
|
||||
@class RZDBObserver;
|
||||
@class RZDBObserverContainer;
|
||||
|
||||
// public change keys
|
||||
NSString* const kRZDBChangeKeyObject = @"RZDBChangeObject";
|
||||
NSString* const kRZDBChangeKeyOld = @"RZDBChangeOld";
|
||||
NSString* const kRZDBChangeKeyNew = @"RZDBChangeNew";
|
||||
NSString* const kRZDBChangeKeyKeyPath = @"RZDBChangeKeyPath";
|
||||
|
||||
// private change keys
|
||||
static NSString* const kRZDBChangeKeyBoundKey = @"_RZDBChangeBoundKey";
|
||||
static NSString* const kRZDBChangeKeyBindingTransformKey = @"_RZDBChangeBindingTransform";
|
||||
|
||||
static void* const kRZDBSwizzledDeallocKey = (void *)&kRZDBSwizzledDeallocKey;
|
||||
|
||||
static void* const kRZDBKVOContext = (void *)&kRZDBKVOContext;
|
||||
|
||||
#define RZDBNotNull(obj) ((obj) != nil && ![(obj) isEqual:[NSNull null]])
|
||||
|
||||
#pragma mark - RZDataBinding_Private interface
|
||||
|
||||
// methods used to implement RZDB_AUTOMATIC_CLEANUP
|
||||
BOOL rz_requiresDeallocSwizzle(Class class);
|
||||
void rz_swizzleDeallocIfNeeded(Class class);
|
||||
|
||||
@interface NSObject (RZDataBinding_Private)
|
||||
|
||||
- (NSMutableArray *)rz_registeredObservers;
|
||||
- (void)rz_setRegisteredObservers:(NSMutableArray *)registeredObservers;
|
||||
|
||||
- (RZDBObserverContainer *)rz_dependentObservers;
|
||||
- (void)rz_setDependentObservers:(RZDBObserverContainer *)dependentObservers;
|
||||
|
||||
- (void)rz_addTarget:(id)target action:(SEL)action boundKey:(NSString *)boundKey bindingTransform:(RZDBKeyBindingTransform)bindingTransform forKeyPath:(NSString *)keyPath withOptions:(NSKeyValueObservingOptions)options;
|
||||
- (void)rz_removeTarget:(id)target action:(SEL)action boundKey:(NSString *)boundKey forKeyPath:(NSString *)keyPath;
|
||||
- (void)rz_observeBoundKeyChange:(NSDictionary *)change;
|
||||
- (void)rz_setBoundKey:(NSString *)key withValue:(id)value transform:(RZDBKeyBindingTransform)transform;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - RZDBObserver interface
|
||||
|
||||
@interface RZDBObserver : NSObject;
|
||||
|
||||
@property (assign, nonatomic) __unsafe_unretained NSObject *observedObject;
|
||||
@property (copy, nonatomic) NSString *keyPath;
|
||||
@property (copy, nonatomic) NSString *boundKey;
|
||||
@property (assign, nonatomic) NSKeyValueObservingOptions observationOptions;
|
||||
|
||||
@property (assign, nonatomic) __unsafe_unretained id target;
|
||||
@property (assign, nonatomic) SEL action;
|
||||
@property (strong, nonatomic) NSMethodSignature *methodSignature;
|
||||
|
||||
@property (copy, nonatomic) RZDBKeyBindingTransform bindingTransform;
|
||||
|
||||
- (instancetype)initWithObservedObject:(NSObject *)observedObject keyPath:(NSString *)keyPath observationOptions:(NSKeyValueObservingOptions)observingOptions;
|
||||
|
||||
- (void)setTarget:(id)target action:(SEL)action boundKey:(NSString *)boundKey bindingTransform:(RZDBKeyBindingTransform)bindingTransform;
|
||||
|
||||
- (void)invalidate;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - RZDBObserverContainer interface
|
||||
|
||||
@interface RZDBObserverContainer : NSObject
|
||||
|
||||
@property (strong, nonatomic) NSHashTable *observers;
|
||||
|
||||
- (void)addObserver:(RZDBObserver *)observer;
|
||||
- (void)removeObserver:(RZDBObserver *)observer;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - RZDataBinding implementation
|
||||
|
||||
@implementation NSObject (RZDataBinding)
|
||||
|
||||
- (void)rz_addTarget:(id)target action:(SEL)action forKeyPathChange:(NSString *)keyPath
|
||||
{
|
||||
[self rz_addTarget:target action:action forKeyPathChange:keyPath callImmediately:NO];
|
||||
}
|
||||
|
||||
- (void)rz_addTarget:(id)target action:(SEL)action forKeyPathChange:(NSString *)keyPath callImmediately:(BOOL)callImmediately
|
||||
{
|
||||
NSParameterAssert(target);
|
||||
NSParameterAssert(action);
|
||||
|
||||
NSKeyValueObservingOptions observationOptions = kNilOptions;
|
||||
|
||||
if ( [target methodSignatureForSelector:action].numberOfArguments > 2 ) {
|
||||
observationOptions |= NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld;
|
||||
}
|
||||
|
||||
if ( callImmediately ) {
|
||||
observationOptions |= NSKeyValueObservingOptionInitial;
|
||||
}
|
||||
|
||||
[self rz_addTarget:target action:action boundKey:nil bindingTransform:nil forKeyPath:keyPath withOptions:observationOptions];
|
||||
}
|
||||
|
||||
- (void)rz_addTarget:(id)target action:(SEL)action forKeyPathChanges:(NSArray *)keyPaths
|
||||
{
|
||||
[self rz_addTarget:target action:action forKeyPathChanges:keyPaths callImmediately:NO];
|
||||
}
|
||||
|
||||
- (void)rz_addTarget:(id)target action:(SEL)action forKeyPathChanges:(NSArray *)keyPaths callImmediately:(BOOL)callImmediately
|
||||
{
|
||||
BOOL callMultiple = NO;
|
||||
|
||||
if ( callImmediately ) {
|
||||
callMultiple = [target methodSignatureForSelector:action].numberOfArguments > 2;
|
||||
}
|
||||
|
||||
[keyPaths enumerateObjectsUsingBlock:^(NSString *keyPath, NSUInteger idx, BOOL *stop) {
|
||||
[self rz_addTarget:target action:action forKeyPathChange:keyPath callImmediately:callMultiple];
|
||||
}];
|
||||
|
||||
if ( callImmediately && !callMultiple ) {
|
||||
((void(*)(id, SEL))objc_msgSend)(target, action);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)rz_removeTarget:(id)target action:(SEL)action forKeyPathChange:(NSString *)keyPath
|
||||
{
|
||||
[self rz_removeTarget:target action:action boundKey:nil forKeyPath:keyPath];
|
||||
}
|
||||
|
||||
- (void)rz_bindKey:(NSString *)key toKeyPath:(NSString *)foreignKeyPath ofObject:(id)object
|
||||
{
|
||||
[self rz_bindKey:key toKeyPath:foreignKeyPath ofObject:object withTransform:nil];
|
||||
}
|
||||
|
||||
- (void)rz_bindKey:(NSString *)key toKeyPath:(NSString *)foreignKeyPath ofObject:(id)object withTransform:(RZDBKeyBindingTransform)bindingTransform
|
||||
{
|
||||
NSParameterAssert(key);
|
||||
NSParameterAssert(foreignKeyPath);
|
||||
|
||||
if ( object != nil ) {
|
||||
@try {
|
||||
id val = [object valueForKeyPath:foreignKeyPath];
|
||||
|
||||
[self rz_setBoundKey:key withValue:val transform:bindingTransform];
|
||||
}
|
||||
@catch (NSException *exception) {
|
||||
[NSException raise:NSInvalidArgumentException format:@"RZDataBinding cannot bind key:%@ to key path:%@ of object:%@. Reason: %@", key, foreignKeyPath, [object description], exception.reason];
|
||||
}
|
||||
|
||||
[object rz_addTarget:self action:@selector(rz_observeBoundKeyChange:) boundKey:key bindingTransform:bindingTransform forKeyPath:foreignKeyPath withOptions:NSKeyValueObservingOptionNew];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)rz_unbindKey:(NSString *)key fromKeyPath:(NSString *)foreignKeyPath ofObject:(id)object
|
||||
{
|
||||
[object rz_removeTarget:self action:@selector(rz_observeBoundKeyChange:) boundKey:key forKeyPath:foreignKeyPath];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - RZDataBinding_Private implementation
|
||||
|
||||
@implementation NSObject (RZDataBinding_Private)
|
||||
|
||||
- (NSMutableArray *)rz_registeredObservers
|
||||
{
|
||||
return objc_getAssociatedObject(self, @selector(rz_registeredObservers));
|
||||
}
|
||||
|
||||
- (void)rz_setRegisteredObservers:(NSMutableArray *)registeredObservers
|
||||
{
|
||||
objc_setAssociatedObject(self, @selector(rz_registeredObservers), registeredObservers, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
|
||||
- (RZDBObserverContainer *)rz_dependentObservers
|
||||
{
|
||||
return objc_getAssociatedObject(self, @selector(rz_dependentObservers));
|
||||
}
|
||||
|
||||
- (void)rz_setDependentObservers:(RZDBObserverContainer *)dependentObservers
|
||||
{
|
||||
objc_setAssociatedObject(self, @selector(rz_dependentObservers), dependentObservers, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
|
||||
- (void)rz_addTarget:(id)target action:(SEL)action boundKey:(NSString *)boundKey bindingTransform:(RZDBKeyBindingTransform)bindingTransform forKeyPath:(NSString *)keyPath withOptions:(NSKeyValueObservingOptions)options
|
||||
{
|
||||
NSMutableArray *registeredObservers = nil;
|
||||
RZDBObserverContainer *dependentObservers = nil;
|
||||
|
||||
RZDBObserver *observer = [[RZDBObserver alloc] initWithObservedObject:self keyPath:keyPath observationOptions:options];
|
||||
|
||||
[observer setTarget:target action:action boundKey:boundKey bindingTransform:bindingTransform];
|
||||
|
||||
@synchronized (self) {
|
||||
registeredObservers = [self rz_registeredObservers];
|
||||
|
||||
if ( registeredObservers == nil ) {
|
||||
registeredObservers = [NSMutableArray array];
|
||||
[self rz_setRegisteredObservers:registeredObservers];
|
||||
}
|
||||
|
||||
[registeredObservers addObject:observer];
|
||||
}
|
||||
|
||||
@synchronized (target) {
|
||||
dependentObservers = [target rz_dependentObservers];
|
||||
|
||||
if ( dependentObservers == nil ) {
|
||||
dependentObservers = [[RZDBObserverContainer alloc] init];
|
||||
[target rz_setDependentObservers:dependentObservers];
|
||||
}
|
||||
|
||||
[dependentObservers addObserver:observer];
|
||||
}
|
||||
|
||||
#if RZDB_AUTOMATIC_CLEANUP
|
||||
rz_swizzleDeallocIfNeeded([self class]);
|
||||
rz_swizzleDeallocIfNeeded([target class]);
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)rz_removeTarget:(id)target action:(SEL)action boundKey:(NSString *)boundKey forKeyPath:(NSString *)keyPath
|
||||
{
|
||||
@synchronized (self) {
|
||||
NSMutableArray *registeredObservers = [self rz_registeredObservers];
|
||||
|
||||
[registeredObservers enumerateObjectsUsingBlock:^(RZDBObserver *observer, NSUInteger idx, BOOL *stop) {
|
||||
BOOL targetsEqual = (target == observer.target);
|
||||
BOOL actionsEqual = (action == NULL || action == observer.action);
|
||||
BOOL boundKeysEqual = (boundKey == observer.boundKey || [boundKey isEqualToString:observer.boundKey]);
|
||||
BOOL keyPathsEqual = [keyPath isEqualToString:observer.keyPath];
|
||||
|
||||
BOOL allEqual = (targetsEqual && actionsEqual && boundKeysEqual && keyPathsEqual);
|
||||
|
||||
if ( allEqual ) {
|
||||
[observer invalidate];
|
||||
}
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)rz_observeBoundKeyChange:(NSDictionary *)change
|
||||
{
|
||||
NSString *boundKey = change[kRZDBChangeKeyBoundKey];
|
||||
|
||||
if ( boundKey != nil ) {
|
||||
id value = change[kRZDBChangeKeyNew];
|
||||
|
||||
[self rz_setBoundKey:boundKey withValue:value transform:change[kRZDBChangeKeyBindingTransformKey]];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)rz_setBoundKey:(NSString *)key withValue:(id)value transform:(RZDBKeyBindingTransform)transform
|
||||
{
|
||||
id currentValue = [self valueForKey:key];
|
||||
|
||||
if ( transform != nil ) {
|
||||
value = transform(value);
|
||||
}
|
||||
|
||||
if ( currentValue != value && ![currentValue isEqual:value] ) {
|
||||
[self setValue:value forKey:key];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)rz_cleanupObservers
|
||||
{
|
||||
NSMutableArray *registeredObservers = [self rz_registeredObservers];
|
||||
RZDBObserverContainer *dependentObservers = [self rz_dependentObservers];
|
||||
|
||||
[[registeredObservers copy] enumerateObjectsUsingBlock:^(RZDBObserver *obs, NSUInteger idx, BOOL *stop) {
|
||||
[obs invalidate];
|
||||
}];
|
||||
|
||||
[[dependentObservers.observers allObjects] enumerateObjectsUsingBlock:^(RZDBObserver *obs, NSUInteger idx, BOOL *stop) {
|
||||
[obs invalidate];
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - RZDBObserver implementation
|
||||
|
||||
@implementation RZDBObserver
|
||||
|
||||
- (instancetype)initWithObservedObject:(NSObject *)observedObject keyPath:(NSString *)keyPath observationOptions:(NSKeyValueObservingOptions)observingOptions
|
||||
{
|
||||
self = [super init];
|
||||
if ( self != nil ) {
|
||||
_observedObject = observedObject;
|
||||
_keyPath = keyPath;
|
||||
_observationOptions = observingOptions;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setTarget:(id)target action:(SEL)action boundKey:(NSString *)boundKey bindingTransform:(RZDBKeyBindingTransform)bindingTransform
|
||||
{
|
||||
self.target = target;
|
||||
self.action = action;
|
||||
self.methodSignature = [target methodSignatureForSelector:action];
|
||||
|
||||
self.boundKey = boundKey;
|
||||
self.bindingTransform = bindingTransform;
|
||||
|
||||
[self.observedObject addObserver:self forKeyPath:self.keyPath options:self.observationOptions context:kRZDBKVOContext];
|
||||
}
|
||||
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
|
||||
{
|
||||
if ( context == kRZDBKVOContext ) {
|
||||
if ( self.methodSignature.numberOfArguments > 2 ) {
|
||||
NSDictionary *changeDict = [self changeDictForKVOChange:change];
|
||||
|
||||
((void(*)(id, SEL, NSDictionary *))objc_msgSend)(self.target, self.action, changeDict);
|
||||
}
|
||||
else {
|
||||
((void(*)(id, SEL))objc_msgSend)(self.target, self.action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (NSDictionary *)changeDictForKVOChange:(NSDictionary *)kvoChange
|
||||
{
|
||||
NSMutableDictionary *changeDict = [NSMutableDictionary dictionary];
|
||||
|
||||
if ( self.observedObject != nil ) {
|
||||
changeDict[kRZDBChangeKeyObject] = self.observedObject;
|
||||
}
|
||||
|
||||
if ( RZDBNotNull(kvoChange[NSKeyValueChangeOldKey]) ) {
|
||||
changeDict[kRZDBChangeKeyOld] = kvoChange[NSKeyValueChangeOldKey];
|
||||
}
|
||||
|
||||
if ( RZDBNotNull(kvoChange[NSKeyValueChangeNewKey]) ) {
|
||||
changeDict[kRZDBChangeKeyNew] = kvoChange[NSKeyValueChangeNewKey];
|
||||
}
|
||||
|
||||
if ( self.keyPath != nil ) {
|
||||
changeDict[kRZDBChangeKeyKeyPath] = self.keyPath;
|
||||
}
|
||||
|
||||
if ( self.boundKey != nil ) {
|
||||
changeDict[kRZDBChangeKeyBoundKey] = self.boundKey;
|
||||
}
|
||||
|
||||
if ( self.bindingTransform != nil ) {
|
||||
changeDict[kRZDBChangeKeyBindingTransformKey] = self.bindingTransform;
|
||||
}
|
||||
|
||||
return [changeDict copy];
|
||||
}
|
||||
|
||||
- (void)invalidate
|
||||
{
|
||||
[[self.target rz_dependentObservers] removeObserver:self];
|
||||
[[self.observedObject rz_registeredObservers] removeObject:self];
|
||||
|
||||
// KVO throws an exception when removing an observer that was never added.
|
||||
// This should never be a problem given how things are setup, but make sure to avoid a crash.
|
||||
@try {
|
||||
[self.observedObject removeObserver:self forKeyPath:self.keyPath context:kRZDBKVOContext];
|
||||
}
|
||||
@catch (__unused NSException *exception) {
|
||||
RZDBLog(@"RZDataBinding attempted to remove an observer from object:%@, but the observer was never added. This shouldn't have happened, but won't affect anything going forward.", self.observedObject);
|
||||
}
|
||||
|
||||
self.observedObject = nil;
|
||||
self.target = nil;
|
||||
self.action = NULL;
|
||||
self.methodSignature = nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - RZDBObserverContainer implementation
|
||||
|
||||
@implementation RZDBObserverContainer
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
self = [super init];
|
||||
if ( self != nil ) {
|
||||
_observers = [NSHashTable weakObjectsHashTable];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)addObserver:(RZDBObserver *)observer
|
||||
{
|
||||
@synchronized (self) {
|
||||
[self.observers addObject:observer];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)removeObserver:(RZDBObserver *)observer
|
||||
{
|
||||
@synchronized (self) {
|
||||
[self.observers removeObject:observer];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
// a class doesn't need dealloc swizzled if it or a superclass has been swizzled already
|
||||
BOOL rz_requiresDeallocSwizzle(Class class)
|
||||
{
|
||||
BOOL swizzled = NO;
|
||||
|
||||
for ( Class currentClass = class; !swizzled && currentClass != nil; currentClass = class_getSuperclass(currentClass) ) {
|
||||
swizzled = [objc_getAssociatedObject(currentClass, kRZDBSwizzledDeallocKey) boolValue];
|
||||
}
|
||||
|
||||
return !swizzled;
|
||||
}
|
||||
|
||||
// In order for automatic cleanup to work, observers must be removed before deallocation.
|
||||
// This method ensures that rz_cleanupObservers is called in the dealloc of classes of objects
|
||||
// that are used in RZDataBinding.
|
||||
void rz_swizzleDeallocIfNeeded(Class class)
|
||||
{
|
||||
static SEL deallocSEL = NULL;
|
||||
static SEL cleanupSEL = NULL;
|
||||
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
deallocSEL = sel_getUid("dealloc");
|
||||
cleanupSEL = sel_getUid("rz_cleanupObservers");
|
||||
});
|
||||
|
||||
@synchronized (class) {
|
||||
if ( !rz_requiresDeallocSwizzle(class) ) {
|
||||
// dealloc swizzling already resolved
|
||||
return;
|
||||
}
|
||||
|
||||
objc_setAssociatedObject(class, kRZDBSwizzledDeallocKey, @(YES), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
|
||||
Method dealloc = NULL;
|
||||
|
||||
// search instance methods of the class (does not search superclass methods)
|
||||
unsigned int n;
|
||||
Method *methods = class_copyMethodList(class, &n);
|
||||
|
||||
for ( unsigned int i = 0; i < n; i++ ) {
|
||||
if ( method_getName(methods[i]) == deallocSEL ) {
|
||||
dealloc = methods[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(methods);
|
||||
|
||||
if ( dealloc == NULL ) {
|
||||
Class superclass = class_getSuperclass(class);
|
||||
|
||||
// class does not implement dealloc, so implement it directly
|
||||
class_addMethod(class, deallocSEL, imp_implementationWithBlock(^(__unsafe_unretained id self) {
|
||||
|
||||
// cleanup RZDB observers
|
||||
((void(*)(id, SEL))objc_msgSend)(self, cleanupSEL);
|
||||
|
||||
// ARC automatically calls super when dealloc is implemented in code,
|
||||
// but when provided our own dealloc IMP we have to call through to super manually
|
||||
struct objc_super superStruct = (struct objc_super){ self, superclass };
|
||||
((void (*)(struct objc_super*, SEL))objc_msgSendSuper)(&superStruct, deallocSEL);
|
||||
|
||||
}), method_getTypeEncoding(dealloc));
|
||||
}
|
||||
else {
|
||||
// class implements dealloc, so extend the existing implementation
|
||||
__block IMP deallocIMP = method_setImplementation(dealloc, imp_implementationWithBlock(^(__unsafe_unretained id self) {
|
||||
// cleanup RZDB observers
|
||||
((void(*)(id, SEL))objc_msgSend)(self, cleanupSEL);
|
||||
|
||||
// invoke the original dealloc IMP
|
||||
((void(*)(id, SEL))deallocIMP)(self, deallocSEL);
|
||||
}));
|
||||
}
|
||||
}
|
||||
111
Example/Pods/RZDataBinding/RZDataBinding/RZDBCoalesce.h
generated
Normal file
111
Example/Pods/RZDataBinding/RZDataBinding/RZDBCoalesce.h
generated
Normal file
@ -0,0 +1,111 @@
|
||||
//
|
||||
// RZDBCoalesce.h
|
||||
//
|
||||
// Created by Rob Visentin on 4/1/15.
|
||||
|
||||
// Copyright 2014 Raizlabs and other contributors
|
||||
// http://raizlabs.com/
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#pragma mark - NSObject+RZDBCoalesce interface
|
||||
|
||||
/**
|
||||
* Provides an interface for supporting coalesced data binding callbacks.
|
||||
*/
|
||||
@interface NSObject (RZDBCoalesce)
|
||||
|
||||
/**
|
||||
* Returns a proxy object that will participate in coalescing events.
|
||||
*
|
||||
* Use [target rz_coalesceProxy] as the target of the rz_addTarget:action: methods to support
|
||||
* coalescing for a target/action pair. If the callback occurs during a an RZDBCoalesce event, it will be
|
||||
* coalesced and deferred until the end RZDBCoalesce is committed.
|
||||
*
|
||||
* @note You should generally not call methods on the coalesce proxy directly.
|
||||
* The proxy will treat any 0-arg or 1-dictionary-arg methods with void return type as RZDB callbacks,
|
||||
* and coalesce them accordingly.
|
||||
*
|
||||
* @see RZDBCoalesce for how to begin/end coalesce events.
|
||||
*
|
||||
* @return A proxy object to use as a data binding target in the rz_addTarget:action: methods.
|
||||
*/
|
||||
- (id)rz_coalesceProxy;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - RZDBCoalesce interface
|
||||
|
||||
/**
|
||||
* There may be chunks of work that should be completed "atomically" with respect to RZDataBinding.
|
||||
* That is, actions registered using the rz_addTarget:action: methods that support coalescing
|
||||
* will be fired once, when the work is completed.
|
||||
*
|
||||
* The RZDBCoalesce object provides class methods to manage coalescing events.
|
||||
*
|
||||
* Coalescing is an advanced feature that should generally only be used if you encounter a performance issue,
|
||||
* or find some other requirement for it.
|
||||
*
|
||||
* @see NSObject+RZDBCoalesce for how to support coalesced callbacks.
|
||||
*/
|
||||
@interface RZDBCoalesce : NSObject
|
||||
|
||||
/**
|
||||
* Begin coalescing events for the current thread.
|
||||
* Changes that occur during the coalesce that would trigger actions registered to coalesce proxies with
|
||||
* the rz_addTarget:action: methods are instead coalesced and executed once when the coalesce ends.
|
||||
*
|
||||
* Every call to +begin MUST be balanced by a call to +commit on the same thread.
|
||||
* It is fine to begin a coalesce while already coalescing--
|
||||
* the coalesce will simply not end until both matching commits are hit.
|
||||
*
|
||||
* @note Bindings that occur during a coalesce still occur immediately.
|
||||
*
|
||||
* @see NSObject+RZDBCoalesce for how to support coalesced callbacks.
|
||||
*/
|
||||
+ (void)begin;
|
||||
|
||||
/**
|
||||
* Commit the current coalesce, sending the coalesced change callbacks.
|
||||
* If this commit closes a nested coalesce, callbacks are not sent until the outermost coalesce is committed.
|
||||
*
|
||||
* Calling this method from outside a coalesce has no effect.
|
||||
*/
|
||||
+ (void)commit;
|
||||
|
||||
/**
|
||||
* Convenience method that first calls +begin, then executes the block, then calls +commit.
|
||||
* You should prefer this method where possible to avoid programmer error (i.e. forgetting to call +commit).
|
||||
*
|
||||
* @param coalesceBlock The block to execute inside a coalesce. Must be non-nil.
|
||||
*
|
||||
* @see NSObject+RZDBCoalesce for how to support coalesced callbacks.
|
||||
*/
|
||||
+ (void)coalesceBlock:(void (^)())coalesceBlock;
|
||||
|
||||
/**
|
||||
* Cannot instantiate RZDBCoalesce directly. Use the class methods instead.
|
||||
*/
|
||||
- (instancetype)init __attribute__((unavailable("Cannot instantiate RZDBCoalesce directly. Use the class methods instead.")));
|
||||
|
||||
@end
|
||||
297
Example/Pods/RZDataBinding/RZDataBinding/RZDBCoalesce.m
generated
Normal file
297
Example/Pods/RZDataBinding/RZDataBinding/RZDBCoalesce.m
generated
Normal file
@ -0,0 +1,297 @@
|
||||
//
|
||||
// RZDBCoalesce.m
|
||||
//
|
||||
// Created by Rob Visentin on 4/1/15.
|
||||
|
||||
// Copyright 2014 Raizlabs and other contributors
|
||||
// http://raizlabs.com/
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
#import <objc/runtime.h>
|
||||
#import <objc/message.h>
|
||||
|
||||
#import "RZDBCoalesce.h"
|
||||
|
||||
#import "NSObject+RZDataBinding.h"
|
||||
|
||||
static NSString* const kRZDBCoalesceStorageKey = @"RZDBCoalesce";
|
||||
|
||||
#pragma mark - RZDBNotification interface
|
||||
|
||||
@interface RZDBNotification : NSObject
|
||||
|
||||
@property (weak, nonatomic) id target;
|
||||
@property (assign, nonatomic) SEL action;
|
||||
|
||||
@property (strong, nonatomic) NSMutableDictionary *changeDict;
|
||||
|
||||
+ (instancetype)notificationWithInvocation:(NSInvocation *)invocation;
|
||||
|
||||
- (void)send;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - RZDBCoalesceProxy interface
|
||||
|
||||
@interface RZDBCoalesceProxy : NSProxy
|
||||
|
||||
@property (assign, nonatomic) __unsafe_unretained id representedObject;
|
||||
|
||||
+ (instancetype)proxyForObject:(id)object;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - RZDBCoalesce private interface
|
||||
|
||||
@interface RZDBCoalesce ()
|
||||
|
||||
@property (assign, nonatomic) NSInteger beginCount;
|
||||
@property (strong, nonatomic, readonly) NSMutableArray *notifications;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - RZDBCoalesce implementation
|
||||
|
||||
@implementation RZDBCoalesce
|
||||
|
||||
+ (void)begin
|
||||
{
|
||||
RZDBCoalesce *current = [self currentCoalesce];
|
||||
|
||||
if ( current == nil ) {
|
||||
[self setCurrentCoalesce:[[self alloc] init]];
|
||||
}
|
||||
else {
|
||||
current.beginCount++;
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)commit
|
||||
{
|
||||
RZDBCoalesce *current = [self currentCoalesce];
|
||||
current.beginCount--;
|
||||
|
||||
if ( current.beginCount == 0 ) {
|
||||
[self setCurrentCoalesce:nil];
|
||||
[current.notifications enumerateObjectsUsingBlock:^(RZDBNotification *notification, NSUInteger idx, BOOL *stop) {
|
||||
[notification send];
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)coalesceBlock:(void (^)())coalesceBlock
|
||||
{
|
||||
NSParameterAssert(coalesceBlock);
|
||||
|
||||
[RZDBCoalesce begin];
|
||||
coalesceBlock();
|
||||
[RZDBCoalesce commit];
|
||||
}
|
||||
|
||||
#pragma mark - private methods
|
||||
|
||||
+ (RZDBCoalesce *)currentCoalesce
|
||||
{
|
||||
return [NSThread currentThread].threadDictionary[kRZDBCoalesceStorageKey];
|
||||
}
|
||||
|
||||
+ (void)setCurrentCoalesce:(RZDBCoalesce *)current
|
||||
{
|
||||
if ( current != nil ) {
|
||||
[NSThread currentThread].threadDictionary[kRZDBCoalesceStorageKey] = current;
|
||||
}
|
||||
else {
|
||||
[[NSThread currentThread].threadDictionary removeObjectForKey:kRZDBCoalesceStorageKey];
|
||||
}
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
self = [super init];
|
||||
if ( self ) {
|
||||
_beginCount = 1;
|
||||
_notifications = [NSMutableArray array];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)addNotification:(RZDBNotification *)notification
|
||||
{
|
||||
NSUInteger existingIdx = [self.notifications indexOfObjectPassingTest:^BOOL(RZDBNotification *existing, NSUInteger idx, BOOL *stop) {
|
||||
return [notification isEqual:existing];
|
||||
}];
|
||||
|
||||
if ( existingIdx != NSNotFound ) {
|
||||
RZDBNotification *existing = self.notifications[existingIdx];
|
||||
|
||||
if ( notification.changeDict[kRZDBChangeKeyNew] != nil ) {
|
||||
existing.changeDict[kRZDBChangeKeyNew] = notification.changeDict[kRZDBChangeKeyNew];
|
||||
}
|
||||
else {
|
||||
[existing.changeDict removeObjectForKey:kRZDBChangeKeyNew];
|
||||
}
|
||||
}
|
||||
else {
|
||||
[self.notifications addObject:notification];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - RZDBNotification implementation
|
||||
|
||||
@implementation RZDBNotification
|
||||
|
||||
+ (instancetype)notificationWithInvocation:(NSInvocation *)invocation
|
||||
{
|
||||
RZDBNotification *notification = nil;
|
||||
|
||||
NSMethodSignature *methodSig = invocation.methodSignature;
|
||||
|
||||
// rzdb callbacks must have void return type, and
|
||||
// if there are any arguments, the first and only argument must be a dictionary
|
||||
if ( methodSig.methodReturnLength == 0 && (methodSig.numberOfArguments == 2 || methodSig.numberOfArguments == 3) ) {
|
||||
notification = [[self alloc] init];
|
||||
notification.target = invocation.target;
|
||||
notification.action = invocation.selector;
|
||||
|
||||
if ( methodSig.numberOfArguments == 3 && strcmp([methodSig getArgumentTypeAtIndex:2], @encode(id)) == 0 ) {
|
||||
__unsafe_unretained id arg1;
|
||||
[invocation getArgument:&arg1 atIndex:2];
|
||||
|
||||
if ( [arg1 isKindOfClass:[NSDictionary class]] ) {
|
||||
notification.changeDict = [arg1 mutableCopy];
|
||||
}
|
||||
else {
|
||||
notification = nil;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return notification;
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(id)object
|
||||
{
|
||||
BOOL equal = [super isEqual:object];
|
||||
|
||||
if ( !equal && [object isKindOfClass:[RZDBNotification class]] ) {
|
||||
RZDBNotification *other = (RZDBNotification *)object;
|
||||
|
||||
equal = (self.target == other.target) &&
|
||||
(self.action == other.action) &&
|
||||
(self.changeDict == other.changeDict ||
|
||||
(self.changeDict[kRZDBChangeKeyObject] == other.changeDict[kRZDBChangeKeyObject] &&
|
||||
[self.changeDict[kRZDBChangeKeyKeyPath] isEqualToString:other.changeDict[kRZDBChangeKeyKeyPath]]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return equal;
|
||||
}
|
||||
|
||||
- (void)send
|
||||
{
|
||||
if ( self.target != nil && self.action != NULL ) {
|
||||
if ( self.changeDict != nil ) {
|
||||
((void(*)(id, SEL, NSDictionary *))objc_msgSend)(self.target, self.action, [self.changeDict copy]);
|
||||
}
|
||||
else {
|
||||
((void(*)(id, SEL))objc_msgSend)(self.target, self.action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - NSObject+RZDBCoalesce implementation
|
||||
|
||||
@implementation NSObject (RZDBCoalesce)
|
||||
|
||||
- (id)rz_coalesceProxy
|
||||
{
|
||||
@synchronized (self) {
|
||||
id proxy = objc_getAssociatedObject(self, _cmd);
|
||||
|
||||
if ( proxy == nil ) {
|
||||
proxy = [RZDBCoalesceProxy proxyForObject:self];
|
||||
objc_setAssociatedObject(self, _cmd, proxy, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
|
||||
return proxy;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - RZDBCoalesceProxy implementation
|
||||
|
||||
@implementation RZDBCoalesceProxy
|
||||
|
||||
+ (instancetype)proxyForObject:(id)object
|
||||
{
|
||||
RZDBCoalesceProxy *proxy = [self alloc];
|
||||
proxy.representedObject = object;
|
||||
|
||||
return proxy;
|
||||
}
|
||||
|
||||
- (Class)class
|
||||
{
|
||||
return [self.representedObject class];
|
||||
}
|
||||
|
||||
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel
|
||||
{
|
||||
return [self.representedObject methodSignatureForSelector:sel];
|
||||
}
|
||||
|
||||
- (void)forwardInvocation:(NSInvocation *)invocation
|
||||
{
|
||||
invocation.target = self.representedObject;
|
||||
|
||||
RZDBCoalesce *currentCoalesce = [RZDBCoalesce currentCoalesce];
|
||||
|
||||
if ( currentCoalesce != nil ) {
|
||||
// notificaton will be non-nil for a valid RZDataBinding callback
|
||||
RZDBNotification *notification = [RZDBNotification notificationWithInvocation:invocation];
|
||||
|
||||
if ( notification != nil ) {
|
||||
[currentCoalesce addNotification:notification];
|
||||
}
|
||||
else {
|
||||
[invocation invoke];
|
||||
}
|
||||
}
|
||||
else {
|
||||
[invocation invoke];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)doesNotRecognizeSelector:(SEL)aSelector
|
||||
{
|
||||
[self.representedObject doesNotRecognizeSelector:aSelector];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
103
Example/Pods/RZDataBinding/RZDataBinding/RZDBMacros.h
generated
Normal file
103
Example/Pods/RZDataBinding/RZDataBinding/RZDBMacros.h
generated
Normal file
@ -0,0 +1,103 @@
|
||||
//
|
||||
// RZDBMacros.h
|
||||
//
|
||||
// Created by Rob Visentin on 3/18/15.
|
||||
|
||||
// Copyright 2014 Raizlabs and other contributors
|
||||
// http://raizlabs.com/
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#ifndef __RZDBMacros__
|
||||
#define __RZDBMacros__
|
||||
|
||||
////////////////////////////////////////
|
||||
//// ////
|
||||
//// Logging ////
|
||||
//// ////
|
||||
////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* The method that should be used to log errors in RZDataBinding that are non-fatal,
|
||||
* but may be useful in debugging. You might choose for example to `#define RZDBLog DDLogInfo`.
|
||||
* The method defined must take exactly two parameters, a format string, and a variable list of arguments.
|
||||
* By default, log messages are sent using NSLog.
|
||||
*/
|
||||
#ifndef RZDBLog
|
||||
#define RZDBLog NSLog
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////
|
||||
//// ////
|
||||
//// Key Path creation Macros ////
|
||||
//// ////
|
||||
////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Convenience macros for creating keypaths. An invalid keypath will throw a compile-time error when compiling in debug mode.
|
||||
*
|
||||
* The first parameter of these macros is used only for compile-time validation of the keypath.
|
||||
*
|
||||
* @return An NSString containing the keypath.
|
||||
*
|
||||
* @example RZDB_KP(NSObject, description.length) -> @"description.length"
|
||||
* RZDB_KP_OBJ(MyLabel, text) -> @"text"
|
||||
* RZDB_KP_SELF(user.firstName) -> @"user.firstName"
|
||||
*/
|
||||
#if DEBUG
|
||||
#define RZDB_KP(Classname, keypath) ({\
|
||||
Classname *_rzdb_keypath_obj; \
|
||||
__unused __typeof(_rzdb_keypath_obj.keypath) _rzdb_keypath_prop; \
|
||||
@#keypath; \
|
||||
})
|
||||
|
||||
#define RZDB_KP_OBJ(object, keypath) ({\
|
||||
__typeof(object) _rzdb_keypath_obj; \
|
||||
__unused __typeof(_rzdb_keypath_obj.keypath) _rzdb_keypath_prop; \
|
||||
@#keypath; \
|
||||
})
|
||||
|
||||
#define RZDB_KP_PROTOCOL(ProtocolName, keypath) ({\
|
||||
id<ProtocolName> _rzdb_keypath_obj; \
|
||||
__unused __typeof(_rzdb_keypath_obj.keypath) _rzdb_keypath_prop; \
|
||||
@#keypath; \
|
||||
})
|
||||
#else
|
||||
#define RZDB_KP(Classname, keypath) (@#keypath)
|
||||
#define RZDB_KP_OBJ(self, keypath) (@#keypath)
|
||||
#define RZDB_KP_PROTOCOL(ProtocolName, keypath) (@#keypath)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @note This macro will implicitly retain self from within blocks while running in debug mode.
|
||||
* The safe way to generate a keypath on self from within a block
|
||||
* is to define a weak reference to self outside the block, and then use RZDB_KP_OBJ(weakSelf, keypath).
|
||||
*/
|
||||
#define RZDB_KP_SELF(keypath) RZDB_KP_OBJ(self, keypath)
|
||||
|
||||
/**
|
||||
* Concatenate two keypath strings.
|
||||
*
|
||||
* keypath1 and keypath2 must be NSStrings like, for example, the ones created by the other RZDB keypath generation macros.
|
||||
* The result is another NSString concatenating the two keypaths, but there is no implicit check that the key path exists.
|
||||
*/
|
||||
#define RZDB_KP_CONCAT(keypath1, keypath2) [keypath1 stringByAppendingFormat:@".%@", keypath2]
|
||||
|
||||
#endif /** __RZDBMacros__ defined */
|
||||
81
Example/Pods/RZDataBinding/RZDataBinding/RZDBTransforms.h
generated
Normal file
81
Example/Pods/RZDataBinding/RZDataBinding/RZDBTransforms.h
generated
Normal file
@ -0,0 +1,81 @@
|
||||
//
|
||||
// RZDataBinding.h
|
||||
//
|
||||
// Created by Rob Visentin on 4/7/15.
|
||||
|
||||
// Copyright 2014 Raizlabs and other contributors
|
||||
// http://raizlabs.com/
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#pragma mark - Definitions
|
||||
|
||||
/**
|
||||
* A transform that takes a value as a parameter and returns an object.
|
||||
*
|
||||
* @param value The value that just changed on a foreign object for a bound key path.
|
||||
*
|
||||
* @return The value to set for the bound key. Ideally the returned value should depend solely on the input value.
|
||||
*/
|
||||
typedef id (^RZDBKeyBindingTransform)(id value);
|
||||
|
||||
#pragma mark - Convenience Constants
|
||||
|
||||
/**
|
||||
* If value is nil, returns @(0), otherwise returns value.
|
||||
*/
|
||||
OBJC_EXTERN RZDBKeyBindingTransform const kRZDBNilToZeroTransform;
|
||||
|
||||
/**
|
||||
* If value is nil, returns @(1), otherwise returns value.
|
||||
*/
|
||||
OBJC_EXTERN RZDBKeyBindingTransform const kRZDBNilToOneTransform;
|
||||
|
||||
/**
|
||||
* If value is nil, returns NSValue with CGSizeZero, otherwise returns value.
|
||||
*/
|
||||
OBJC_EXTERN RZDBKeyBindingTransform const kRZDBNilToCGSizeZeroTransform;
|
||||
|
||||
/**
|
||||
* If value is nil, returns NSValue with CGRectZero, otherwise returns value.
|
||||
*/
|
||||
OBJC_EXTERN RZDBKeyBindingTransform const kRZDBNilToCGRectZeroTransform;
|
||||
|
||||
/**
|
||||
* If value is nil, returns NSValue with CGRectNull, otherwise returns value.
|
||||
*/
|
||||
OBJC_EXTERN RZDBKeyBindingTransform const kRZDBNilToCGRectNullTransform;
|
||||
|
||||
/**
|
||||
* Returns @(![value boolValue])
|
||||
*/
|
||||
OBJC_EXTERN RZDBKeyBindingTransform const kRZDBLogicalNegateTransform;
|
||||
|
||||
/**
|
||||
* Returns @(1.0 - [value doubleValue])
|
||||
*/
|
||||
OBJC_EXTERN RZDBKeyBindingTransform const kRZDBOneMinusTransform;
|
||||
|
||||
/**
|
||||
* Returns @(~[value longLongValue])
|
||||
*/
|
||||
OBJC_EXTERN RZDBKeyBindingTransform const kRZDBBitwiseComplementTransform;
|
||||
71
Example/Pods/RZDataBinding/RZDataBinding/RZDBTransforms.m
generated
Normal file
71
Example/Pods/RZDataBinding/RZDataBinding/RZDBTransforms.m
generated
Normal file
@ -0,0 +1,71 @@
|
||||
//
|
||||
// RZDataBinding.m
|
||||
//
|
||||
// Created by Rob Visentin on 4/7/15.
|
||||
|
||||
// Copyright 2014 Raizlabs and other contributors
|
||||
// http://raizlabs.com/
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#import <CoreGraphics/CGGeometry.h>
|
||||
|
||||
#import "RZDBTransforms.h"
|
||||
|
||||
RZDBKeyBindingTransform const kRZDBNilToZeroTransform = ^(id value) {
|
||||
return (value == nil) ? @(0) : value;
|
||||
};
|
||||
|
||||
RZDBKeyBindingTransform const kRZDBNilToOneTransform = ^(id value) {
|
||||
return (value == nil) ? @(1) : value;
|
||||
};
|
||||
|
||||
RZDBKeyBindingTransform const kRZDBNilToCGSizeZeroTransform = ^(id value) {
|
||||
if ( value == nil ) {
|
||||
value = [NSValue valueWithBytes:&CGSizeZero objCType:@encode(CGSize)];
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
RZDBKeyBindingTransform const kRZDBNilToCGRectZeroTransform = ^(id value) {
|
||||
if ( value == nil ) {
|
||||
value = [NSValue valueWithBytes:&CGRectZero objCType:@encode(CGRect)];
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
RZDBKeyBindingTransform const kRZDBNilToCGRectNullTransform = ^(id value) {
|
||||
if ( value == nil ) {
|
||||
value = [NSValue valueWithBytes:&CGRectNull objCType:@encode(CGRect)];
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
RZDBKeyBindingTransform const kRZDBLogicalNegateTransform = ^(id value) {
|
||||
return @(![value boolValue]);
|
||||
};
|
||||
|
||||
RZDBKeyBindingTransform const kRZDBOneMinusTransform = ^(id value) {
|
||||
return @(1.0 - [value doubleValue]);
|
||||
};
|
||||
|
||||
RZDBKeyBindingTransform const kRZDBBitwiseComplementTransform = ^(id value) {
|
||||
return @(~[value longLongValue]);
|
||||
};
|
||||
31
Example/Pods/RZDataBinding/RZDataBinding/RZDataBinding.h
generated
Normal file
31
Example/Pods/RZDataBinding/RZDataBinding/RZDataBinding.h
generated
Normal file
@ -0,0 +1,31 @@
|
||||
//
|
||||
// RZDataBinding.h
|
||||
//
|
||||
// Created by Rob Visentin on 4/7/15.
|
||||
|
||||
// Copyright 2014 Raizlabs and other contributors
|
||||
// http://raizlabs.com/
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#import "RZDBMacros.h"
|
||||
#import "RZDBTransforms.h"
|
||||
#import "RZDBCoalesce.h"
|
||||
#import "NSObject+RZDataBinding.h"
|
||||
@ -1,7 +1,6 @@
|
||||
FRAMEWORK_SEARCH_PATHS = $(inherited) "$(PLATFORM_DIR)/Developer/Library/Frameworks"
|
||||
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
|
||||
HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Public"
|
||||
HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/Expecta+Snapshots" "${PODS_ROOT}/Headers/Public"
|
||||
OTHER_LDFLAGS = -framework "Foundation" -framework "XCTest"
|
||||
PODS_ROOT = ${SRCROOT}
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
|
||||
SKIP_INSTALL = YES
|
||||
@ -7,7 +7,7 @@
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
|
||||
<string>org.cocoapods.${PRODUCT_NAME:rfc1034identifier}</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
@ -15,7 +15,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2.0.0</string>
|
||||
<string>3.0.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
ENABLE_BITCODE = NO
|
||||
FRAMEWORK_SEARCH_PATHS = $(inherited) "$(PLATFORM_DIR)/Developer/Library/Frameworks"
|
||||
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
|
||||
HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Public"
|
||||
HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/Expecta" "${PODS_ROOT}/Headers/Public"
|
||||
OTHER_LDFLAGS = -framework "Foundation" -framework "XCTest"
|
||||
PODS_ROOT = ${SRCROOT}
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
|
||||
SKIP_INSTALL = YES
|
||||
@ -7,7 +7,7 @@
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
|
||||
<string>org.cocoapods.${PRODUCT_NAME:rfc1034identifier}</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
ENABLE_BITCODE = NO
|
||||
FRAMEWORK_SEARCH_PATHS = $(inherited) "$(PLATFORM_DIR)/Developer/Library/Frameworks"
|
||||
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
|
||||
HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Public"
|
||||
HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/FBSnapshotTestCase" "${PODS_ROOT}/Headers/Public"
|
||||
OTHER_LDFLAGS = -framework "Foundation" -framework "QuartzCore" -framework "UIKit" -framework "XCTest"
|
||||
OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
|
||||
PODS_ROOT = ${SRCROOT}
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
|
||||
SKIP_INSTALL = YES
|
||||
@ -7,7 +7,7 @@
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
|
||||
<string>org.cocoapods.${PRODUCT_NAME:rfc1034identifier}</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
@ -15,7 +15,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2.0.7</string>
|
||||
<string>2.1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user