TO:
iOS开发技巧系列---详解KVC(我告诉你KVC的一切)
DLIntrospection使用
https://github.com/delebedev/DLIntrospection
IOS 高级开发 KVC(一)
IOS 高级开发 KVC(二)
iOS runtime消息转发机制等
看了一些相关文章,还是自己写个备份便以后查询。
很多对象被Apple封装后并没提供太多的属性供开发者使用,比如UITextField,但我们可以通过KVC的方式来修改UITextField的占位文字颜色和字体。
// 修改占位字符的颜色
[_textField setValue:[UIColor greenColor] forKeyPath:@"_placeholderLabel.textColor"];
// 修改占位字符的字体
[_textField setValue:[UIFont boldSystemFontOfSize:18] forKeyPath:@"_placeholderLabel.font"];
// 文字偏移量
_textField.leftView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 0)];
// 设置显示模式为永远显示(默认不显示)
_textField.leftViewMode = UITextFieldViewModeAlways;
效果如下。更多的修改方式可以参考iOS-改变UITextField的占位文字颜色(三种)
当不知道属性名时,推荐使用“NSObject+DLIntrospection”来打印出UITextField的内部变量,这样可以找到原来是“UITextFieldLabel* _placeholderLabel”。
NSArray *tempClasses = [UITextField classes];
NSLog(@"// 打印所有类\n%@",tempClasses);
NSArray *tempProperties = [UITextField properties];
NSLog(@"// 打印属性\n%@",tempProperties);
NSArray *tempInstanceVariables = [UITextField instanceVariables];
NSLog(@"// 内部变量\n%@",tempInstanceVariables);
NSArray *tempClassMethods = [UITextField classMethods];
NSLog(@"// 类方法\n%@",tempClassMethods);
NSArray *tempInstanceMethods = [UITextField instanceMethods];
NSLog(@"// 方法\n%@",tempInstanceMethods);
NSArray *tempProtocols = [UITextField protocols];
NSLog(@"// 遵守的协议\n%@",tempProtocols);
NSDictionary *tempDescriptionForProtocol = [UITextField descriptionForProtocol:@protocol(UITextFieldDelegate)];
NSLog(@"// 自己的协议描述\n%@",tempDescriptionForProtocol);
NSString *tempParentClassHierarchy = [UITextField parentClassHierarchy];
NSLog(@"// 层级关系\n%@",tempParentClassHierarchy);
输出:
这里将每一项都做了输出,主要是想看一下结果会是什么样子。
// 打印所有类
(
AAAbsintheContext,
AAAbsintheSigner,
AAAbsintheSignerContextCache,
AAAccount,
AAAccountManagementUIResponse,
AAAccountManager,
AAAddEmailUIRequest,
AAAppleIDSettingsRequest,
AAAppleTVRequest,
AAAttestationSigner,
AAAuthenticateRequest,
AAAuthenticationResponse,
AAAutoAccountVerifier,
AAAvailabilityRequest,
AAAvailabilityResponse,
AACertificatePinner,
AAChildAccountCreationUIRequest,
AACloudKitDevicesListRequest,
AACloudKitDevicesListResponse,
AACloudKitMigrationStateRequest,
AACloudKitMigrationStateResponse,
AACloudKitStartMigrationRequest,
AACloudKitStartMigrationResponse,
AACompleteEmailVettingRequest,
AACompleteEmailVettingResponse,
AADataclassManager,
AADelegateAccountSetupHelper,
AADevice,
AADeviceInfo,
AADeviceListRequest,
AADeviceListResponse,
AADeviceProvisioningRequest,
AADeviceProvisioningResponse,
AADeviceProvisioningSession,
AAEmailVettin
...共14159个...
)
// 打印属性
<__NSFrozenArrayM 0x60000300fe10>(
@property (atomic, assign, readonly) unsigned long hash,
@property (atomic, assign, readonly) class superclass,
@property (atomic, copy, readonly) NSString* description,
@property (atomic, copy, readonly) NSString* debugDescription,
@property (atomic, assign, readonly) unsigned long hash,
@property (atomic, assign, readonly) class superclass,
@property (atomic, copy, readonly) NSString* description,
@property (atomic, copy, readonly) NSString* debugDescription,
@property (nonatomic, copy) NSString* ab_text,
@property (nonatomic, copy) NSDictionary* ab_textAttributes,
@property (nonatomic, strong, setter=(null)) NSLayoutConstraint* _baselineLayoutConstraint,
@property (nonatomic, strong, setter=(null)) _UIBaselineLayoutStrut* _baselineLayoutLabel,
@property (nonatomic, assign) BOOL _tvUseVibrancy,
@property (nonatomic, strong) UIColor* _tvCustomTextColor,
@property (nonatomic, strong) UIColor* _tvCustomFocusedTextColor,
@property (nonatomic, assign) BOOL _disableTextColorUpdateOnTraitCollectionChange,
@property (nonatomic, strong) _UITextFieldVisualStyle* visualStyle,
@property (atomic, strong) UIView* recentsAccessoryView,
@property (nonatomic, copy) NSString* text,
@property (nonatomic, copy) NSAttributedString* attributedText,
@property (nonatomic, strong) UIColor* textColor,
@property (nonatomic, strong) UIFont* font,
@property (nonatomic, assign) long textAlignment,
@property (nonatomic, assign) long borderStyle,
@property (nonatomic, copy) NSDictionary* defaultTextAttributes,
@property (nonatomic, copy) NSString* placeholder,
@property (nonatomic, copy) NSAttributedString* attributedPlaceholder,
@property (nonatomic, assign) BOOL clearsOnBeginEditing,
@property (nonatomic, assign) BOOL adjustsFontSizeToFitWidth,
@property (nonatomic, assign) double minimumFontSize,
@property (nonatomic, weak) * delegate,
@property (nonatomic, strong) UIImage* background,
@property (nonatomic, strong) UIImage* disabledBackground,
@property (nonatomic, assign, readonly, getter=isEditing) BOOL editing,
@property (nonatomic, assign) BOOL allowsEditingTextAttributes,
@property (nonatomic, copy) NSDictionary* typingAttributes,
@property (nonatomic, assign) long clearButtonMode,
@property (nonatomic, strong) UIView* leftView,
@property (nonatomic, assign) long leftViewMode,
@property (nonatomic, strong) UIView* rightView,
@property (nonatomic, assign) long rightViewMode,
@property (atomic, strong) UIView* inputView,
@property (atomic, strong) UIView* inputAccessoryView,
@property (nonatomic, assign) BOOL clearsOnInsertion,
@property (atomic, assign, readonly) unsigned long hash,
@property (atomic, assign, readonly) class superclass,
@property (atomic, copy, readonly) NSString* description,
@property (atomic, copy, readonly) NSString* debugDescription,
@property (nonatomic, assign) long autocapitalizationType,
@property (nonatomic, assign) long autocorrectionType,
@property (nonatomic, assign) long spellCheckingType,
@property (nonatomic, assign) long smartQuotesType,
@property (nonatomic, assign) long smartDashesType,
@property (nonatomic, assign) long smartInsertDeleteType,
@property (nonatomic, assign) long keyboardType,
@property (nonatomic, assign) long keyboardAppearance,
@property (nonatomic, assign) long returnKeyType,
@property (nonatomic, assign) BOOL enablesReturnKeyAutomatically,
@property (nonatomic, assign, getter=isSecureTextEntry) BOOL secureTextEntry,
@property (nonatomic, copy) NSString* textContentType,
@property (nonatomic, copy) UITextInputPasswordRules* passwordRules,
@property (nonatomic, assign, readonly) BOOL hasText,
@property (nonatomic, copy) NSString* recentInputIdentifier,
@property (nonatomic, assign) {_NSRange=QQ} validTextRange,
@property (nonatomic, copy) NSIndexSet* PINEntrySeparatorIndexes,
@property (nonatomic, assign) {__CFCharacterSet=} * textTrimmingSet,
@property (nonatomic, strong) UIColor* insertionPointColor,
@property (nonatomic, strong) UIColor* selectionBarColor,
@property (nonatomic, strong) UIColor* selectionHighlightColor,
@property (nonatomic, strong) UIImage* selectionDragDotImage,
@property (nonatomic, strong) UIColor* underlineColorForTextAlternatives,
@property (nonatomic, strong) UIColor* underlineColorForSpelling,
@property (nonatomic, assign) unsigned long insertionPointWidth,
@property (nonatomic, assign) int textLoupeVisibility,
@property (nonatomic, assign) int textSelectionBehavior,
@property (nonatomic, assign) id textSuggestionDelegate,
@property (nonatomic, assign) BOOL isSingleLineDocument,
@property (nonatomic, assign) BOOL contentsIsSingleValue,
@property (nonatomic, assign) BOOL hasDefaultContents,
@property (nonatomic, assign) BOOL acceptsPayloads,
@property (nonatomic, assign) BOOL acceptsEmoji,
@property (nonatomic, assign) BOOL acceptsDictationSearchResults,
@property (nonatomic, assign) BOOL forceEnableDictation,
@property (nonatomic, assign) BOOL forceDisableDictation,
@property (nonatomic, assign) BOOL forceDefaultDictationInfo,
@property (nonatomic, assign) long forceDictationKeyboardType,
@property (nonatomic, assign) int emptyContentReturnKeyType,
@property (nonatomic, assign) BOOL returnKeyGoesToNextResponder,
@property (nonatomic, assign) BOOL acceptsFloatingKeyboard,
@property (nonatomic, assign) BOOL acceptsSplitKeyboard,
@property (nonatomic, assign) BOOL displaySecureTextUsingPlainText,
@property (nonatomic, assign) BOOL displaySecureEditsUsingPlainText,
@property (nonatomic, assign) BOOL learnsCorrections,
@property (nonatomic, assign) int shortcutConversionType,
@property (nonatomic, assign) BOOL suppressReturnKeyStyling,
@property (nonatomic, assign) BOOL useInterfaceLanguageForLocalization,
@property (nonatomic, assign) BOOL deferBecomingResponder,
@property (nonatomic, assign) BOOL enablesReturnKeyOnNonWhiteSpaceContent,
@property (nonatomic, copy) NSString* autocorrectionContext,
@property (nonatomic, copy) NSString* responseContext,
@property (nonatomic, strong) UIInputContextHistory* inputContextHistory,
@property (nonatomic, assign) BOOL disableInputBars,
@property (nonatomic, assign) BOOL isCarPlayIdiom,
@property (nonatomic, assign) long textScriptType,
@property (nonatomic, assign) BOOL loadKeyboardsForSiriLanguage,
@property (nonatomic, assign) BOOL disablePrediction,
@property (nonatomic, assign) BOOL hidePrediction,
@property (nonatomic, assign, getter=isDevicePasscodeEntry) BOOL devicePasscodeEntry,
@property (nonatomic, assign, readonly) NSLayoutManager* layoutManager,
@property (nonatomic, assign, readonly) NSTextStorage* textStorage,
@property (nonatomic, assign, readonly) NSTextContainer* textContainer,
@property (nonatomic, assign) long nonEditingLinebreakMode,
@property (nonatomic, assign) BOOL allowsAttachments,
@property (atomic, copy) UITextRange* selectedTextRange,
@property (nonatomic, assign, readonly) UITextRange* markedTextRange,
@property (nonatomic, copy) NSDictionary* markedTextStyle,
@property (nonatomic, assign, readonly) UITextPosition* beginningOfDocument,
@property (nonatomic, assign, readonly) UITextPosition* endOfDocument,
@property (nonatomic, weak) * inputDelegate,
@property (nonatomic, assign, readonly) * tokenizer,
@property (nonatomic, assign, readonly) UIView* textInputView,
@property (nonatomic, assign) long selectionAffinity,
@property (nonatomic, assign, readonly) id insertDictationResultPlaceholder,
@property (nonatomic, weak) * textDragDelegate,
@property (nonatomic, assign, readonly) UIDragInteraction* textDragInteraction,
@property (nonatomic, assign, readonly, getter=isTextDragActive) BOOL textDragActive,
@property (nonatomic, assign) long textDragOptions,
@property (nonatomic, copy) UIPasteConfiguration* pasteConfiguration,
@property (nonatomic, weak) * pasteDelegate,
@property (nonatomic, weak) * textDropDelegate,
@property (nonatomic, assign, readonly) UIDropInteraction* textDropInteraction,
@property (nonatomic, assign, readonly, getter=isTextDropActive) BOOL textDropActive,
@property (nonatomic, assign) {CGPoint=dd} contentOffsetForSameViewDrops,
@property (nonatomic, assign) BOOL adjustsFontForContentSizeCategory
)
// 内部变量
<__NSFrozenArrayM 0x6000030fdaa0>(
long _borderStyle,
double _minimumFontSize,
id _delegate,
UIImage* _background,
UIImage* _disabledBackground,
long _clearButtonMode,
UIView* _leftView,
long _leftViewMode,
UIView* _rightView,
long _rightViewMode,
UIView* _contentCoverView,
long _contentCoverViewMode,
UIView* _backgroundCoverView,
long _backgroundCoverViewMode,
UITextInputTraits* _traits,
UITextInputTraits* _nonAtomTraits,
_UIFullFontSize* _fullFontSize,
{UIEdgeInsets="top"d"left"d"bottom"d"right"d} _padding,
float _progress,
UIButton* _clearButton,
{CGSize="width"d"height"d} _clearButtonOffset,
{CGSize="width"d"height"d} _leftViewOffset,
{CGSize="width"d"height"d} _rightViewOffset,
UITextFieldBorderView* _backgroundView,
UITextFieldBorderView* _disabledBackgroundView,
UITextFieldBackgroundView* _systemBackgroundView,
_UITextFieldContentView* _textContentView,
_UIFloatingContentView* _floatingContentView,
UIVisualEffectView* _contentBackdropView,
_UIDetachedFieldEditorBackgroundView* _fieldEditorBackgroundView,
UIVisualEffectView* _fieldEditorEffectView,
UITextFieldLabel* _placeholderLabel,
UITextFieldLabel* _suffixLabel,
UITextFieldLabel* _prefixLabel,
UIImageView* _iconView,
UILabel* _label,
double _labelOffset,
NSAttributedString* _overriddenPlaceholder,
long _overriddenPlaceholderAlignment,
UITextInteractionAssistant* _interactionAssistant,
UITapGestureRecognizer* _selectGestureRecognizer,
UIFieldEditor* _fieldEditor,
NSTextContainer* __textContainer,
_UIFieldEditorLayoutManager* __layoutManager,
_UICascadingTextStorage* _textStorage,
UITextPasteController* _pasteController,
UIView* _inputView,
UIView* _inputAccessoryView,
UIView* _recentsAccessoryView,
UISystemInputViewController* _systemInputViewController,
UITextFieldAtomBackgroundView* _atomBackgroundView,
* _textDragDropSupport,
{?="verticallyCenterText"b1"isAnimating"b4"inactiveHasDimAppearance"b1"becomesFirstResponderOnClearButtonTap"b1"clearsPlaceholderOnBeginEditing"b1"adjustsFontSizeToFitWidth"b1"fieldEditorAttached"b1"canBecomeFirstResponder"b1"shouldSuppressShouldBeginEditing"b1"inResignFirstResponder"b1"undoDisabled"b1"explicitAlignment"b1"implementsCustomDrawing"b1"needsClearing"b1"suppressContentChangedNotification"b1"allowsEditingTextAttributes"b1"usesAttributedText"b1"backgroundViewState"b2"clearingBehavior"b2"overridePasscodeStyle"b1"shouldResignWithoutUpdate"b1"blurEnabled"b1"disableFocus"b1"disableRemoteTextEditing"b1"allowsAttachments"b1"contentCoverUnsecuresText"b1"forcesClearButtonHighContrastAppearance"b1} _textFieldFlags,
BOOL _deferringBecomeFirstResponder,
BOOL _animateNextHighlightChange,
CUICatalog* _cuiCatalog,
CUIStyleEffectConfiguration* _cuiStyleEffectConfiguration,
double _roundedRectBackgroundCornerRadius,
NSArray* _overriddenAttributesForEditing,
BOOL _adjustsFontForContentSizeCategory,
BOOL _tvUseVibrancy,
BOOL _disableTextColorUpdateOnTraitCollectionChange,
* _pasteDelegate,
NSLayoutConstraint* _baselineLayoutConstraint,
_UIBaselineLayoutStrut* _baselineLayoutLabel,
UIColor* _tvCustomTextColor,
UIColor* _tvCustomFocusedTextColor,
long _textDragOptions,
* _textDragDelegate,
* _textDropDelegate,
_UITextFieldVisualStyle* _visualStyle
)
// 类方法
<__NSArrayI 0x6000030b4930>(
+ (id)fallback_debugHierarchyValueForPropertyWithName:(id)arg0 onObject:(id)arg1 outOptions:(id *)arg2 outError:(id *)arg3 ,
+ (id)fallback_debugHierarchyPropertyDescriptions,
+ (BOOL)doc_setDefaultKeyboardAppearanceIfPossible:(long)arg0 ,
+ (BOOL)_isCompatibilityTextField
)
// 方法
(
"- (void)setAb_textAttributes:(id)arg0 ",
"- (void)setAb_text:(id)arg0 ",
"- (id)ab_textAttributes",
"- (id)ab_text",
"- (void)_cnui_applyContactStyle",
"- (void).cxx_destruct",
"- (void)dealloc",
"- (void)setAttributes:(id)arg0 range:({_NSRange=QQ})arg1 ",
"- (void)setDelegate:(id)arg0 ",
"- (void)setEnabled:(BOOL)arg0 ",
"- (id)methodSignatureForSelector:(SEL)arg0 ",
"- (id)forwardingTargetForSelector:(SEL)arg0 ",
"- (id)font",
"- (void)setNeedsLayout",
"- (id)shadowColor",
"- ({CGSize=dd})shadowOffset",
"- (void)encodeWithCoder:(id)arg0 ",
"- (id)initWithCoder:(id)arg0 ",
"- (void)observeValueForKeyPath:(id)arg0 ofObject:(id)arg1 change:(id)arg2 context:(void *)arg3 ",
"- (void)setProgress:(float)arg0 ",
"- (id)delegate",
"- (BOOL)respondsToSelector:(SEL)arg0 ",
"- (id)textContainer",
"- (id)layoutManager",
"- (id)markedTextStyle",
"- (id)typingAttributes",
"- (void)setLabel:(id)arg0 ",
...共591个...
)
// 遵守的协议
<__NSFrozenArrayM 0x6000030d9ad0>(
DebugHierarchyObject_Fallback ,
ABText ,
UIKeyboardInput ,
_UILayoutBaselineUpdating ,
_UIFloatingContentViewDelegate ,
UIGestureRecognizerDelegate ,
UIKeyInputPrivate ,
_UITextFieldVisualStyleSubject ,
UIViewGhostedRangeSupporting ,
UITextInputTraits_Private ,
_UITextFieldContent_Internal ,
UIPopoverControllerDelegate ,
_UITextFieldContentViewContextProvider,
UITextDragSupporting ,
UITextDropSupporting ,
UITextPasteConfigurationSupporting_Internal ,
UITextFieldContent <_UITextContent>,
UITextDraggable ,
UITextDroppable ,
UITextPasteConfigurationSupporting ,
UITextInput ,
NSCoding,
UIContentSizeCategoryAdjusting
)
// 自己的协议描述
{
"@optional" = (
"- (void)textFieldShouldReturn:",
"- (void)textFieldShouldBeginEditing:",
"- (void)textFieldDidBeginEditing:",
"- (void)textFieldShouldEndEditing:",
"- (void)textFieldDidEndEditing:",
"- (void)textFieldDidEndEditing:reason:",
"- (void)textField:shouldChangeCharactersInRange:replacementString:",
"- (void)textFieldShouldClear:"
);
}
// 层级关系
-> UITextField -> UIControl -> UIView -> UIResponder -> NSObject
NSObject+DLIntrospection源码备份:
还没认真看,以后慢慢学习。
#import
@interface NSObject (DLIntrospection)
/// 打印所有类
+ (NSArray *)classes;
/// 打印属性
+ (NSArray *)properties;
/// 内部变量
+ (NSArray *)instanceVariables;
/// 类方法
+ (NSArray *)classMethods;
/// 方法
+ (NSArray *)instanceMethods;
/// 遵守的协议
+ (NSArray *)protocols;
/// 自己的协议描述
+ (NSDictionary *)descriptionForProtocol:(Protocol *)proto;
/// 层级关系
+ (NSString *)parentClassHierarchy;
@end
#import "NSObject+DLIntrospection.h"
#import
@interface NSString (DLIntrospection)
+ (NSString *)decodeType:(const char *)cString;
@end
@implementation NSString (DLIntrospection)
//https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html
+ (NSString *)decodeType:(const char *)cString {
if (!strcmp(cString, @encode(char))) return @"char";
if (!strcmp(cString, @encode(int))) return @"int";
if (!strcmp(cString, @encode(short))) return @"short";
if (!strcmp(cString, @encode(long))) return @"long";
if (!strcmp(cString, @encode(long long))) return @"long long";
if (!strcmp(cString, @encode(unsigned char))) return @"unsigned char";
if (!strcmp(cString, @encode(unsigned int))) return @"unsigned int";
if (!strcmp(cString, @encode(unsigned short))) return @"unsigned short";
if (!strcmp(cString, @encode(unsigned long))) return @"unsigned long";
if (!strcmp(cString, @encode(unsigned long long))) return @"unsigned long long";
if (!strcmp(cString, @encode(float))) return @"float";
if (!strcmp(cString, @encode(double))) return @"double";
if (!strcmp(cString, @encode(BOOL))) return @"BOOL";
if (!strcmp(cString, @encode(void))) return @"void";
if (!strcmp(cString, @encode(char *))) return @"char *";
if (!strcmp(cString, @encode(id))) return @"id";
if (!strcmp(cString, @encode(Class))) return @"class";
if (!strcmp(cString, @encode(SEL))) return @"SEL";
//@TODO: do handle bitmasks
NSString *result = [NSString stringWithCString:cString encoding:NSUTF8StringEncoding];
if ([[result substringToIndex:1] isEqualToString:@"@"] && [result rangeOfString:@"?"].location == NSNotFound) {
result = [[result substringWithRange:NSMakeRange(2, result.length - 3)] stringByAppendingString:@"*"];
} else
if ([[result substringToIndex:1] isEqualToString:@"^"]) {
result = [NSString stringWithFormat:@"%@ *",
[NSString decodeType:[[result substringFromIndex:1] cStringUsingEncoding:NSUTF8StringEncoding]]];
}
return result;
}
@end
static void getSuper(Class class, NSMutableString *result) {
[result appendFormat:@" -> %@", NSStringFromClass(class)];
if ([class superclass]) { getSuper([class superclass], result); }
}
@implementation NSObject (DLIntrospection)
+ (NSArray *)classes {
unsigned int classesCount;
Class *classes = objc_copyClassList(&classesCount);
NSMutableArray *result = [NSMutableArray array];
for (unsigned int i = 0 ; i < classesCount; i++) {
[result addObject:NSStringFromClass(classes[i])];
}
return [result sortedArrayUsingSelector:@selector(compare:)];
}
+ (NSArray *)classMethods {
return [self methodsForClass:object_getClass([self class]) typeFormat:@"+"];
}
+ (NSArray *)instanceMethods {
return [self methodsForClass:[self class] typeFormat:@"-"];
}
+ (NSArray *)properties {
unsigned int outCount;
objc_property_t *properties = class_copyPropertyList([self class], &outCount);
NSMutableArray *result = [NSMutableArray array];
for (unsigned int i = 0; i < outCount; i++) {
[result addObject:[self formattedPropery:properties[i]]];
}
free(properties);
return result.count ? [result copy] : nil;
}
+ (NSArray *)instanceVariables {
unsigned int outCount;
Ivar *ivars = class_copyIvarList([self class], &outCount);
NSMutableArray *result = [NSMutableArray array];
for (unsigned int i = 0; i < outCount; i++) {
NSString *type = [NSString decodeType:ivar_getTypeEncoding(ivars[i])];
NSString *name = [NSString stringWithCString:ivar_getName(ivars[i]) encoding:NSUTF8StringEncoding];
NSString *ivarDescription = [NSString stringWithFormat:@"%@ %@", type, name];
[result addObject:ivarDescription];
}
free(ivars);
return result.count ? [result copy] : nil;
}
+ (NSArray *)protocols {
unsigned int outCount;
Protocol * const *protocols = class_copyProtocolList([self class], &outCount);
NSMutableArray *result = [NSMutableArray array];
for (unsigned int i = 0; i < outCount; i++) {
unsigned int adoptedCount;
Protocol * const *adotedProtocols = protocol_copyProtocolList(protocols[i], &adoptedCount);
NSString *protocolName = [NSString stringWithCString:protocol_getName(protocols[i]) encoding:NSUTF8StringEncoding];
NSMutableArray *adoptedProtocolNames = [NSMutableArray array];
for (unsigned int idx = 0; idx < adoptedCount; idx++) {
[adoptedProtocolNames addObject:[NSString stringWithCString:protocol_getName(adotedProtocols[idx]) encoding:NSUTF8StringEncoding]];
}
NSString *protocolDescription = protocolName;
if (adoptedProtocolNames.count) {
protocolDescription = [NSString stringWithFormat:@"%@ <%@>", protocolName, [adoptedProtocolNames componentsJoinedByString:@", "]];
}
[result addObject:protocolDescription];
//free(adotedProtocols);
}
//free((__bridge void *)(*protocols));
return result.count ? [result copy] : nil;
}
+ (NSDictionary *)descriptionForProtocol:(Protocol *)proto {
NSMutableDictionary *methodsAndProperties = [NSMutableDictionary dictionary];
NSArray *requiredMethods = [[[self class] formattedMethodsForProtocol:proto required:YES instance:NO] arrayByAddingObjectsFromArray:[[self class]formattedMethodsForProtocol:proto required:YES instance:YES]];
NSArray *optionalMethods = [[[self class] formattedMethodsForProtocol:proto required:NO instance:NO] arrayByAddingObjectsFromArray:[[self class]formattedMethodsForProtocol:proto required:NO instance:YES]];
unsigned int propertiesCount;
NSMutableArray *propertyDescriptions = [NSMutableArray array];
objc_property_t *properties = protocol_copyPropertyList(proto, &propertiesCount);
for (unsigned int i = 0; i < propertiesCount; i++) {
[propertyDescriptions addObject:[self formattedPropery:properties[i]]];
}
if (requiredMethods.count) {
[methodsAndProperties setObject:requiredMethods forKey:@"@required"];
}
if (optionalMethods.count) {
[methodsAndProperties setObject:optionalMethods forKey:@"@optional"];
} if (propertyDescriptions.count) {
[methodsAndProperties setObject:[propertyDescriptions copy] forKey:@"@properties"];
}
free(properties);
return methodsAndProperties.count ? [methodsAndProperties copy ] : nil;
}
+ (NSString *)parentClassHierarchy {
NSMutableString *result = [NSMutableString string];
getSuper([self class], result);
return result;
}
#pragma mark - Private
+ (NSArray *)methodsForClass:(Class)class typeFormat:(NSString *)type {
unsigned int outCount;
Method *methods = class_copyMethodList(class, &outCount);
NSMutableArray *result = [NSMutableArray array];
for (unsigned int i = 0; i < outCount; i++) {
NSString *methodDescription = [NSString stringWithFormat:@"%@ (%@)%@",
type,
[NSString decodeType:method_copyReturnType(methods[i])],
NSStringFromSelector(method_getName(methods[i]))];
NSInteger args = method_getNumberOfArguments(methods[i]);
NSMutableArray *selParts = [[methodDescription componentsSeparatedByString:@":"] mutableCopy];
NSInteger offset = 2; //1-st arg is object (@), 2-nd is SEL (:)
for (NSUInteger idx = offset; idx < args; idx++) {
NSString *returnType = [NSString decodeType:method_copyArgumentType(methods[i], (unsigned int)idx)];
selParts[idx - offset] = [NSString stringWithFormat:@"%@:(%@)arg%lu",
selParts[idx - offset],
returnType,
idx - 2];
}
[result addObject:[selParts componentsJoinedByString:@" "]];
}
free(methods);
return result.count ? [result copy] : nil;
}
+ (NSArray *)formattedMethodsForProtocol:(Protocol *)proto required:(BOOL)required instance:(BOOL)instance {
unsigned int methodCount;
struct objc_method_description *methods = protocol_copyMethodDescriptionList(proto, required, instance, &methodCount);
NSMutableArray *methodsDescription = [NSMutableArray array];
for (unsigned int i = 0; i < methodCount; i++) {
[methodsDescription addObject:
[NSString stringWithFormat:@"%@ (%@)%@",
instance ? @"-" : @"+",
#warning return correct type
@"void",
NSStringFromSelector(methods[i].name)]];
}
free(methods);
return [methodsDescription copy];
}
+ (NSString *)formattedPropery:(objc_property_t)prop {
unsigned int attrCount;
objc_property_attribute_t *attrs = property_copyAttributeList(prop, &attrCount);
NSMutableDictionary *attributes = [NSMutableDictionary dictionary];
for (unsigned int idx = 0; idx < attrCount; idx++) {
NSString *name = [NSString stringWithCString:attrs[idx].name encoding:NSUTF8StringEncoding];
NSString *value = [NSString stringWithCString:attrs[idx].value encoding:NSUTF8StringEncoding];
[attributes setObject:value forKey:name];
}
free(attrs);
NSMutableString *property = [NSMutableString stringWithFormat:@"@property "];
NSMutableArray *attrsArray = [NSMutableArray array];
//https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtPropertyIntrospection.html#//apple_ref/doc/uid/TP40008048-CH101-SW5
[attrsArray addObject:[attributes objectForKey:@"N"] ? @"nonatomic" : @"atomic"];
if ([attributes objectForKey:@"&"]) {
[attrsArray addObject:@"strong"];
} else if ([attributes objectForKey:@"C"]) {
[attrsArray addObject:@"copy"];
} else if ([attributes objectForKey:@"W"]) {
[attrsArray addObject:@"weak"];
} else {
[attrsArray addObject:@"assign"];
}
if ([attributes objectForKey:@"R"]) {[attrsArray addObject:@"readonly"];}
if ([attributes objectForKey:@"G"]) {
[attrsArray addObject:[NSString stringWithFormat:@"getter=%@", [attributes objectForKey:@"G"]]];
}
if ([attributes objectForKey:@"S"]) {
[attrsArray addObject:[NSString stringWithFormat:@"setter=%@", [attributes objectForKey:@"G"]]];
}
[property appendFormat:@"(%@) %@ %@",
[attrsArray componentsJoinedByString:@", "],
[NSString decodeType:[[attributes objectForKey:@"T"] cStringUsingEncoding:NSUTF8StringEncoding]],
[NSString stringWithCString:property_getName(prop) encoding:NSUTF8StringEncoding]];
return [property copy];
}
@end