我有以下头文件和实现文件,其中NSURLMyObject
是的类别NSURL
,并且包含一个只读类属性myString
:
NSURL+MyClass.h
@interface NSURL (NSURLMyClass)
@property(class, readonly) NSString* myString;
@end
NSURL+MyClass.mm
@implementation MyObject
static NSString* _myString;
+ (NSString*) myString
{
if (_myString == nil) {
_myString = @"Hello";
}
return _myString;
}
@end
我还看到过其他帖子,其中有以下情况:
readwrite
在实现中重新声明属性,然后进行合成- 或者直接访问带下划线的成员变量,但没有讨论类属性,也没有讨论类别的类属性。
我相信此类类只读属性大致相当于static constexpr
现代 C++ 中的成员变量,其中初始化它们只需在标题中使用一行代码:
我的类.hxx
#include <string>
using std::literals;
struct MyClass
{
static constexpr auto myString = "Hello"s;
};
// access with, for example, `std::println("{}", MyClass::myString);`
现在回答我的问题:
是否可以
MyClass.myString
更紧凑地初始化,类似于 C++,而无需声明static
下划线前缀的变量、getter 和空值测试?我应该声明一个
+ (instancetype) init
方法然后myString
在其中初始化吗?这不会覆盖已经提供的+init
方法吗?NSURL
还有其他方法吗,即子类而不是类别?我对 Objective-C 语义不太熟悉,因此我不确定
NSURL*
某个 Foundation 类返回的 是否可以直接转换为MyClass*
where@interface MyClass : NSURL
。
总结:
如果你不需要特别
myString
与该类关联NSURL
,并且myString
是一个字符串文字,那么最简洁的表达方式是NSURL
如果您确实希望或需要将其与字符串文字关联myString
,则可以避免中间存储:如果
myString
不是字符串文字,或者需要进行计算,那么您所看到的_myString
存储和初始化的现有模式是最常见和最简洁的方法这不太正确。在 Objective-C 中,属性是一种简洁地合成方法的方式,并提供了调用这些方法的替代语法。一般来说,一个属性调用
foo
:foo
getter 方法和一个setFoo:
setter 方法,x.foo
≍[x foo]
和x.foo = f
≍ 的形式调用这些方法[x setFoo:f]
对于实例属性和类属性来说都是相同的 - 尽管默认情况下类属性的存储语义略有不同。
与您的示例大致相同的 C++ 代码将生成类似
和你的 Objective-C 代码非常粗略的等价物是这样的
根据您在此处实际尝试执行的操作,这可能是浪费,也是不必要的。
根据您要执行的操作,您可能能够完全避免使用属性。例如,是否
myString
一定需要与相关联NSURL
?如果不是,这在 Objective-C 中是完全有效的(也是声明字符串常量的常用方法):如果您确实想通过引用该数据
NSURL.myString
,并且如果字符串是一个常量,那么您也可以避免将其完全存储:文字
NSString
s 已存储在二进制文件中的常量位置;如果myString
永远不会改变,则无需添加static
存储空间并在那里存储指向它的指针。如果 的值myString
是计算出来的,那么存储它以避免在每次调用时重新创建该值是有意义的,但这听起来不像您想要的。有了更多细节,我们就可以在这里给出更具体的建议。
这将是不典型的:
+init
init
会声明一个在你的类上命名的方法,并且init
通常只在类型的实例[NSURL init]
上调用来初始化它们;调用会很不合适+init
并尝试访问该值会怎样?这可能与您想要的相差甚远——您可以对 进行子类化
NSURL
,但子类化是一种影响子类型现有行为的机制,但这不会给您带来任何好处。您不想自定义任何内容NSURL
或其实例,只需向类型添加额外的数据。由于您要添加一个类方法,实例在这里不会发挥作用:如果某个方法
NSURL
向您返回一个对象,您将无法调用myString
它,因为它myString
属于类,而不是实例。