Skip to content

Instantly share code, notes, and snippets.

@jlott1
Created June 30, 2015 16:17
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jlott1/1310c9f1ac1b21c8721e to your computer and use it in GitHub Desktop.
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
//
// 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
//
// 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