Created
June 30, 2015 16:17
-
-
Save jlott1/1310c9f1ac1b21c8721e to your computer and use it in GitHub Desktop.
UIView Category for locating the UIViewController container for a UIView AND also getting the property name for a UIView....VERY VERY Useful
This file contains 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
// | |
// UIView+FindUIViewController.h | |
// | |
// Created by Jonathan Lott on 6/30/15. | |
// Copyright (c) 2015 A Lott Of Ideas. All rights reserved. | |
// | |
@interface ClassProperty : NSObject | |
@property (nonatomic, strong) NSString* name; | |
@property (nonatomic, strong) NSString* type; | |
+ (instancetype)propertyWithName:(NSString*)name type:(NSString*)type; | |
@end | |
@interface PropertyUtils : NSObject | |
+ (NSDictionary *)classPropsDictionaryFor:(Class)klass; | |
+ (NSArray*)classPropsFor:(Class)klass; | |
@end | |
@interface NSObject (ClassProps) | |
+ (NSArray *)classProps; | |
+ (NSArray *)classPropsOfType:(Class)klass; | |
@end | |
#import <UIKit/UIKit.h> | |
@interface UIView (FindUIViewController) | |
- (UIViewController *) firstAvailableUIViewController; | |
- (id) traverseResponderChainForUIViewController; | |
- (NSString*)propertyName; | |
@end | |
This file contains 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
// | |
// UIView+FindUIViewController.m | |
// | |
// Created by Jonathan Lott on 6/30/15. | |
// Copyright (c) 2015 A Lott Of Ideas. All rights reserved. | |
// | |
#import "NSObject+ClassProps.h" | |
#import "UIView+FindUIViewController.h" | |
#import "objc/runtime.h" | |
@implementation ClassProperty | |
+ (instancetype)propertyWithName:(NSString*)name type:(NSString*)type | |
{ | |
ClassProperty* prop = [[[self class] alloc] init]; | |
prop.name = name; | |
prop.type = type; | |
return prop; | |
} | |
@end | |
@implementation PropertyUtils | |
static const char *getPropertyType(objc_property_t property) { | |
const char *attributes = property_getAttributes(property); | |
//printf("attributes=%s\n", attributes); | |
char buffer[1 + strlen(attributes)]; | |
strcpy(buffer, attributes); | |
char *state = buffer, *attribute; | |
while ((attribute = strsep(&state, ",")) != NULL) { | |
if (attribute[0] == 'T' && attribute[1] != '@') { | |
// it's a C primitive type: | |
/* | |
if you want a list of what will be returned for these primitives, search online for | |
"objective-c" "Property Attribute Description Examples" | |
apple docs list plenty of examples of what you get for int "i", long "l", unsigned "I", struct, etc. | |
*/ | |
NSString *name = [[NSString alloc] initWithBytes:attribute + 1 length:strlen(attribute) - 1 encoding:NSASCIIStringEncoding]; | |
return (const char *)[name cStringUsingEncoding:NSASCIIStringEncoding]; | |
} | |
else if (attribute[0] == 'T' && attribute[1] == '@' && strlen(attribute) == 2) { | |
// it's an ObjC id type: | |
return "id"; | |
} | |
else if (attribute[0] == 'T' && attribute[1] == '@') { | |
// it's another ObjC object type: | |
NSString *name = [[NSString alloc] initWithBytes:attribute + 3 length:strlen(attribute) - 4 encoding:NSASCIIStringEncoding]; | |
return (const char *)[name cStringUsingEncoding:NSASCIIStringEncoding]; | |
} | |
} | |
return ""; | |
} | |
+ (NSDictionary *)classPropsDictionaryFor:(Class)klass | |
{ | |
if (klass == NULL) { | |
return nil; | |
} | |
NSMutableDictionary *results = [[NSMutableDictionary alloc] init]; | |
unsigned int outCount, i; | |
objc_property_t *properties = class_copyPropertyList(klass, &outCount); | |
for (i = 0; i < outCount; i++) { | |
objc_property_t property = properties[i]; | |
const char *propName = property_getName(property); | |
if(propName) { | |
const char *propType = getPropertyType(property); | |
NSString *propertyName = [NSString stringWithUTF8String:propName]; | |
NSString *propertyType = [NSString stringWithUTF8String:propType]; | |
[results setObject:propertyType forKey:propertyName]; | |
} | |
} | |
free(properties); | |
// returning a copy here to make sure the dictionary is immutable | |
return [NSDictionary dictionaryWithDictionary:results]; | |
} | |
+ (NSArray*)classPropsFor:(Class)klass | |
{ | |
if (klass == NULL) { | |
return nil; | |
} | |
NSMutableArray *results = [[NSMutableArray alloc] init]; | |
unsigned int outCount, i; | |
objc_property_t *properties = class_copyPropertyList(klass, &outCount); | |
for (i = 0; i < outCount; i++) { | |
objc_property_t property = properties[i]; | |
const char *propName = property_getName(property); | |
if(propName) { | |
const char *propType = getPropertyType(property); | |
NSString *propertyName = [NSString stringWithUTF8String:propName]; | |
NSString *propertyType = [NSString stringWithUTF8String:propType]; | |
ClassProperty* prop = [ClassProperty propertyWithName:propertyName type:propertyType]; | |
[results addObject:prop]; | |
} | |
} | |
free(properties); | |
// returning a copy here to make sure it is immutable | |
return [NSArray arrayWithArray:results]; | |
} | |
@end | |
@implementation NSObject (ClassProps) | |
+ (NSArray *)classProps | |
{ | |
return [PropertyUtils classPropsFor:[self class]]; | |
} | |
+ (NSArray *)classPropsOfType:(Class)klass | |
{ | |
NSArray* props = [self classProps]; | |
props = [props filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"type == %@", [klass description]]]; | |
return props; | |
} | |
@end | |
@implementation UIView (FindUIViewController) | |
- (UIViewController *) firstAvailableUIViewController { | |
// convenience function for casting and to "mask" the recursive function | |
return (UIViewController *)[self traverseResponderChainForUIViewController]; | |
} | |
- (id) traverseResponderChainForUIViewController { | |
id nextResponder = [self nextResponder]; | |
if ([nextResponder isKindOfClass:[UIViewController class]]) { | |
return nextResponder; | |
} else if ([nextResponder isKindOfClass:[UIView class]]) { | |
return [nextResponder traverseResponderChainForUIViewController]; | |
} else { | |
return nil; | |
} | |
} | |
- (NSString*)propertyName | |
{ | |
NSString* outletName = self.description; | |
UIViewController* viewController = self.firstAvailableUIViewController; | |
NSArray* outletViews = [[viewController class] classPropsOfType:[self class]]; | |
NSArray* outletNames = [outletViews valueForKey:@"name"]; | |
for(NSString* name in outletNames) | |
{ | |
// grab values for each prop name | |
id value = [viewController valueForKey:name]; | |
if(value == self) | |
{ | |
outletName = name; | |
} | |
} | |
return outletName; | |
} | |
@end | |
@implementation UIViewController (ViewAccess) | |
- (UIViewController*)viewControllerContainingView:(UIView*)view | |
{ | |
return view.firstAvailableUIViewController; | |
} | |
@end | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment