Last active
August 29, 2015 14:07
-
-
Save jhurliman/fe8210d9998dff0f8e3a to your computer and use it in GitHub Desktop.
UIViewController+SegueData.m
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// UIViewController+SegueData.h | |
// SegueDataPassing - Helper method for performing a segue and passing data to | |
// the destination view controller. | |
// | |
// Created by John Hurliman on 10/21/14. | |
// Copyright (c) 2014 John Hurliman. Released under the MIT license. | |
// http://opensource.org/licenses/MIT | |
// | |
#import <UIKit/UIKit.h> | |
@interface UIViewController (SegueData) | |
/** | |
* Getter for the segueData property. This property is set on the destination | |
* UIViewController when calling performSegueWithIdentifier:data:. | |
*/ | |
- (id)segueData; | |
/** | |
* Setter for the segueData property. This is called automatically when calling | |
* performSegueWithIdentifier:data: and generally does not need to called | |
* explicitly. | |
*/ | |
- (void)setSegueData:(id)data; | |
/** | |
* Perform a segue and set the segueData property on the destination | |
* UIViewController to the data value. | |
*/ | |
- (void)performSegueWithIdentifier:(NSString *)identifier data:(id)data; | |
@end | |
// | |
// UIViewController+SegueData.m | |
// SegueDataPassing | |
// | |
// Created by John Hurliman on 10/21/14. | |
// Copyright (c) 2014 John Hurliman. Released under the MIT license. | |
// http://opensource.org/licenses/MIT | |
// | |
#import "UIViewController+SegueData.h" | |
#import <objc/runtime.h> | |
#import <objc/message.h> | |
// Unique identifiers for associated objects | |
static char const * const SegueMethodSwizzledKey = "SegueMethodSwizzledKey"; | |
static char const * const SegueNameKey = "SegueNameKey"; | |
static char const * const SegueDataToPassKey = "SegueDataToPassKey"; | |
static char const * const SegueDataKey = "SegueDataKey"; | |
// Method swizzling helper for replacing prepareForSegue:sender: | |
void MethodSwizzle(Class c, SEL orig, SEL new) { | |
Method origMethod = class_getInstanceMethod(c, orig); | |
Method newMethod = class_getInstanceMethod(c, new); | |
if(class_addMethod(c, orig, method_getImplementation(newMethod), method_getTypeEncoding(newMethod))) | |
class_replaceMethod(c, new, method_getImplementation(origMethod), method_getTypeEncoding(origMethod)); | |
else | |
method_exchangeImplementations(origMethod, newMethod); | |
} | |
@implementation UIViewController (SegueData) | |
- (id)segueData | |
{ | |
return objc_getAssociatedObject(self, SegueDataKey); | |
} | |
- (void)setSegueData:(id)data | |
{ | |
objc_setAssociatedObject(self, SegueDataKey, data, OBJC_ASSOCIATION_RETAIN_NONATOMIC); | |
} | |
- (void)performSegueWithIdentifier:(NSString *)identifier data:(id)data | |
{ | |
// Store the segue name and the data to be passed as instance variables of | |
// the current view controller | |
objc_setAssociatedObject(self, SegueNameKey, identifier, OBJC_ASSOCIATION_RETAIN_NONATOMIC); | |
objc_setAssociatedObject(self, SegueDataToPassKey, data, OBJC_ASSOCIATION_RETAIN_NONATOMIC); | |
// Replace the prepareForSegue:sender: method with our own if we haven't yet | |
NSNumber *swizzled = objc_getAssociatedObject(self, SegueMethodSwizzledKey); | |
if (!swizzled || !swizzled.boolValue) { | |
objc_setAssociatedObject(self, SegueMethodSwizzledKey, @(YES), OBJC_ASSOCIATION_RETAIN_NONATOMIC); | |
MethodSwizzle(UIViewController.class, @selector(prepareForSegue:sender:), @selector(myPrepareForSegue:sender:)); | |
} | |
// Perform the actual segue | |
[self performSegueWithIdentifier:identifier sender:self]; | |
} | |
- (void)myPrepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender | |
{ | |
NSString *segueName = objc_getAssociatedObject(self, SegueNameKey); | |
// Check if this is our segue | |
if ([segue.identifier isEqualToString:segueName]) { | |
UIViewController *dest = segue.destinationViewController; | |
dest.segueData = objc_getAssociatedObject(self, SegueDataToPassKey); | |
// Release temporary pointers | |
objc_setAssociatedObject(self, SegueDataToPassKey, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC); | |
objc_setAssociatedObject(self, SegueNameKey, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC); | |
} | |
// (Unintuitively) calls the original method | |
[self myPrepareForSegue:segue sender:sender]; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment