- macOS 11.5.2
- Xcode 13.2.1
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import <iostream>
int main(int argc, const char * argv[]) {
@autoreleasepool {
Class clazz = NSClassFromString(@"NSString");
uint32_t count = 0;
objc_property_t* properties = class_copyPropertyList(clazz, &count);
for (uint32_t i = 0; i < count; i ){
const char* name = property_getName(properties[i]);
std::cout << name << std::endl;
}
free(properties);
}
return 0;
}
我將截取一些輸出片段:
hash
superclass
description
debugDescription
hash
superclass
description
debugDescription
vertexID
sha224
NS_isSourceOver
hash
superclass
description
debugDescription
...
從輸出中我們可以發現,hash、description、superclass等屬性會重復出現幾次,而一些屬性(如UTF8String)并沒有出現在結果串列中。我應該如何正確獲取屬性串列?我會很感激。
uj5u.com熱心網友回復:
您沒有看到UTF8String作為屬性出現的原因是它沒有在 的主宣告中宣告為屬性NSString,而是在類別中宣告。在 macOS 12.2.1/Xcode 13.2.1 上,宣告NSString歸結為:
@interface NSString : NSObject <NSCopying, NSMutableCopying, NSSecureCoding>
@property (readonly) NSUInteger length;
- (unichar)characterAtIndex:(NSUInteger)index;
- (instancetype)init NS_DESIGNATED_INITIALIZER;
- (nullable instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER;
@end
NSString之后立即在類別中宣告所有其他屬性和方法:
@interface NSString (NSStringExtensionMethods)
#pragma mark *** Substrings ***
/* To avoid breaking up character sequences such as Emoji, you can do:
[str substringFromIndex:[str rangeOfComposedCharacterSequenceAtIndex:index].location]
[str substringToIndex:NSMaxRange([str rangeOfComposedCharacterSequenceAtIndex:index])]
[str substringWithRange:[str rangeOfComposedCharacterSequencesForRange:range]
*/
- (NSString *)substringFromIndex:(NSUInteger)from;
- (NSString *)substringToIndex:(NSUInteger)to;
// ...
@property (nullable, readonly) const char *UTF8String NS_RETURNS_INNER_POINTER; // Convenience to return null-terminated UTF8 representation
// ...
@end
當在這樣的型別的類別中宣告屬性時,它不會作為實際的 Obj-C 屬性發出,因為類別只能將方法添加到類,而不是實體變數。當類別宣告型別的屬性時,它必須由方法支持,而不是傳統屬性。
你也可以通過自定義類看到這一點——在我的機器上,
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
@interface MyClass: NSObject
@property (nullable, readonly) const char *direct_UTF8String NS_RETURNS_INNER_POINTER;
@end
@interface MyClass (Extensions)
@property (nullable, readonly) const char *category_UTF8String NS_RETURNS_INNER_POINTER;
@end
@implementation MyClass
- (const char *)direct_UTF8String {
return "Hello, world!";
}
- (const char *)category_UTF8String {
return "Hi there!";
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
Class clazz = NSClassFromString(@"MyClass");
printf("%s properties:\n", class_getName(clazz));
uint32_t count = 0;
objc_property_t* properties = class_copyPropertyList(clazz, &count);
for (uint32_t i = 0; i < count; i ){
printf("%s\n", property_getName(properties[i]));
}
free(properties);
puts("-----------------------------------------------");
printf("%s methods:\n", class_getName(clazz));
Method *methods = class_copyMethodList(clazz, &count);
for (uint32_t i = 0; i < count; i ) {
SEL name = method_getName(methods[i]);
printf("%s\n", sel_getName(name));
}
free(methods);
}
return 0;
}
輸出
MyClass properties:
direct_UTF8String
-----------------------------------------------
MyClass methods:
direct_UTF8String
category_UTF8String
如果您*UTF8String從類中洗掉方法的實際實作,則該屬性仍處于宣告狀態,但類別方法會消失(因為由于類別的作業方式,它實際上沒有綜合實作):
MyClass properties:
direct_UTF8String
-----------------------------------------------
MyClass methods:
direct_UTF8String
至于如何適應這一點:這取決于您嘗試獲取屬性的目的,以及您可能特別需要的原因UTF8String。
uj5u.com熱心網友回復:
NSString 在其介面中宣告它實作了方法,但實際上并未實作它們,這就是為什么當您在運行時列印其方法的串列時,它不會列印您期望的內容。這些方法由其他私有類實作,并且當您初始化 的新實體時,您不會NSString獲得一個實體,而是獲得NSString具有實際實作的該私有類的實體。
您可以通過列印字串的型別別來看到,以下列印的是NSCFStringor NSTaggedPointerString, not NSString:
NSString* aString = [NSString stringWithFormat: @"something"];
NSLog(@"%@", [aString class]);
這列印__NSCFConstantString:
NSLog(@"%@", [@"a constant string" class]);
這種模式稱為類簇模式。如果您修改轉儲方法,NSCFString您將獲得“redactedDescription”,您似乎無法查詢這些類。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/435915.html
上一篇:Python奇數和偶數
