你有什麼想法嗎?謝謝
我們得到的想法。解決方案...你必須決定。
從documentation about format specifiers,你不能只擔心description
。具體地,從該文件...
Objective-C的對象,打印爲通過 descriptionWithLocale返回的字符串:如果有的話,或以其它方式描述。另外 與CFTypeRef對象一起使用,返回 CFCopyDescription函數的結果。
除非我們想鏈接器和/或動態加載程序破解我們不能做太多關於CFTypeRef
對象。
然而,我們可以做一些約和description
descriptionWithLocale:
,雖然這東西是有點粗糙。
你也可以考慮debugDescription
以及。
這是一種方法來實現你的目標,雖然我認爲它是「教育」,你應該使用你最好的判斷,你是否要走這條路線。
首先,您需要確定您的替換description
實現的樣子。我們將像這樣宣佈替換爲description
的簡單替換(忽略原始實現)。
static NSString * swizzledDescription(id self, SEL _cmd)
{
NSUInteger count = [self count];
NSMutableString *result = [NSMutableString stringWithFormat:@"Array instance (%p) of type %@ with %lu elements", (void*)self, NSStringFromClass([self class]), (unsigned long)count];
int fmtLen = snprintf(0,0,"%lu",count);
for (NSUInteger i = 0; i < count; ++i) {
[result appendFormat:@"\n%p: %*lu: %@", (void*)self, fmtLen, i, self[i]];
}
return result;
}
和更簡單的實現descriptionWithLocale:
完全忽略了語言環境。
static NSString * swizzledDescriptionWithLocale(id self, SEL _cmd, id locale) {
return swizzledDescription(self, _cmd);
}
現在,我們該如何使NSArray
實現使用這段代碼?一種方法是找到NSArray
的所有子類並替換它們的方法...
static void swizzleMethod(Class class, SEL selector, IMP newImp) {
Method method = class_getInstanceMethod(class, selector);
if (method) {
IMP origImp = method_getImplementation(method);
if (origImp != newImp) {
method_setImplementation(method, newImp);
}
}
}
static void swizzleArrayDescriptions() {
int numClasses = objc_getClassList(NULL, 0);
if (numClasses <= 0) return;
Class *classes = (__unsafe_unretained Class *)malloc(sizeof(Class) * numClasses);
numClasses = objc_getClassList(classes, numClasses);
Class target = [NSArray class];
for (int i = 0; i < numClasses; i++) {
for (Class c = classes[i]; c; c = class_getSuperclass(c)) {
if (c == target) {
c = classes[i];
swizzleMethod(c, @selector(description), (IMP)swizzledDescription);
swizzleMethod(c, @selector(descriptionWithLocale:), (IMP)swizzledDescriptionWithLocale);
break;
}
}
}
free(classes);
}
合理的地方打電話swizzleArrayDescriptions
是在應用程序委託的+initialize
方法。
@implementation AppDelegate
+ (void)initialize {
if (self == [AppDelegate class]) {
swizzleArrayDescriptions();
}
}
現在,你應該可以玩它,看看你是如何相處的。
作爲一個非常簡單的測試......
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Insert code here to initialize your application
NSArray *array = @[@"One", @"Two", @3, @"4", @"FIVE", @(6.0), @".7.", @8, @9, @10, @"Eleven" ];
NSLog(@"%@", array);
NSLog(@"%@", [array mutableCopy]);
}
產生這種輸出...
2015-11-08 14:30:45.501 TestApp[72183:25861219] Array instance (0x6000000c5780) of type __NSArrayI with 11 elements
0x6000000c5780: 0: One
0x6000000c5780: 1: Two
0x6000000c5780: 2: 3
0x6000000c5780: 3: 4
0x6000000c5780: 4: FIVE
0x6000000c5780: 5: 6
0x6000000c5780: 6: .7.
0x6000000c5780: 7: 8
0x6000000c5780: 8: 9
0x6000000c5780: 9: 10
0x6000000c5780: 10: Eleven
2015-11-08 14:30:45.501 TestApp[72183:25861219] Array instance (0x600000045580) of type __NSArrayM with 11 elements
0x600000045580: 0: One
0x600000045580: 1: Two
0x600000045580: 2: 3
0x600000045580: 3: 4
0x600000045580: 4: FIVE
0x600000045580: 5: 6
0x600000045580: 6: .7.
0x600000045580: 7: 8
0x600000045580: 8: 9
0x600000045580: 9: 10
0x600000045580: 10: Eleven
當然,你應該做的比我更多的測試,因爲我所做的就是黑客這在教堂之後,因爲它似乎有點有趣(下雨,所以野餐被取消)。
如果您需要調用原始實現,您將需要創建原始實現的緩存,並按類別鍵入,並相應地調用它們。然而,對於這樣的情況,如果你想修改返回的字符串,你可能不需要這樣做,並且它在任何情況下都應該是直截了當的。
此外,請注意關於混合遊戲的正常注意事項,並且在玩類集羣時它們會更高一些。
注意,你也可以做這樣的事情來在運行時創建自定義的子類。你甚至可以用正常的方式將你的子類定義爲NSArray
的直接子類,然後調整它們的類型而不影響任何不屬於你的類......或者一堆不同的東西......記住ObjectiveC運行時是你的朋友。
你幾乎已經經歷了選擇和缺點。我不認爲有任何其他選擇。我想你可以改變方式,但除非你能詳盡地涵蓋所有班級成員,否則你可能不得不面對不完整的報道。並記住NSMutableArray也是一個類集羣:) – Avi
如果你想在特定的設計中爲特定的數組做這個,那麼寫一個方法/函數來生成數組的所有者中的描述可能是最簡單的,也就是說, (NSString *)describeMyArray :(NSArray *)array {...} – Jef
爲什麼你想提供一個自定義的' description'?目標是什麼?解決這個問題可能比解決基本集合類的功能更好。 –