mirror of
https://github.com/SoPat712/YTLitePlus.git
synced 2025-11-01 13:23:37 -04:00
635 lines
19 KiB
Objective-C
635 lines
19 KiB
Objective-C
//
|
|
// FLEXRuntime+UIKitHelpers.m
|
|
// FLEX
|
|
//
|
|
// Created by Tanner Bennett on 12/16/19.
|
|
// Copyright © 2020 FLEX Team. All rights reserved.
|
|
//
|
|
|
|
#import "FLEXRuntime+UIKitHelpers.h"
|
|
#import "FLEXRuntimeUtility.h"
|
|
#import "FLEXPropertyAttributes.h"
|
|
#import "FLEXArgumentInputViewFactory.h"
|
|
#import "FLEXObjectExplorerFactory.h"
|
|
#import "FLEXFieldEditorViewController.h"
|
|
#import "FLEXMethodCallingViewController.h"
|
|
#import "FLEXObjectListViewController.h"
|
|
#import "FLEXTableView.h"
|
|
#import "FLEXUtility.h"
|
|
#import "NSArray+FLEX.h"
|
|
#import "NSString+FLEX.h"
|
|
|
|
#define FLEXObjectExplorerDefaultsImpl \
|
|
- (FLEXObjectExplorerDefaults *)defaults { \
|
|
return self.tag; \
|
|
} \
|
|
\
|
|
- (void)setDefaults:(FLEXObjectExplorerDefaults *)defaults { \
|
|
self.tag = defaults; \
|
|
}
|
|
|
|
#pragma mark FLEXProperty
|
|
@implementation FLEXProperty (UIKitHelpers)
|
|
FLEXObjectExplorerDefaultsImpl
|
|
|
|
/// Decide whether to use potentialTarget or [potentialTarget class] to get or set property
|
|
- (id)appropriateTargetForPropertyType:(id)potentialTarget {
|
|
if (!object_isClass(potentialTarget)) {
|
|
if (self.isClassProperty) {
|
|
return [potentialTarget class];
|
|
} else {
|
|
return potentialTarget;
|
|
}
|
|
} else {
|
|
if (self.isClassProperty) {
|
|
return potentialTarget;
|
|
} else {
|
|
// Instance property with a class object
|
|
return nil;
|
|
}
|
|
}
|
|
}
|
|
|
|
- (BOOL)isEditable {
|
|
if (self.attributes.isReadOnly) {
|
|
return self.likelySetterExists;
|
|
}
|
|
|
|
const FLEXTypeEncoding *typeEncoding = self.attributes.typeEncoding.UTF8String;
|
|
return [FLEXArgumentInputViewFactory canEditFieldWithTypeEncoding:typeEncoding currentValue:nil];
|
|
}
|
|
|
|
- (BOOL)isCallable {
|
|
return YES;
|
|
}
|
|
|
|
- (id)currentValueWithTarget:(id)object {
|
|
return [self getPotentiallyUnboxedValue:
|
|
[self appropriateTargetForPropertyType:object]
|
|
];
|
|
}
|
|
|
|
- (id)currentValueBeforeUnboxingWithTarget:(id)object {
|
|
return [self getValue:
|
|
[self appropriateTargetForPropertyType:object]
|
|
];
|
|
}
|
|
|
|
- (NSString *)previewWithTarget:(id)object {
|
|
if (object_isClass(object) && !self.isClassProperty) {
|
|
return self.attributes.fullDeclaration;
|
|
} else if (self.defaults.wantsDynamicPreviews) {
|
|
return [FLEXRuntimeUtility
|
|
summaryForObject:[self currentValueWithTarget:object]
|
|
];
|
|
}
|
|
|
|
return nil;
|
|
}
|
|
|
|
- (UIViewController *)viewerWithTarget:(id)object {
|
|
id value = [self currentValueWithTarget:object];
|
|
return [FLEXObjectExplorerFactory explorerViewControllerForObject:value];
|
|
}
|
|
|
|
- (UIViewController *)editorWithTarget:(id)object section:(FLEXTableViewSection *)section {
|
|
id target = [self appropriateTargetForPropertyType:object];
|
|
return [FLEXFieldEditorViewController target:target property:self commitHandler:^{
|
|
[section reloadData:YES];
|
|
}];
|
|
}
|
|
|
|
- (UITableViewCellAccessoryType)suggestedAccessoryTypeWithTarget:(id)object {
|
|
id targetForValueCheck = [self appropriateTargetForPropertyType:object];
|
|
if (!targetForValueCheck) {
|
|
// Instance property with a class object
|
|
return UITableViewCellAccessoryNone;
|
|
}
|
|
|
|
// We use .tag to store the cached value of .isEditable that is
|
|
// initialized by FLEXObjectExplorer in -reloadMetada
|
|
if ([self getPotentiallyUnboxedValue:targetForValueCheck]) {
|
|
if (self.defaults.isEditable) {
|
|
// Editable non-nil value, both
|
|
return UITableViewCellAccessoryDetailDisclosureButton;
|
|
} else {
|
|
// Uneditable non-nil value, chevron only
|
|
return UITableViewCellAccessoryDisclosureIndicator;
|
|
}
|
|
} else {
|
|
if (self.defaults.isEditable) {
|
|
// Editable nil value, just (i)
|
|
return UITableViewCellAccessoryDetailButton;
|
|
} else {
|
|
// Non-editable nil value, neither
|
|
return UITableViewCellAccessoryNone;
|
|
}
|
|
}
|
|
}
|
|
|
|
- (NSString *)reuseIdentifierWithTarget:(id)object { return nil; }
|
|
|
|
- (NSArray<UIAction *> *)additionalActionsWithTarget:(id)object sender:(UIViewController *)sender __IOS_AVAILABLE(13.0) {
|
|
BOOL returnsObject = self.attributes.typeEncoding.flex_typeIsObjectOrClass;
|
|
BOOL targetNotNil = [self appropriateTargetForPropertyType:object] != nil;
|
|
|
|
// "Explore PropertyClass" for properties with a concrete class name
|
|
if (returnsObject) {
|
|
NSMutableArray<UIAction *> *actions = [NSMutableArray new];
|
|
|
|
// Action for exploring class of this property
|
|
Class propertyClass = self.attributes.typeEncoding.flex_typeClass;
|
|
if (propertyClass) {
|
|
NSString *title = [NSString stringWithFormat:@"Explore %@", NSStringFromClass(propertyClass)];
|
|
[actions addObject:[UIAction actionWithTitle:title image:nil identifier:nil handler:^(UIAction *action) {
|
|
UIViewController *explorer = [FLEXObjectExplorerFactory explorerViewControllerForObject:propertyClass];
|
|
[sender.navigationController pushViewController:explorer animated:YES];
|
|
}]];
|
|
}
|
|
|
|
// Action for exploring references to this object
|
|
if (targetNotNil) {
|
|
// Since the property holder is not nil, check if the property value is nil
|
|
id value = [self currentValueBeforeUnboxingWithTarget:object];
|
|
if (value) {
|
|
NSString *title = @"List all references";
|
|
[actions addObject:[UIAction actionWithTitle:title image:nil identifier:nil handler:^(UIAction *action) {
|
|
UIViewController *list = [FLEXObjectListViewController
|
|
objectsWithReferencesToObject:value
|
|
retained:NO
|
|
];
|
|
[sender.navigationController pushViewController:list animated:YES];
|
|
}]];
|
|
}
|
|
}
|
|
|
|
return actions;
|
|
}
|
|
|
|
return nil;
|
|
}
|
|
|
|
- (NSArray<NSString *> *)copiableMetadataWithTarget:(id)object {
|
|
BOOL returnsObject = self.attributes.typeEncoding.flex_typeIsObjectOrClass;
|
|
BOOL targetNotNil = [self appropriateTargetForPropertyType:object] != nil;
|
|
|
|
NSMutableArray *items = [NSMutableArray arrayWithArray:@[
|
|
@"Name", self.name ?: @"",
|
|
@"Type", self.attributes.typeEncoding ?: @"",
|
|
@"Declaration", self.fullDescription ?: @"",
|
|
]];
|
|
|
|
if (targetNotNil) {
|
|
id value = [self currentValueBeforeUnboxingWithTarget:object];
|
|
[items addObjectsFromArray:@[
|
|
@"Value Preview", [self previewWithTarget:object] ?: @"",
|
|
@"Value Address", returnsObject ? [FLEXUtility addressOfObject:value] : @"",
|
|
]];
|
|
}
|
|
|
|
[items addObjectsFromArray:@[
|
|
@"Getter", NSStringFromSelector(self.likelyGetter) ?: @"",
|
|
@"Setter", self.likelySetterExists ? NSStringFromSelector(self.likelySetter) : @"",
|
|
@"Image Name", self.imageName ?: @"",
|
|
@"Attributes", self.attributes.string ?: @"",
|
|
@"objc_property", [FLEXUtility pointerToString:self.objc_property],
|
|
@"objc_property_attribute_t", [FLEXUtility pointerToString:self.attributes.list],
|
|
]];
|
|
|
|
return items;
|
|
}
|
|
|
|
- (NSString *)contextualSubtitleWithTarget:(id)object {
|
|
id target = [self appropriateTargetForPropertyType:object];
|
|
if (target && self.attributes.typeEncoding.flex_typeIsObjectOrClass) {
|
|
return [FLEXUtility addressOfObject:[self currentValueBeforeUnboxingWithTarget:target]];
|
|
}
|
|
|
|
return nil;
|
|
}
|
|
|
|
@end
|
|
|
|
|
|
#pragma mark FLEXIvar
|
|
@implementation FLEXIvar (UIKitHelpers)
|
|
FLEXObjectExplorerDefaultsImpl
|
|
|
|
- (BOOL)isEditable {
|
|
const FLEXTypeEncoding *typeEncoding = self.typeEncoding.UTF8String;
|
|
return [FLEXArgumentInputViewFactory canEditFieldWithTypeEncoding:typeEncoding currentValue:nil];
|
|
}
|
|
|
|
- (BOOL)isCallable {
|
|
return NO;
|
|
}
|
|
|
|
- (id)currentValueWithTarget:(id)object {
|
|
if (!object_isClass(object)) {
|
|
return [self getPotentiallyUnboxedValue:object];
|
|
}
|
|
|
|
return nil;
|
|
}
|
|
|
|
- (NSString *)previewWithTarget:(id)object {
|
|
if (object_isClass(object)) {
|
|
return self.details;
|
|
} else if (self.defaults.wantsDynamicPreviews) {
|
|
return [FLEXRuntimeUtility
|
|
summaryForObject:[self currentValueWithTarget:object]
|
|
];
|
|
}
|
|
|
|
return nil;
|
|
}
|
|
|
|
- (UIViewController *)viewerWithTarget:(id)object {
|
|
NSAssert(!object_isClass(object), @"Unreachable state: viewing ivar on class object");
|
|
id value = [self currentValueWithTarget:object];
|
|
return [FLEXObjectExplorerFactory explorerViewControllerForObject:value];
|
|
}
|
|
|
|
- (UIViewController *)editorWithTarget:(id)object section:(FLEXTableViewSection *)section {
|
|
NSAssert(!object_isClass(object), @"Unreachable state: editing ivar on class object");
|
|
return [FLEXFieldEditorViewController target:object ivar:self commitHandler:^{
|
|
[section reloadData:YES];
|
|
}];
|
|
}
|
|
|
|
- (UITableViewCellAccessoryType)suggestedAccessoryTypeWithTarget:(id)object {
|
|
if (object_isClass(object)) {
|
|
return UITableViewCellAccessoryNone;
|
|
}
|
|
|
|
// Could use .isEditable here, but we use .tag for speed since it is cached
|
|
if ([self getPotentiallyUnboxedValue:object]) {
|
|
if (self.defaults.isEditable) {
|
|
// Editable non-nil value, both
|
|
return UITableViewCellAccessoryDetailDisclosureButton;
|
|
} else {
|
|
// Uneditable non-nil value, chevron only
|
|
return UITableViewCellAccessoryDisclosureIndicator;
|
|
}
|
|
} else {
|
|
if (self.defaults.isEditable) {
|
|
// Editable nil value, just (i)
|
|
return UITableViewCellAccessoryDetailButton;
|
|
} else {
|
|
// Non-editable nil value, neither
|
|
return UITableViewCellAccessoryNone;
|
|
}
|
|
}
|
|
}
|
|
|
|
- (NSString *)reuseIdentifierWithTarget:(id)object { return nil; }
|
|
|
|
- (NSArray<UIAction *> *)additionalActionsWithTarget:(id)object sender:(UIViewController *)sender __IOS_AVAILABLE(13.0) {
|
|
Class ivarClass = self.typeEncoding.flex_typeClass;
|
|
|
|
// "Explore PropertyClass" for properties with a concrete class name
|
|
if (ivarClass) {
|
|
NSString *title = [NSString stringWithFormat:@"Explore %@", NSStringFromClass(ivarClass)];
|
|
return @[[UIAction actionWithTitle:title image:nil identifier:nil handler:^(UIAction *action) {
|
|
UIViewController *explorer = [FLEXObjectExplorerFactory explorerViewControllerForObject:ivarClass];
|
|
[sender.navigationController pushViewController:explorer animated:YES];
|
|
}]];
|
|
}
|
|
|
|
return nil;
|
|
}
|
|
|
|
- (NSArray<NSString *> *)copiableMetadataWithTarget:(id)object {
|
|
BOOL isInstance = !object_isClass(object);
|
|
BOOL returnsObject = self.typeEncoding.flex_typeIsObjectOrClass;
|
|
id value = isInstance ? [self getValue:object] : nil;
|
|
|
|
NSMutableArray *items = [NSMutableArray arrayWithArray:@[
|
|
@"Name", self.name ?: @"",
|
|
@"Type", self.typeEncoding ?: @"",
|
|
@"Declaration", self.description ?: @"",
|
|
]];
|
|
|
|
if (isInstance) {
|
|
[items addObjectsFromArray:@[
|
|
@"Value Preview", isInstance ? [self previewWithTarget:object] : @"",
|
|
@"Value Address", returnsObject ? [FLEXUtility addressOfObject:value] : @"",
|
|
]];
|
|
}
|
|
|
|
[items addObjectsFromArray:@[
|
|
@"Size", @(self.size).stringValue,
|
|
@"Offset", @(self.offset).stringValue,
|
|
@"objc_ivar", [FLEXUtility pointerToString:self.objc_ivar],
|
|
]];
|
|
|
|
return items;
|
|
}
|
|
|
|
- (NSString *)contextualSubtitleWithTarget:(id)object {
|
|
if (!object_isClass(object) && self.typeEncoding.flex_typeIsObjectOrClass) {
|
|
return [FLEXUtility addressOfObject:[self getValue:object]];
|
|
}
|
|
|
|
return nil;
|
|
}
|
|
|
|
@end
|
|
|
|
|
|
#pragma mark FLEXMethod
|
|
@implementation FLEXMethodBase (UIKitHelpers)
|
|
FLEXObjectExplorerDefaultsImpl
|
|
|
|
- (BOOL)isEditable {
|
|
return NO;
|
|
}
|
|
|
|
- (BOOL)isCallable {
|
|
return NO;
|
|
}
|
|
|
|
- (id)currentValueWithTarget:(id)object {
|
|
// Methods can't be "edited" and have no "value"
|
|
return nil;
|
|
}
|
|
|
|
- (NSString *)previewWithTarget:(id)object {
|
|
return [self.selectorString stringByAppendingFormat:@" — %@", self.typeEncoding];
|
|
}
|
|
|
|
- (UIViewController *)viewerWithTarget:(id)object {
|
|
// We disallow calling of FLEXMethodBase methods
|
|
@throw NSInternalInconsistencyException;
|
|
return nil;
|
|
}
|
|
|
|
- (UIViewController *)editorWithTarget:(id)object section:(FLEXTableViewSection *)section {
|
|
// Methods cannot be edited
|
|
@throw NSInternalInconsistencyException;
|
|
return nil;
|
|
}
|
|
|
|
- (UITableViewCellAccessoryType)suggestedAccessoryTypeWithTarget:(id)object {
|
|
// We shouldn't be using any FLEXMethodBase objects for this
|
|
@throw NSInternalInconsistencyException;
|
|
return UITableViewCellAccessoryNone;
|
|
}
|
|
|
|
- (NSString *)reuseIdentifierWithTarget:(id)object { return nil; }
|
|
|
|
- (NSArray<UIAction *> *)additionalActionsWithTarget:(id)object sender:(UIViewController *)sender __IOS_AVAILABLE(13.0) {
|
|
return nil;
|
|
}
|
|
|
|
- (NSArray<NSString *> *)copiableMetadataWithTarget:(id)object {
|
|
return @[
|
|
@"Selector", self.name ?: @"",
|
|
@"Type Encoding", self.typeEncoding ?: @"",
|
|
@"Declaration", self.description ?: @"",
|
|
];
|
|
}
|
|
|
|
- (NSString *)contextualSubtitleWithTarget:(id)object {
|
|
return nil;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation FLEXMethod (UIKitHelpers)
|
|
|
|
- (BOOL)isCallable {
|
|
return self.signature != nil;
|
|
}
|
|
|
|
- (UIViewController *)viewerWithTarget:(id)object {
|
|
object = self.isInstanceMethod ? object : (object_isClass(object) ? object : [object class]);
|
|
return [FLEXMethodCallingViewController target:object method:self];
|
|
}
|
|
|
|
- (UITableViewCellAccessoryType)suggestedAccessoryTypeWithTarget:(id)object {
|
|
if (self.isInstanceMethod) {
|
|
if (object_isClass(object)) {
|
|
// Instance method from class, can't call
|
|
return UITableViewCellAccessoryNone;
|
|
} else {
|
|
// Instance method from instance, can call
|
|
return UITableViewCellAccessoryDisclosureIndicator;
|
|
}
|
|
} else {
|
|
return UITableViewCellAccessoryDisclosureIndicator;
|
|
}
|
|
}
|
|
|
|
- (NSArray<NSString *> *)copiableMetadataWithTarget:(id)object {
|
|
return [[super copiableMetadataWithTarget:object] arrayByAddingObjectsFromArray:@[
|
|
@"NSMethodSignature *", [FLEXUtility addressOfObject:self.signature],
|
|
@"Signature String", self.signatureString ?: @"",
|
|
@"Number of Arguments", @(self.numberOfArguments).stringValue,
|
|
@"Return Type", @(self.returnType ?: ""),
|
|
@"Return Size", @(self.returnSize).stringValue,
|
|
@"objc_method", [FLEXUtility pointerToString:self.objc_method],
|
|
]];
|
|
}
|
|
|
|
@end
|
|
|
|
|
|
#pragma mark FLEXProtocol
|
|
@implementation FLEXProtocol (UIKitHelpers)
|
|
FLEXObjectExplorerDefaultsImpl
|
|
|
|
- (BOOL)isEditable {
|
|
return NO;
|
|
}
|
|
|
|
- (BOOL)isCallable {
|
|
return NO;
|
|
}
|
|
|
|
- (id)currentValueWithTarget:(id)object {
|
|
return nil;
|
|
}
|
|
|
|
- (NSString *)previewWithTarget:(id)object {
|
|
return nil;
|
|
}
|
|
|
|
- (UIViewController *)viewerWithTarget:(id)object {
|
|
return [FLEXObjectExplorerFactory explorerViewControllerForObject:self];
|
|
}
|
|
|
|
- (UIViewController *)editorWithTarget:(id)object section:(FLEXTableViewSection *)section {
|
|
// Protocols cannot be edited
|
|
@throw NSInternalInconsistencyException;
|
|
return nil;
|
|
}
|
|
|
|
- (UITableViewCellAccessoryType)suggestedAccessoryTypeWithTarget:(id)object {
|
|
return UITableViewCellAccessoryDisclosureIndicator;
|
|
}
|
|
|
|
- (NSString *)reuseIdentifierWithTarget:(id)object { return nil; }
|
|
|
|
- (NSArray<UIAction *> *)additionalActionsWithTarget:(id)object sender:(UIViewController *)sender __IOS_AVAILABLE(13.0) {
|
|
return nil;
|
|
}
|
|
|
|
- (NSArray<NSString *> *)copiableMetadataWithTarget:(id)object {
|
|
NSArray<NSString *> *conformanceNames = [self.protocols valueForKeyPath:@"name"];
|
|
NSString *conformances = [conformanceNames componentsJoinedByString:@"\n"];
|
|
return @[
|
|
@"Name", self.name ?: @"",
|
|
@"Conformances", conformances ?: @"",
|
|
];
|
|
}
|
|
|
|
- (NSString *)contextualSubtitleWithTarget:(id)object {
|
|
return nil;
|
|
}
|
|
|
|
@end
|
|
|
|
|
|
#pragma mark FLEXStaticMetadata
|
|
@interface FLEXStaticMetadata () {
|
|
@protected
|
|
NSString *_name;
|
|
}
|
|
@property (nonatomic) FLEXTableViewCellReuseIdentifier reuse;
|
|
@property (nonatomic) NSString *subtitle;
|
|
@property (nonatomic) id metadata;
|
|
@end
|
|
|
|
@interface FLEXStaticMetadata_Class : FLEXStaticMetadata
|
|
+ (instancetype)withClass:(Class)cls;
|
|
@end
|
|
|
|
@implementation FLEXStaticMetadata
|
|
@synthesize name = _name;
|
|
@synthesize tag = _tag;
|
|
|
|
FLEXObjectExplorerDefaultsImpl
|
|
|
|
+ (NSArray<FLEXStaticMetadata *> *)classHierarchy:(NSArray<Class> *)classes {
|
|
return [classes flex_mapped:^id(Class cls, NSUInteger idx) {
|
|
return [FLEXStaticMetadata_Class withClass:cls];
|
|
}];
|
|
}
|
|
|
|
+ (instancetype)style:(FLEXStaticMetadataRowStyle)style title:(NSString *)title string:(NSString *)string {
|
|
return [[self alloc] initWithStyle:style title:title subtitle:string];
|
|
}
|
|
|
|
+ (instancetype)style:(FLEXStaticMetadataRowStyle)style title:(NSString *)title number:(NSNumber *)number {
|
|
return [[self alloc] initWithStyle:style title:title subtitle:number.stringValue];
|
|
}
|
|
|
|
- (id)initWithStyle:(FLEXStaticMetadataRowStyle)style title:(NSString *)title subtitle:(NSString *)subtitle {
|
|
self = [super init];
|
|
if (self) {
|
|
if (style == FLEXStaticMetadataRowStyleKeyValue) {
|
|
_reuse = kFLEXKeyValueCell;
|
|
} else {
|
|
_reuse = kFLEXMultilineDetailCell;
|
|
}
|
|
|
|
_name = title;
|
|
_subtitle = subtitle;
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
- (NSString *)description {
|
|
return self.name;
|
|
}
|
|
|
|
- (NSString *)reuseIdentifierWithTarget:(id)object {
|
|
return self.reuse;
|
|
}
|
|
|
|
- (BOOL)isEditable {
|
|
return NO;
|
|
}
|
|
|
|
- (BOOL)isCallable {
|
|
return NO;
|
|
}
|
|
|
|
- (id)currentValueWithTarget:(id)object {
|
|
return nil;
|
|
}
|
|
|
|
- (NSString *)previewWithTarget:(id)object {
|
|
return self.subtitle;
|
|
}
|
|
|
|
- (UIViewController *)viewerWithTarget:(id)object {
|
|
return nil;
|
|
}
|
|
|
|
- (UIViewController *)editorWithTarget:(id)object section:(FLEXTableViewSection *)section {
|
|
// Static metadata cannot be edited
|
|
@throw NSInternalInconsistencyException;
|
|
return nil;
|
|
}
|
|
|
|
- (UITableViewCellAccessoryType)suggestedAccessoryTypeWithTarget:(id)object {
|
|
return UITableViewCellAccessoryNone;
|
|
}
|
|
|
|
- (NSArray<UIAction *> *)additionalActionsWithTarget:(id)object sender:(UIViewController *)sender __IOS_AVAILABLE(13.0) {
|
|
return nil;
|
|
}
|
|
|
|
- (NSArray<NSString *> *)copiableMetadataWithTarget:(id)object {
|
|
return @[self.name, self.subtitle];
|
|
}
|
|
|
|
- (NSString *)contextualSubtitleWithTarget:(id)object {
|
|
return nil;
|
|
}
|
|
|
|
@end
|
|
|
|
|
|
#pragma mark FLEXStaticMetadata_Class
|
|
@implementation FLEXStaticMetadata_Class
|
|
|
|
+ (instancetype)withClass:(Class)cls {
|
|
NSParameterAssert(cls);
|
|
|
|
FLEXStaticMetadata_Class *metadata = [self new];
|
|
metadata.metadata = cls;
|
|
metadata->_name = NSStringFromClass(cls);
|
|
metadata.reuse = kFLEXDefaultCell;
|
|
return metadata;
|
|
}
|
|
|
|
- (id)initWithStyle:(FLEXStaticMetadataRowStyle)style title:(NSString *)title subtitle:(NSString *)subtitle {
|
|
@throw NSInternalInconsistencyException;
|
|
return nil;
|
|
}
|
|
|
|
- (UIViewController *)viewerWithTarget:(id)object {
|
|
return [FLEXObjectExplorerFactory explorerViewControllerForObject:self.metadata];
|
|
}
|
|
|
|
- (UITableViewCellAccessoryType)suggestedAccessoryTypeWithTarget:(id)object {
|
|
return UITableViewCellAccessoryDisclosureIndicator;
|
|
}
|
|
|
|
- (NSArray<NSString *> *)copiableMetadataWithTarget:(id)object {
|
|
return @[
|
|
@"Class Name", self.name,
|
|
@"Class", [FLEXUtility addressOfObject:self.metadata]
|
|
];
|
|
}
|
|
|
|
- (NSString *)contextualSubtitleWithTarget:(id)object {
|
|
return [FLEXUtility addressOfObject:self.metadata];
|
|
}
|
|
|
|
@end
|