├── Tests ├── PSTDelegateExample │ ├── en.lproj │ │ └── InfoPlist.strings │ ├── PSTAppDelegate.h │ ├── PSTDelegateExample-Prefix.pch │ ├── main.m │ ├── PSTExampleDelegate.h │ ├── PSTAppDelegate.m │ ├── Images.xcassets │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ └── LaunchImage.launchimage │ │ │ └── Contents.json │ └── PSTDelegateExample-Info.plist ├── PSTDelegateExampleTests │ ├── en.lproj │ │ └── InfoPlist.strings │ ├── PSTDelegateExampleTests-Info.plist │ └── PSTDelegateExampleTests.m └── PSTDelegateExample.xcodeproj │ └── project.pbxproj ├── .gitignore ├── README.md ├── LICENSE ├── PSTDelegateProxy.h └── PSTDelegateProxy.m /Tests/PSTDelegateExample/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Tests/PSTDelegateExampleTests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | .DS_Store 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | *.xcworkspace 13 | !default.xcworkspace 14 | xcuserdata 15 | profile 16 | *.moved-aside 17 | DerivedData 18 | .idea/ 19 | -------------------------------------------------------------------------------- /Tests/PSTDelegateExample/PSTAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // PSTAppDelegate.h 3 | // PSTDelegateExample 4 | // 5 | // Created by Peter Steinberger on 30/07/13. 6 | // Copyright (c) 2013 Peter Steinberger. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface PSTAppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Tests/PSTDelegateExample/PSTDelegateExample-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #import 8 | 9 | #ifndef __IPHONE_3_0 10 | #warning "This project uses features only available in iOS SDK 3.0 and later." 11 | #endif 12 | 13 | #ifdef __OBJC__ 14 | #import 15 | #import 16 | #endif 17 | -------------------------------------------------------------------------------- /Tests/PSTDelegateExample/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // PSTDelegateExample 4 | // 5 | // Created by Peter Steinberger on 30/07/13. 6 | // Copyright (c) 2013 Peter Steinberger. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "PSTAppDelegate.h" 12 | 13 | int main(int argc, char * argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([PSTAppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Tests/PSTDelegateExample/PSTExampleDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // PSTExampleDelegate.h 3 | // PSTDelegateExample 4 | // 5 | // Created by Peter Steinberger on 30/07/13. 6 | // Copyright (c) 2013 Peter Steinberger. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @protocol PSTExampleDelegate 12 | 13 | @optional 14 | 15 | - (void)exampleDelegateCalledWithString:(NSString *)string; 16 | 17 | - (BOOL)exampleDelegateThatReturnsBOOL; 18 | 19 | - (BOOL)exampleDelegateThatReturnsBOOLAndIsImplemented; 20 | 21 | @property (nonatomic, assign, readonly) BOOL delegateProperty; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /Tests/PSTDelegateExample/PSTAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // PSTAppDelegate.m 3 | // PSTDelegateExample 4 | // 5 | // Created by Peter Steinberger on 30/07/13. 6 | // Copyright (c) 2013 Peter Steinberger. All rights reserved. 7 | // 8 | 9 | #import "PSTAppDelegate.h" 10 | 11 | @implementation PSTAppDelegate 12 | 13 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 14 | { 15 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 16 | // Override point for customization after application launch. 17 | self.window.backgroundColor = [UIColor whiteColor]; 18 | [self.window makeKeyAndVisible]; 19 | return YES; 20 | } 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /Tests/PSTDelegateExampleTests/PSTDelegateExampleTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | com.petersteinberger.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | PSTDelegateProxy 2 | ================ 3 | 4 | A simple proxy that forwards optional methods to delegates - less boilerplate in your code! 5 | 6 | When calling optional delegates, the regular pattern is to check using respondsToSelector:, then actually call the method. This is straightforward and easy to understand: 7 | 8 | 9 | ``` objective-c 10 | id delegate = self.delegate; 11 | if ([delegate respondsToSelector:@selector(resizableViewDidBeginEditing:)]) { 12 | [delegate resizableViewDidBeginEditing:self]; 13 | } 14 | ``` 15 | 16 | What we really want is something like this: 17 | 18 | ``` objective-c 19 | [self.delegateProxy resizableViewDidBeginEditing:self]; 20 | ``` 21 | 22 | Read more on my blog: [Smart Proxy Delegation](http://petersteinberger.com/blog/2013/smart-proxy-delegation/) 23 | 24 | 25 | License 26 | ======= 27 | MIT License. -------------------------------------------------------------------------------- /Tests/PSTDelegateExample/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "40x40", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "60x60", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "ipad", 20 | "size" : "29x29", 21 | "scale" : "1x" 22 | }, 23 | { 24 | "idiom" : "ipad", 25 | "size" : "29x29", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "ipad", 30 | "size" : "40x40", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "40x40", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "76x76", 41 | "scale" : "1x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "76x76", 46 | "scale" : "2x" 47 | } 48 | ], 49 | "info" : { 50 | "version" : 1, 51 | "author" : "xcode" 52 | } 53 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Peter Steinberger 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Tests/PSTDelegateExample/Images.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "orientation" : "portrait", 5 | "idiom" : "iphone", 6 | "extent" : "full-screen", 7 | "minimum-system-version" : "7.0", 8 | "scale" : "2x" 9 | }, 10 | { 11 | "orientation" : "portrait", 12 | "idiom" : "iphone", 13 | "subtype" : "retina4", 14 | "extent" : "full-screen", 15 | "minimum-system-version" : "7.0", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "orientation" : "portrait", 20 | "idiom" : "ipad", 21 | "extent" : "full-screen", 22 | "minimum-system-version" : "7.0", 23 | "scale" : "1x" 24 | }, 25 | { 26 | "orientation" : "landscape", 27 | "idiom" : "ipad", 28 | "extent" : "full-screen", 29 | "minimum-system-version" : "7.0", 30 | "scale" : "1x" 31 | }, 32 | { 33 | "orientation" : "portrait", 34 | "idiom" : "ipad", 35 | "extent" : "full-screen", 36 | "minimum-system-version" : "7.0", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "orientation" : "landscape", 41 | "idiom" : "ipad", 42 | "extent" : "full-screen", 43 | "minimum-system-version" : "7.0", 44 | "scale" : "2x" 45 | } 46 | ], 47 | "info" : { 48 | "version" : 1, 49 | "author" : "xcode" 50 | } 51 | } -------------------------------------------------------------------------------- /Tests/PSTDelegateExample/PSTDelegateExample-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | com.petersteinberger.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /PSTDelegateProxy.h: -------------------------------------------------------------------------------- 1 | // 2 | // PSTDelegateProxy.h 3 | // 4 | // Copyright (c) 2013 Peter Steinberger (http://petersteinberger.com) 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | #import 24 | 25 | // Add this define into your implementation to save the delegate into the delegate proxy. 26 | // You will also require an internal declaration as follows: 27 | // @property (nonatomic, strong) id delegateProxy; 28 | #define PST_DELEGATE_PROXY_CUSTOM(protocolname, GETTER, SETTER) \ 29 | - (id)GETTER { return ((PSTDelegateProxy *)self.GETTER##Proxy).delegate; } \ 30 | - (void)SETTER:(id)delegate { self.GETTER##Proxy = delegate ? (id)[[PSTDelegateProxy alloc] initWithDelegate:delegate conformingToProtocol:@protocol(protocolname) defaultReturnValue:nil] : nil; } 31 | 32 | #define PST_DELEGATE_PROXY(protocolname) PST_DELEGATE_PROXY_CUSTOM(protocolname, delegate, setDelegate) 33 | 34 | // Forwards calls to a delegate. Uses modern message forwarding with almost no runtime overhead. 35 | // Works for optional and requred methods. Won't work for class methods. 36 | @interface PSTDelegateProxy : NSProxy 37 | 38 | // Designated initializer. `delegate` can be nil. 39 | // `returnValue` will unbox on method signatures that return a primitive number (e.g. @YES) 40 | // Method signatures that don't match the unboxed type in `returnValue` will be ignored. 41 | - (id)initWithDelegate:(id)delegate conformingToProtocol:(Protocol *)protocol defaultReturnValue:(NSValue *)returnValue; 42 | 43 | // Returns an object that will return `defaultValue` for methods that return an primitive value type. 44 | // Method signatures that don't match the unboxed type in `returnValue` will be ignored. 45 | - (instancetype)copyThatDefaultsTo:(NSValue *)defaultValue; 46 | - (instancetype)copyThatDefaultsToYES; 47 | 48 | // The internal (weak) delegate. 49 | @property (nonatomic, weak, readonly) id delegate; 50 | 51 | // The property we allow calling to. 52 | @property (nonatomic, strong, readonly) Protocol *protocol; 53 | 54 | // The default boxed primitive return value if method isn't implemented. Defaults to nil. 55 | @property (nonatomic, strong, readonly) NSValue *defaultReturnValue; 56 | 57 | @end 58 | -------------------------------------------------------------------------------- /PSTDelegateProxy.m: -------------------------------------------------------------------------------- 1 | // 2 | // PSTDelegateProxy.m 3 | // 4 | // Copyright (c) 2013 Peter Steinberger (http://petersteinberger.com) 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #import "PSTDelegateProxy.h" 25 | #import 26 | #import 27 | 28 | @implementation PSTDelegateProxy { 29 | CFDictionaryRef _signatures; 30 | } 31 | 32 | /////////////////////////////////////////////////////////////////////////////////////////// 33 | #pragma mark - NSObject 34 | 35 | - (id)initWithDelegate:(id)delegate conformingToProtocol:(Protocol *)protocol defaultReturnValue:(NSValue *)returnValue { 36 | NSParameterAssert(protocol); 37 | NSParameterAssert(returnValue == nil || [returnValue isKindOfClass:NSValue.class]); 38 | if (self) { 39 | _delegate = delegate; 40 | _protocol = protocol; 41 | _defaultReturnValue = returnValue; 42 | } 43 | return self; 44 | } 45 | 46 | - (NSString *)description { 47 | return [NSString stringWithFormat:@"<%@: %p delegate:%@ protocol:%@>", self.class, self, self.delegate, self.protocol]; 48 | } 49 | 50 | - (BOOL)respondsToSelector:(SEL)selector { 51 | return [_delegate respondsToSelector:selector]; 52 | } 53 | 54 | - (id)forwardingTargetForSelector:(SEL)selector { 55 | id delegate = _delegate; 56 | return [delegate respondsToSelector:selector] ? delegate : self; 57 | } 58 | 59 | // Regular message forwarding continues if delegate doesn't respond to selector or is nil. 60 | - (NSMethodSignature *)methodSignatureForSelector:(SEL)selector { 61 | NSMethodSignature *signature = [_delegate methodSignatureForSelector:selector]; 62 | if (!signature) { 63 | if (!_signatures) _signatures = [self methodSignaturesForProtocol:_protocol]; 64 | signature = CFDictionaryGetValue(_signatures, selector); 65 | } 66 | return signature; 67 | } 68 | 69 | - (void)forwardInvocation:(NSInvocation *)invocation { 70 | // Set a default return type if set. 71 | if (_defaultReturnValue && strcmp(_defaultReturnValue.objCType, invocation.methodSignature.methodReturnType) == 0) { 72 | char buffer[invocation.methodSignature.methodReturnLength]; 73 | [_defaultReturnValue getValue:buffer]; 74 | [invocation setReturnValue:&buffer]; 75 | } 76 | } 77 | 78 | /////////////////////////////////////////////////////////////////////////////////////////// 79 | #pragma mark - Public 80 | 81 | - (instancetype)copyThatDefaultsTo:(NSValue *)defaultValue { 82 | return [[self.class alloc] initWithDelegate:_delegate conformingToProtocol:_protocol defaultReturnValue:defaultValue]; 83 | } 84 | 85 | - (instancetype)copyThatDefaultsToYES { 86 | return [self copyThatDefaultsTo:@YES]; 87 | } 88 | 89 | /////////////////////////////////////////////////////////////////////////////////////////// 90 | #pragma mark - Private 91 | 92 | static CFMutableDictionaryRef _protocolCache = nil; 93 | static OSSpinLock _lock = OS_SPINLOCK_INIT; 94 | 95 | - (CFDictionaryRef)methodSignaturesForProtocol:(Protocol *)protocol { 96 | OSSpinLockLock(&_lock); 97 | // Cache lookup 98 | if (!_protocolCache) _protocolCache = CFDictionaryCreateMutable(NULL, 0, NULL, &kCFTypeDictionaryValueCallBacks); 99 | CFDictionaryRef signatureCache = CFDictionaryGetValue(_protocolCache, (__bridge const void *)(protocol)); 100 | 101 | if (!signatureCache) { 102 | // Add protocol methods + derived protocol method definitions into protocolCache. 103 | signatureCache = CFDictionaryCreateMutable(NULL, 0, NULL, &kCFTypeDictionaryValueCallBacks); 104 | [self methodSignaturesForProtocol:protocol inDictionary:(CFMutableDictionaryRef)signatureCache]; 105 | CFDictionarySetValue(_protocolCache, (__bridge const void *)(protocol), signatureCache); 106 | CFRelease(signatureCache); 107 | } 108 | OSSpinLockUnlock(&_lock); 109 | return signatureCache; 110 | } 111 | 112 | - (void)methodSignaturesForProtocol:(Protocol *)protocol inDictionary:(CFMutableDictionaryRef)cache { 113 | void (^enumerateRequiredMethods)(BOOL) = ^(BOOL isRequired) { 114 | unsigned int methodCount; 115 | struct objc_method_description *descr = protocol_copyMethodDescriptionList(protocol, isRequired, YES, &methodCount); 116 | for (NSUInteger idx = 0; idx < methodCount; idx++) { 117 | NSMethodSignature *signature = [NSMethodSignature signatureWithObjCTypes:descr[idx].types]; 118 | CFDictionarySetValue(cache, descr[idx].name, (__bridge const void *)(signature)); 119 | } 120 | free(descr); 121 | }; 122 | // We need to enumerate both required and optional protocol methods. 123 | enumerateRequiredMethods(NO); enumerateRequiredMethods(YES); 124 | 125 | // There might be sub-protocols we need to catch as well. 126 | unsigned int inheritedProtocolCount; 127 | Protocol *__unsafe_unretained* inheritedProtocols = protocol_copyProtocolList(protocol, &inheritedProtocolCount); 128 | for (NSUInteger idx = 0; idx < inheritedProtocolCount; idx++) { 129 | [self methodSignaturesForProtocol:inheritedProtocols[idx] inDictionary:cache]; 130 | } 131 | free(inheritedProtocols); 132 | } 133 | @end 134 | -------------------------------------------------------------------------------- /Tests/PSTDelegateExampleTests/PSTDelegateExampleTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // PSTDelegateExampleTests.m 3 | // PSTDelegateExampleTests 4 | // 5 | // Created by Peter Steinberger on 30/07/13. 6 | // Copyright (c) 2013 Peter Steinberger. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "../PSTDelegateExample/PSTExampleDelegate.h" 11 | #import "../../PSTDelegateProxy.h" 12 | 13 | @interface TestDelegate : NSObject @end 14 | @implementation TestDelegate @end 15 | 16 | @interface PSTDelegateExampleTests : XCTestCase { 17 | NSString *_delegateString; 18 | } 19 | @end 20 | 21 | @protocol ExtendedDelegate 22 | - (void)requiredCall; 23 | @optional 24 | - (void)testCall; 25 | @end 26 | 27 | @protocol NeverCachedProtocol 28 | @optional 29 | - (BOOL)neverCachedCall; 30 | @end 31 | @interface NeverCachedProtocolImpl : NSObject @end 32 | @implementation NeverCachedProtocolImpl @end 33 | 34 | 35 | @interface ExtendedDelegateImpl : NSObject @end 36 | @implementation ExtendedDelegateImpl 37 | - (void)requiredCall {} 38 | @end 39 | 40 | @implementation PSTDelegateExampleTests 41 | 42 | - (void)testDelegateBeingCalled { 43 | _delegateString = nil; 44 | 45 | PSTDelegateProxy *delegateProxy = [[PSTDelegateProxy alloc] initWithDelegate:self conformingToProtocol:@protocol(PSTExampleDelegate) defaultReturnValue:nil]; 46 | [(id)delegateProxy exampleDelegateCalledWithString:@"Test"]; 47 | XCTAssertEqualObjects(_delegateString, @"Test"); 48 | } 49 | 50 | - (void)testDelegateBeingCalledWithReturnValue { 51 | PSTDelegateProxy *delegateProxy = [[PSTDelegateProxy alloc] initWithDelegate:self conformingToProtocol:@protocol(PSTExampleDelegate) defaultReturnValue:nil]; 52 | 53 | BOOL delegateReturnNO = [(id)delegateProxy exampleDelegateThatReturnsBOOL]; 54 | XCTAssertFalse(delegateReturnNO, @"Must be false."); 55 | 56 | BOOL delegateReturnYES = [(id)(delegateProxy.copyThatDefaultsToYES) exampleDelegateThatReturnsBOOL]; 57 | XCTAssertTrue(delegateReturnYES, @"Must be true."); 58 | } 59 | 60 | - (void)testDelegateBeingCalledWithReturnValueThatIsImplemented { 61 | PSTDelegateProxy *delegateProxy = [[PSTDelegateProxy alloc] initWithDelegate:self conformingToProtocol:@protocol(PSTExampleDelegate) defaultReturnValue:nil]; 62 | 63 | BOOL delegateReturnYES = [(id)delegateProxy exampleDelegateThatReturnsBOOLAndIsImplemented]; 64 | XCTAssertTrue(delegateReturnYES, @"Must be true."); 65 | } 66 | 67 | - (void)testRespondsToSelectorForwarding { 68 | PSTDelegateProxy *delegateProxy = [[PSTDelegateProxy alloc] initWithDelegate:self conformingToProtocol:@protocol(PSTExampleDelegate) defaultReturnValue:nil]; 69 | XCTAssertTrue([delegateProxy respondsToSelector:@selector(exampleDelegateCalledWithString:)], @"Must be true."); 70 | XCTAssertFalse([delegateProxy respondsToSelector:@selector(exampleDelegateThatReturnsBOOL)], @"Must be false."); 71 | } 72 | 73 | - (void)testThatProxyCanDealWithNilledOutDelegates { 74 | PSTDelegateProxy *delegateProxy; 75 | @autoreleasepool { 76 | TestDelegate *delegate = [TestDelegate new]; 77 | delegateProxy = [[PSTDelegateProxy alloc] initWithDelegate:delegate conformingToProtocol:@protocol(PSTExampleDelegate) defaultReturnValue:nil]; 78 | } 79 | // At this stage, delegate must be nil 80 | XCTAssertTrue(delegateProxy.delegate == nil, @"Delegate must be nil"); 81 | [(id)delegateProxy exampleDelegateCalledWithString:@"Test"]; 82 | } 83 | 84 | - (void)testThatProxyCanDealWithNilledOutDelegatesAndReturnValues { 85 | PSTDelegateProxy *delegateProxy; 86 | @autoreleasepool { 87 | TestDelegate *delegate = [TestDelegate new]; 88 | delegateProxy = [[PSTDelegateProxy alloc] initWithDelegate:delegate conformingToProtocol:@protocol(PSTExampleDelegate) defaultReturnValue:nil]; 89 | } 90 | // At this stage, delegate must be nil 91 | XCTAssertTrue(delegateProxy.delegate == nil, @"Delegate must be nil"); 92 | 93 | // check that we still return false here. 94 | BOOL returnValue = [(id)delegateProxy exampleDelegateThatReturnsBOOL]; 95 | XCTAssertFalse(returnValue, @"return should be false"); 96 | 97 | // Most important test, chec that this defaults to YES. 98 | BOOL returnValueTrue = [(id)delegateProxy.copyThatDefaultsToYES exampleDelegateThatReturnsBOOL]; 99 | XCTAssertTrue(returnValueTrue, @"return should be true"); 100 | } 101 | 102 | // Ensure caching works. 103 | - (void)testThatProxyCanDealWithNilledOutDelegatesCached { 104 | [self testThatProxyCanDealWithNilledOutDelegates]; 105 | 106 | PSTDelegateProxy *delegateProxy; 107 | @autoreleasepool { 108 | TestDelegate *delegate = [TestDelegate new]; 109 | delegateProxy = [[PSTDelegateProxy alloc] initWithDelegate:delegate conformingToProtocol:@protocol(PSTExampleDelegate) defaultReturnValue:nil]; 110 | } 111 | // At this stage, delegate must be nil 112 | XCTAssertTrue(delegateProxy.delegate == nil, @"Delegate must be nil"); 113 | [(id)delegateProxy exampleDelegateCalledWithString:@"Test"]; 114 | } 115 | 116 | - (void)testDerivedProcols { 117 | PSTDelegateProxy *delegateProxy; 118 | @autoreleasepool { 119 | ExtendedDelegateImpl *impl = [ExtendedDelegateImpl new]; 120 | delegateProxy = [[PSTDelegateProxy alloc] initWithDelegate:impl conformingToProtocol:@protocol(PSTExampleDelegate) defaultReturnValue:nil]; 121 | } 122 | 123 | // At this stage, delegate must be nil 124 | XCTAssertTrue(delegateProxy.delegate == nil, @"Delegate must be nil"); 125 | 126 | 127 | BOOL returnValueTrue = [(id)delegateProxy.copyThatDefaultsToYES exampleDelegateThatReturnsBOOL]; 128 | XCTAssertTrue(returnValueTrue, @"return should be true"); 129 | } 130 | 131 | - (void)testProperty { 132 | PSTDelegateProxy *delegateProxy; 133 | @autoreleasepool { 134 | ExtendedDelegateImpl *impl = [ExtendedDelegateImpl new]; 135 | delegateProxy = [[PSTDelegateProxy alloc] initWithDelegate:impl conformingToProtocol:@protocol(PSTExampleDelegate) defaultReturnValue:nil]; 136 | 137 | [(id)delegateProxy delegateProperty]; 138 | } 139 | 140 | // At this stage, delegate must be nil 141 | XCTAssertTrue(delegateProxy.delegate == nil, @"Delegate must be nil"); 142 | 143 | // Properties are covered with querying protocol_copyMethodDescriptionList. 144 | BOOL returnValueTrue = [(id)delegateProxy.copyThatDefaultsToYES exampleDelegateThatReturnsBOOL]; 145 | XCTAssertTrue(returnValueTrue, @"return should be true"); 146 | } 147 | 148 | - (void)testNeverCachedProperty { 149 | PSTDelegateProxy *delegateProxy = [[PSTDelegateProxy alloc] initWithDelegate:nil conformingToProtocol:@protocol(NeverCachedProtocol) defaultReturnValue:nil]; 150 | 151 | // At this stage, delegate must be nil 152 | XCTAssertTrue(delegateProxy.delegate == nil, @"Delegate must be nil"); 153 | 154 | // Properties are covered with querying protocol_copyMethodDescriptionList. 155 | BOOL returnValueTrue = [(id)delegateProxy.copyThatDefaultsToYES neverCachedCall]; 156 | XCTAssertTrue(returnValueTrue, @"return should be true"); 157 | } 158 | 159 | - (void)testRequiredDelegateCall { 160 | PSTDelegateProxy *delegateProxy; 161 | @autoreleasepool { 162 | ExtendedDelegateImpl *impl = [ExtendedDelegateImpl new]; 163 | delegateProxy = [[PSTDelegateProxy alloc] initWithDelegate:impl conformingToProtocol:@protocol(ExtendedDelegate) defaultReturnValue:nil]; 164 | [(id)delegateProxy requiredCall]; 165 | } 166 | // delegate is nil by now, still needs to work. 167 | [(id)delegateProxy requiredCall]; 168 | } 169 | 170 | /////////////////////////////////////////////////////////////////////////////////////////// 171 | #pragma mark - PSTExampleDelegate 172 | 173 | - (void)exampleDelegateCalledWithString:(NSString *)string { 174 | _delegateString = string; 175 | } 176 | 177 | - (BOOL)exampleDelegateThatReturnsBOOLAndIsImplemented { 178 | return YES; 179 | } 180 | 181 | @end 182 | -------------------------------------------------------------------------------- /Tests/PSTDelegateExample.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 78F49CB417A82F7300B31722 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 78F49CB317A82F7300B31722 /* Foundation.framework */; }; 11 | 78F49CB617A82F7300B31722 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 78F49CB517A82F7300B31722 /* CoreGraphics.framework */; }; 12 | 78F49CB817A82F7300B31722 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 78F49CB717A82F7300B31722 /* UIKit.framework */; }; 13 | 78F49CBE17A82F7300B31722 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 78F49CBC17A82F7300B31722 /* InfoPlist.strings */; }; 14 | 78F49CC017A82F7300B31722 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 78F49CBF17A82F7300B31722 /* main.m */; }; 15 | 78F49CC417A82F7300B31722 /* PSTAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 78F49CC317A82F7300B31722 /* PSTAppDelegate.m */; }; 16 | 78F49CC617A82F7300B31722 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 78F49CC517A82F7300B31722 /* Images.xcassets */; }; 17 | 78F49CCD17A82F7300B31722 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 78F49CCC17A82F7300B31722 /* XCTest.framework */; }; 18 | 78F49CCE17A82F7300B31722 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 78F49CB317A82F7300B31722 /* Foundation.framework */; }; 19 | 78F49CCF17A82F7300B31722 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 78F49CB717A82F7300B31722 /* UIKit.framework */; }; 20 | 78F49CD717A82F7300B31722 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 78F49CD517A82F7300B31722 /* InfoPlist.strings */; }; 21 | 78F49CD917A82F7300B31722 /* PSTDelegateExampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 78F49CD817A82F7300B31722 /* PSTDelegateExampleTests.m */; }; 22 | 78F49CE417A82F8400B31722 /* PSTDelegateProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 78F49CE317A82F8400B31722 /* PSTDelegateProxy.m */; }; 23 | 78F49CE517A82F8400B31722 /* PSTDelegateProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 78F49CE317A82F8400B31722 /* PSTDelegateProxy.m */; }; 24 | /* End PBXBuildFile section */ 25 | 26 | /* Begin PBXContainerItemProxy section */ 27 | 78F49CD017A82F7300B31722 /* PBXContainerItemProxy */ = { 28 | isa = PBXContainerItemProxy; 29 | containerPortal = 78F49CA817A82F7300B31722 /* Project object */; 30 | proxyType = 1; 31 | remoteGlobalIDString = 78F49CAF17A82F7300B31722; 32 | remoteInfo = PSTDelegateExample; 33 | }; 34 | /* End PBXContainerItemProxy section */ 35 | 36 | /* Begin PBXFileReference section */ 37 | 78F49CB017A82F7300B31722 /* PSTDelegateExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PSTDelegateExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 38 | 78F49CB317A82F7300B31722 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 39 | 78F49CB517A82F7300B31722 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 40 | 78F49CB717A82F7300B31722 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 41 | 78F49CBB17A82F7300B31722 /* PSTDelegateExample-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "PSTDelegateExample-Info.plist"; sourceTree = ""; }; 42 | 78F49CBD17A82F7300B31722 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 43 | 78F49CBF17A82F7300B31722 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 44 | 78F49CC117A82F7300B31722 /* PSTDelegateExample-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "PSTDelegateExample-Prefix.pch"; sourceTree = ""; }; 45 | 78F49CC217A82F7300B31722 /* PSTAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PSTAppDelegate.h; sourceTree = ""; }; 46 | 78F49CC317A82F7300B31722 /* PSTAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PSTAppDelegate.m; sourceTree = ""; }; 47 | 78F49CC517A82F7300B31722 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 48 | 78F49CCB17A82F7300B31722 /* PSTDelegateExampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PSTDelegateExampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 49 | 78F49CCC17A82F7300B31722 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; 50 | 78F49CD417A82F7300B31722 /* PSTDelegateExampleTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "PSTDelegateExampleTests-Info.plist"; sourceTree = ""; }; 51 | 78F49CD617A82F7300B31722 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 52 | 78F49CD817A82F7300B31722 /* PSTDelegateExampleTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PSTDelegateExampleTests.m; sourceTree = ""; }; 53 | 78F49CE217A82F8400B31722 /* PSTDelegateProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PSTDelegateProxy.h; path = ../../PSTDelegateProxy.h; sourceTree = ""; }; 54 | 78F49CE317A82F8400B31722 /* PSTDelegateProxy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PSTDelegateProxy.m; path = ../../PSTDelegateProxy.m; sourceTree = ""; }; 55 | 78F49CE617A82FBE00B31722 /* PSTExampleDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PSTExampleDelegate.h; sourceTree = ""; }; 56 | /* End PBXFileReference section */ 57 | 58 | /* Begin PBXFrameworksBuildPhase section */ 59 | 78F49CAD17A82F7300B31722 /* Frameworks */ = { 60 | isa = PBXFrameworksBuildPhase; 61 | buildActionMask = 2147483647; 62 | files = ( 63 | 78F49CB617A82F7300B31722 /* CoreGraphics.framework in Frameworks */, 64 | 78F49CB817A82F7300B31722 /* UIKit.framework in Frameworks */, 65 | 78F49CB417A82F7300B31722 /* Foundation.framework in Frameworks */, 66 | ); 67 | runOnlyForDeploymentPostprocessing = 0; 68 | }; 69 | 78F49CC817A82F7300B31722 /* Frameworks */ = { 70 | isa = PBXFrameworksBuildPhase; 71 | buildActionMask = 2147483647; 72 | files = ( 73 | 78F49CCD17A82F7300B31722 /* XCTest.framework in Frameworks */, 74 | 78F49CCF17A82F7300B31722 /* UIKit.framework in Frameworks */, 75 | 78F49CCE17A82F7300B31722 /* Foundation.framework in Frameworks */, 76 | ); 77 | runOnlyForDeploymentPostprocessing = 0; 78 | }; 79 | /* End PBXFrameworksBuildPhase section */ 80 | 81 | /* Begin PBXGroup section */ 82 | 78F49CA717A82F7300B31722 = { 83 | isa = PBXGroup; 84 | children = ( 85 | 78F49CB917A82F7300B31722 /* PSTDelegateExample */, 86 | 78F49CD217A82F7300B31722 /* PSTDelegateExampleTests */, 87 | 78F49CB217A82F7300B31722 /* Frameworks */, 88 | 78F49CB117A82F7300B31722 /* Products */, 89 | ); 90 | sourceTree = ""; 91 | }; 92 | 78F49CB117A82F7300B31722 /* Products */ = { 93 | isa = PBXGroup; 94 | children = ( 95 | 78F49CB017A82F7300B31722 /* PSTDelegateExample.app */, 96 | 78F49CCB17A82F7300B31722 /* PSTDelegateExampleTests.xctest */, 97 | ); 98 | name = Products; 99 | sourceTree = ""; 100 | }; 101 | 78F49CB217A82F7300B31722 /* Frameworks */ = { 102 | isa = PBXGroup; 103 | children = ( 104 | 78F49CB317A82F7300B31722 /* Foundation.framework */, 105 | 78F49CB517A82F7300B31722 /* CoreGraphics.framework */, 106 | 78F49CB717A82F7300B31722 /* UIKit.framework */, 107 | 78F49CCC17A82F7300B31722 /* XCTest.framework */, 108 | ); 109 | name = Frameworks; 110 | sourceTree = ""; 111 | }; 112 | 78F49CB917A82F7300B31722 /* PSTDelegateExample */ = { 113 | isa = PBXGroup; 114 | children = ( 115 | 78F49CC217A82F7300B31722 /* PSTAppDelegate.h */, 116 | 78F49CC317A82F7300B31722 /* PSTAppDelegate.m */, 117 | 78F49CE217A82F8400B31722 /* PSTDelegateProxy.h */, 118 | 78F49CE317A82F8400B31722 /* PSTDelegateProxy.m */, 119 | 78F49CC517A82F7300B31722 /* Images.xcassets */, 120 | 78F49CBA17A82F7300B31722 /* Supporting Files */, 121 | 78F49CE617A82FBE00B31722 /* PSTExampleDelegate.h */, 122 | ); 123 | path = PSTDelegateExample; 124 | sourceTree = ""; 125 | }; 126 | 78F49CBA17A82F7300B31722 /* Supporting Files */ = { 127 | isa = PBXGroup; 128 | children = ( 129 | 78F49CBB17A82F7300B31722 /* PSTDelegateExample-Info.plist */, 130 | 78F49CBC17A82F7300B31722 /* InfoPlist.strings */, 131 | 78F49CBF17A82F7300B31722 /* main.m */, 132 | 78F49CC117A82F7300B31722 /* PSTDelegateExample-Prefix.pch */, 133 | ); 134 | name = "Supporting Files"; 135 | sourceTree = ""; 136 | }; 137 | 78F49CD217A82F7300B31722 /* PSTDelegateExampleTests */ = { 138 | isa = PBXGroup; 139 | children = ( 140 | 78F49CD817A82F7300B31722 /* PSTDelegateExampleTests.m */, 141 | 78F49CD317A82F7300B31722 /* Supporting Files */, 142 | ); 143 | path = PSTDelegateExampleTests; 144 | sourceTree = ""; 145 | }; 146 | 78F49CD317A82F7300B31722 /* Supporting Files */ = { 147 | isa = PBXGroup; 148 | children = ( 149 | 78F49CD417A82F7300B31722 /* PSTDelegateExampleTests-Info.plist */, 150 | 78F49CD517A82F7300B31722 /* InfoPlist.strings */, 151 | ); 152 | name = "Supporting Files"; 153 | sourceTree = ""; 154 | }; 155 | /* End PBXGroup section */ 156 | 157 | /* Begin PBXNativeTarget section */ 158 | 78F49CAF17A82F7300B31722 /* PSTDelegateExample */ = { 159 | isa = PBXNativeTarget; 160 | buildConfigurationList = 78F49CDC17A82F7300B31722 /* Build configuration list for PBXNativeTarget "PSTDelegateExample" */; 161 | buildPhases = ( 162 | 78F49CAC17A82F7300B31722 /* Sources */, 163 | 78F49CAD17A82F7300B31722 /* Frameworks */, 164 | 78F49CAE17A82F7300B31722 /* Resources */, 165 | ); 166 | buildRules = ( 167 | ); 168 | dependencies = ( 169 | ); 170 | name = PSTDelegateExample; 171 | productName = PSTDelegateExample; 172 | productReference = 78F49CB017A82F7300B31722 /* PSTDelegateExample.app */; 173 | productType = "com.apple.product-type.application"; 174 | }; 175 | 78F49CCA17A82F7300B31722 /* PSTDelegateExampleTests */ = { 176 | isa = PBXNativeTarget; 177 | buildConfigurationList = 78F49CDF17A82F7300B31722 /* Build configuration list for PBXNativeTarget "PSTDelegateExampleTests" */; 178 | buildPhases = ( 179 | 78F49CC717A82F7300B31722 /* Sources */, 180 | 78F49CC817A82F7300B31722 /* Frameworks */, 181 | 78F49CC917A82F7300B31722 /* Resources */, 182 | ); 183 | buildRules = ( 184 | ); 185 | dependencies = ( 186 | 78F49CD117A82F7300B31722 /* PBXTargetDependency */, 187 | ); 188 | name = PSTDelegateExampleTests; 189 | productName = PSTDelegateExampleTests; 190 | productReference = 78F49CCB17A82F7300B31722 /* PSTDelegateExampleTests.xctest */; 191 | productType = "com.apple.product-type.bundle.unit-test"; 192 | }; 193 | /* End PBXNativeTarget section */ 194 | 195 | /* Begin PBXProject section */ 196 | 78F49CA817A82F7300B31722 /* Project object */ = { 197 | isa = PBXProject; 198 | attributes = { 199 | CLASSPREFIX = PST; 200 | LastUpgradeCheck = 0500; 201 | ORGANIZATIONNAME = "Peter Steinberger"; 202 | TargetAttributes = { 203 | 78F49CCA17A82F7300B31722 = { 204 | TestTargetID = 78F49CAF17A82F7300B31722; 205 | }; 206 | }; 207 | }; 208 | buildConfigurationList = 78F49CAB17A82F7300B31722 /* Build configuration list for PBXProject "PSTDelegateExample" */; 209 | compatibilityVersion = "Xcode 3.2"; 210 | developmentRegion = English; 211 | hasScannedForEncodings = 0; 212 | knownRegions = ( 213 | en, 214 | ); 215 | mainGroup = 78F49CA717A82F7300B31722; 216 | productRefGroup = 78F49CB117A82F7300B31722 /* Products */; 217 | projectDirPath = ""; 218 | projectRoot = ""; 219 | targets = ( 220 | 78F49CAF17A82F7300B31722 /* PSTDelegateExample */, 221 | 78F49CCA17A82F7300B31722 /* PSTDelegateExampleTests */, 222 | ); 223 | }; 224 | /* End PBXProject section */ 225 | 226 | /* Begin PBXResourcesBuildPhase section */ 227 | 78F49CAE17A82F7300B31722 /* Resources */ = { 228 | isa = PBXResourcesBuildPhase; 229 | buildActionMask = 2147483647; 230 | files = ( 231 | 78F49CBE17A82F7300B31722 /* InfoPlist.strings in Resources */, 232 | 78F49CC617A82F7300B31722 /* Images.xcassets in Resources */, 233 | ); 234 | runOnlyForDeploymentPostprocessing = 0; 235 | }; 236 | 78F49CC917A82F7300B31722 /* Resources */ = { 237 | isa = PBXResourcesBuildPhase; 238 | buildActionMask = 2147483647; 239 | files = ( 240 | 78F49CD717A82F7300B31722 /* InfoPlist.strings in Resources */, 241 | ); 242 | runOnlyForDeploymentPostprocessing = 0; 243 | }; 244 | /* End PBXResourcesBuildPhase section */ 245 | 246 | /* Begin PBXSourcesBuildPhase section */ 247 | 78F49CAC17A82F7300B31722 /* Sources */ = { 248 | isa = PBXSourcesBuildPhase; 249 | buildActionMask = 2147483647; 250 | files = ( 251 | 78F49CC417A82F7300B31722 /* PSTAppDelegate.m in Sources */, 252 | 78F49CC017A82F7300B31722 /* main.m in Sources */, 253 | 78F49CE417A82F8400B31722 /* PSTDelegateProxy.m in Sources */, 254 | ); 255 | runOnlyForDeploymentPostprocessing = 0; 256 | }; 257 | 78F49CC717A82F7300B31722 /* Sources */ = { 258 | isa = PBXSourcesBuildPhase; 259 | buildActionMask = 2147483647; 260 | files = ( 261 | 78F49CD917A82F7300B31722 /* PSTDelegateExampleTests.m in Sources */, 262 | 78F49CE517A82F8400B31722 /* PSTDelegateProxy.m in Sources */, 263 | ); 264 | runOnlyForDeploymentPostprocessing = 0; 265 | }; 266 | /* End PBXSourcesBuildPhase section */ 267 | 268 | /* Begin PBXTargetDependency section */ 269 | 78F49CD117A82F7300B31722 /* PBXTargetDependency */ = { 270 | isa = PBXTargetDependency; 271 | target = 78F49CAF17A82F7300B31722 /* PSTDelegateExample */; 272 | targetProxy = 78F49CD017A82F7300B31722 /* PBXContainerItemProxy */; 273 | }; 274 | /* End PBXTargetDependency section */ 275 | 276 | /* Begin PBXVariantGroup section */ 277 | 78F49CBC17A82F7300B31722 /* InfoPlist.strings */ = { 278 | isa = PBXVariantGroup; 279 | children = ( 280 | 78F49CBD17A82F7300B31722 /* en */, 281 | ); 282 | name = InfoPlist.strings; 283 | sourceTree = ""; 284 | }; 285 | 78F49CD517A82F7300B31722 /* InfoPlist.strings */ = { 286 | isa = PBXVariantGroup; 287 | children = ( 288 | 78F49CD617A82F7300B31722 /* en */, 289 | ); 290 | name = InfoPlist.strings; 291 | sourceTree = ""; 292 | }; 293 | /* End PBXVariantGroup section */ 294 | 295 | /* Begin XCBuildConfiguration section */ 296 | 78F49CDA17A82F7300B31722 /* Debug */ = { 297 | isa = XCBuildConfiguration; 298 | buildSettings = { 299 | ALWAYS_SEARCH_USER_PATHS = NO; 300 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 301 | CLANG_CXX_LIBRARY = "libc++"; 302 | CLANG_ENABLE_MODULES = YES; 303 | CLANG_ENABLE_OBJC_ARC = YES; 304 | CLANG_WARN_BOOL_CONVERSION = YES; 305 | CLANG_WARN_CONSTANT_CONVERSION = YES; 306 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 307 | CLANG_WARN_EMPTY_BODY = YES; 308 | CLANG_WARN_ENUM_CONVERSION = YES; 309 | CLANG_WARN_INT_CONVERSION = YES; 310 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 311 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 312 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 313 | COPY_PHASE_STRIP = NO; 314 | GCC_C_LANGUAGE_STANDARD = gnu99; 315 | GCC_DYNAMIC_NO_PIC = NO; 316 | GCC_OPTIMIZATION_LEVEL = 0; 317 | GCC_PREPROCESSOR_DEFINITIONS = ( 318 | "DEBUG=1", 319 | "$(inherited)", 320 | ); 321 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 322 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 323 | GCC_WARN_UNDECLARED_SELECTOR = YES; 324 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 325 | GCC_WARN_UNUSED_FUNCTION = YES; 326 | GCC_WARN_UNUSED_VARIABLE = YES; 327 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 328 | ONLY_ACTIVE_ARCH = YES; 329 | SDKROOT = iphoneos; 330 | TARGETED_DEVICE_FAMILY = "1,2"; 331 | }; 332 | name = Debug; 333 | }; 334 | 78F49CDB17A82F7300B31722 /* Release */ = { 335 | isa = XCBuildConfiguration; 336 | buildSettings = { 337 | ALWAYS_SEARCH_USER_PATHS = NO; 338 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 339 | CLANG_CXX_LIBRARY = "libc++"; 340 | CLANG_ENABLE_MODULES = YES; 341 | CLANG_ENABLE_OBJC_ARC = YES; 342 | CLANG_WARN_BOOL_CONVERSION = YES; 343 | CLANG_WARN_CONSTANT_CONVERSION = YES; 344 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 345 | CLANG_WARN_EMPTY_BODY = YES; 346 | CLANG_WARN_ENUM_CONVERSION = YES; 347 | CLANG_WARN_INT_CONVERSION = YES; 348 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 349 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 350 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 351 | COPY_PHASE_STRIP = YES; 352 | ENABLE_NS_ASSERTIONS = NO; 353 | GCC_C_LANGUAGE_STANDARD = gnu99; 354 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 355 | GCC_WARN_UNDECLARED_SELECTOR = YES; 356 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 357 | GCC_WARN_UNUSED_FUNCTION = YES; 358 | GCC_WARN_UNUSED_VARIABLE = YES; 359 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 360 | SDKROOT = iphoneos; 361 | TARGETED_DEVICE_FAMILY = "1,2"; 362 | VALIDATE_PRODUCT = YES; 363 | }; 364 | name = Release; 365 | }; 366 | 78F49CDD17A82F7300B31722 /* Debug */ = { 367 | isa = XCBuildConfiguration; 368 | buildSettings = { 369 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 370 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 371 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 372 | GCC_PREFIX_HEADER = "PSTDelegateExample/PSTDelegateExample-Prefix.pch"; 373 | INFOPLIST_FILE = "PSTDelegateExample/PSTDelegateExample-Info.plist"; 374 | PRODUCT_NAME = "$(TARGET_NAME)"; 375 | WRAPPER_EXTENSION = app; 376 | }; 377 | name = Debug; 378 | }; 379 | 78F49CDE17A82F7300B31722 /* Release */ = { 380 | isa = XCBuildConfiguration; 381 | buildSettings = { 382 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 383 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 384 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 385 | GCC_PREFIX_HEADER = "PSTDelegateExample/PSTDelegateExample-Prefix.pch"; 386 | INFOPLIST_FILE = "PSTDelegateExample/PSTDelegateExample-Info.plist"; 387 | PRODUCT_NAME = "$(TARGET_NAME)"; 388 | WRAPPER_EXTENSION = app; 389 | }; 390 | name = Release; 391 | }; 392 | 78F49CE017A82F7300B31722 /* Debug */ = { 393 | isa = XCBuildConfiguration; 394 | buildSettings = { 395 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/PSTDelegateExample.app/PSTDelegateExample"; 396 | FRAMEWORK_SEARCH_PATHS = ( 397 | "$(SDKROOT)/Developer/Library/Frameworks", 398 | "$(inherited)", 399 | "$(DEVELOPER_FRAMEWORKS_DIR)", 400 | ); 401 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 402 | GCC_PREFIX_HEADER = "PSTDelegateExample/PSTDelegateExample-Prefix.pch"; 403 | GCC_PREPROCESSOR_DEFINITIONS = ( 404 | "DEBUG=1", 405 | "$(inherited)", 406 | ); 407 | INFOPLIST_FILE = "PSTDelegateExampleTests/PSTDelegateExampleTests-Info.plist"; 408 | PRODUCT_NAME = "$(TARGET_NAME)"; 409 | TEST_HOST = "$(BUNDLE_LOADER)"; 410 | WRAPPER_EXTENSION = xctest; 411 | }; 412 | name = Debug; 413 | }; 414 | 78F49CE117A82F7300B31722 /* Release */ = { 415 | isa = XCBuildConfiguration; 416 | buildSettings = { 417 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/PSTDelegateExample.app/PSTDelegateExample"; 418 | FRAMEWORK_SEARCH_PATHS = ( 419 | "$(SDKROOT)/Developer/Library/Frameworks", 420 | "$(inherited)", 421 | "$(DEVELOPER_FRAMEWORKS_DIR)", 422 | ); 423 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 424 | GCC_PREFIX_HEADER = "PSTDelegateExample/PSTDelegateExample-Prefix.pch"; 425 | INFOPLIST_FILE = "PSTDelegateExampleTests/PSTDelegateExampleTests-Info.plist"; 426 | PRODUCT_NAME = "$(TARGET_NAME)"; 427 | TEST_HOST = "$(BUNDLE_LOADER)"; 428 | WRAPPER_EXTENSION = xctest; 429 | }; 430 | name = Release; 431 | }; 432 | /* End XCBuildConfiguration section */ 433 | 434 | /* Begin XCConfigurationList section */ 435 | 78F49CAB17A82F7300B31722 /* Build configuration list for PBXProject "PSTDelegateExample" */ = { 436 | isa = XCConfigurationList; 437 | buildConfigurations = ( 438 | 78F49CDA17A82F7300B31722 /* Debug */, 439 | 78F49CDB17A82F7300B31722 /* Release */, 440 | ); 441 | defaultConfigurationIsVisible = 0; 442 | defaultConfigurationName = Release; 443 | }; 444 | 78F49CDC17A82F7300B31722 /* Build configuration list for PBXNativeTarget "PSTDelegateExample" */ = { 445 | isa = XCConfigurationList; 446 | buildConfigurations = ( 447 | 78F49CDD17A82F7300B31722 /* Debug */, 448 | 78F49CDE17A82F7300B31722 /* Release */, 449 | ); 450 | defaultConfigurationIsVisible = 0; 451 | }; 452 | 78F49CDF17A82F7300B31722 /* Build configuration list for PBXNativeTarget "PSTDelegateExampleTests" */ = { 453 | isa = XCConfigurationList; 454 | buildConfigurations = ( 455 | 78F49CE017A82F7300B31722 /* Debug */, 456 | 78F49CE117A82F7300B31722 /* Release */, 457 | ); 458 | defaultConfigurationIsVisible = 0; 459 | }; 460 | /* End XCConfigurationList section */ 461 | }; 462 | rootObject = 78F49CA817A82F7300B31722 /* Project object */; 463 | } 464 | --------------------------------------------------------------------------------