Skip to content

Instantly share code, notes, and snippets.

@jhurliman
Last active August 29, 2015 14:07
Show Gist options
  • Save jhurliman/fe8210d9998dff0f8e3a to your computer and use it in GitHub Desktop.
Save jhurliman/fe8210d9998dff0f8e3a to your computer and use it in GitHub Desktop.
UIViewController+SegueData.m
//
// 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