AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / coding / 问题 / 79466619
Accepted
SRSR333
SRSR333
Asked: 2025-02-25 20:52:24 +0800 CST2025-02-25 20:52:24 +0800 CST 2025-02-25 20:52:24 +0800 CST

如何紧凑地初始化 Objective-C 中某个类别的类只读属性?

  • 772

我有以下头文件和实现文件,其中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);`

现在回答我的问题:

  1. 是否可以MyClass.myString更紧凑地初始化,类似于 C++,而无需声明static下划线前缀的变量、getter 和空值测试?

  2. 我应该声明一个+ (instancetype) init方法然后myString在其中初始化吗?这不会覆盖已经提供的+init方法吗?NSURL

  3. 还有其他方法吗,即子类而不是类别?我对 Objective-C 语义不太熟悉,因此我不确定NSURL*某个 Foundation 类返回的 是否可以直接转换为MyClass*where @interface MyClass : NSURL。

objective-c
  • 1 1 个回答
  • 30 Views

1 个回答

  • Voted
  1. Best Answer
    Itai Ferber
    2025-02-25T22:21:44+08:002025-02-25T22:21:44+08:00

    总结:

    1. 如果你不需要特别myString与该类关联NSURL,并且myString是一个字符串文字,那么最简洁的表达方式是

      // MyString.h
      extern NSString * const myString;
      
      // MyString.mm
      NSString * const myString = @"Hello";
      
      // OtherFile.mm
      NSString *someThing = myString; // accessed like a global var
      
    2. NSURL如果您确实希望或需要将其与字符串文字关联myString,则可以避免中间存储:

      + (NSString *)myString {
          return @"Hello";
      }
      
    3. 如果myString不是字符串文字,或者需要进行计算,那么您所看到的_myString存储和初始化的现有模式是最常见和最简洁的方法


    我相信此类类只读属性大致相当于static constexpr现代 C++ 中的成员变量,其中初始化它们只需在标题中使用一行代码:

    这不太正确。在 Objective-C 中,属性是一种简洁地合成方法的方式,并提供了调用这些方法的替代语法。一般来说,一个属性调用foo:

    1. 创建一个foogetter 方法和一个setFoo:setter 方法,
    2. 然后允许以x.foo≍[x foo]和x.foo = f≍ 的形式调用这些方法[x setFoo:f]

    对于实例属性和类属性来说都是相同的 - 尽管默认情况下类属性的存储语义略有不同。

    与您的示例大致相同的 C++ 代码将生成类似

    #include <string>
    
    using std::literals;
    
    struct MyClass 
    {
        static constexpr auto myString() {
            return "Hello"s;
        }
    };
    

    和你的 Objective-C 代码非常粗略的等价物是这样的

    struct MyClass
    {
        static auto myString() {
            if (!myString_) {
                myString_ = "Hello";
            }
            
            return *myString_;
        }
        
    private:
        static const char *myString_;
    };
    

    根据您在此处实际尝试执行的操作,这可能是浪费,也是不必要的。

    MyClass.myString 是否可以更紧凑地初始化,类似于 C++,而不必声明静态下划线前缀变量、getter 和空值测试?

    根据您要执行的操作,您可能能够完全避免使用属性。例如,是否myString一定需要与相关联NSURL?如果不是,这在 Objective-C 中是完全有效的(也是声明字符串常量的常用方法):

    // MyString.h
    extern NSString * const myString;
    
    // MyString.mm
    NSString * const myString = @"Hello";
    

    如果您确实想通过引用该数据NSURL.myString,并且如果字符串是一个常量,那么您也可以避免将其完全存储:

    + (NSString *)myString 
    {
        return @"Hello";
    }
    

    文字NSStrings 已存储在二进制文件中的常量位置;如果myString永远不会改变,则无需添加static存储空间并在那里存储指向它的指针。如果 的值myString是计算出来的,那么存储它以避免在每次调用时重新创建该值是有意义的,但这听起来不像您想要的。

    有了更多细节,我们就可以在这里给出更具体的建议。

    我是否应该声明一个 + (instancetype) init 方法,然后在其中初始化 myString?这不会覆盖 NSURL 已提供的 +init 方法吗?

    这将是不典型的:

    1. +initinit会声明一个在你的类上命名的方法,并且init通常只在类型的实例[NSURL init]上调用来初始化它们;调用会很不合适
    2. 这在 Objective-C 中根本不是一个常见的模式:就像你所看到的,这样的值通常是根据需要计算并在第一次调用时存储的;很少需要明确初始化这样的类值——如果你忘记调用+init并尝试访问该值会怎样?

    还有其他方法吗,即子类而不是类别?我不太熟悉 Objective-C 语义,所以我不确定某个 Foundation 类返回的 NSURL* 是否可以直接转换为 MyClass*,其中 @interface MyClass : NSURL。

    这可能与您想要的相差甚远——您可以对 进行子类化NSURL,但子类化是一种影响子类型现有行为的机制,但这不会给您带来任何好处。您不想自定义任何内容NSURL或其实例,只需向类型添加额外的数据。

    由于您要添加一个类方法,实例在这里不会发挥作用:如果某个方法NSURL向您返回一个对象,您将无法调用myString它,因为它myString属于类,而不是实例。

    • 1

相关问题

  • 引用计数未初始化的对象

  • Cocoa - Block 隐式保留“自我” - 不同的解决方案

  • Xcode 14.3 编辑器非常慢。总是占用大约 20 - 30 GB 的 RAM

  • 需要一些关于dispatch_queue_create和RunLoop的澄清。在它们之间共享 RunLoop

  • Objective-c:将属性设置为属性,是否保留默认设置

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    重新格式化数字,在固定位置插入分隔符

    • 6 个回答
  • Marko Smith

    为什么 C++20 概念会导致循环约束错误,而老式的 SFINAE 不会?

    • 2 个回答
  • Marko Smith

    VScode 自动卸载扩展的问题(Material 主题)

    • 2 个回答
  • Marko Smith

    Vue 3:创建时出错“预期标识符但发现‘导入’”[重复]

    • 1 个回答
  • Marko Smith

    具有指定基础类型但没有枚举器的“枚举类”的用途是什么?

    • 1 个回答
  • Marko Smith

    如何修复未手动导入的模块的 MODULE_NOT_FOUND 错误?

    • 6 个回答
  • Marko Smith

    `(表达式,左值) = 右值` 在 C 或 C++ 中是有效的赋值吗?为什么有些编译器会接受/拒绝它?

    • 3 个回答
  • Marko Smith

    在 C++ 中,一个不执行任何操作的空程序需要 204KB 的堆,但在 C 中则不需要

    • 1 个回答
  • Marko Smith

    PowerBI 目前与 BigQuery 不兼容:Simba 驱动程序与 Windows 更新有关

    • 2 个回答
  • Marko Smith

    AdMob:MobileAds.initialize() - 对于某些设备,“java.lang.Integer 无法转换为 java.lang.String”

    • 1 个回答
  • Martin Hope
    Fantastic Mr Fox msvc std::vector 实现中仅不接受可复制类型 2025-04-23 06:40:49 +0800 CST
  • Martin Hope
    Howard Hinnant 使用 chrono 查找下一个工作日 2025-04-21 08:30:25 +0800 CST
  • Martin Hope
    Fedor 构造函数的成员初始化程序可以包含另一个成员的初始化吗? 2025-04-15 01:01:44 +0800 CST
  • Martin Hope
    Petr Filipský 为什么 C++20 概念会导致循环约束错误,而老式的 SFINAE 不会? 2025-03-23 21:39:40 +0800 CST
  • Martin Hope
    Catskul C++20 是否进行了更改,允许从已知绑定数组“type(&)[N]”转换为未知绑定数组“type(&)[]”? 2025-03-04 06:57:53 +0800 CST
  • Martin Hope
    Stefan Pochmann 为什么 {2,3,10} 和 {x,3,10} (x=2) 的顺序不同? 2025-01-13 23:24:07 +0800 CST
  • Martin Hope
    Chad Feller 在 5.2 版中,bash 条件语句中的 [[ .. ]] 中的分号现在是可选的吗? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench 为什么双破折号 (--) 会导致此 MariaDB 子句评估为 true? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng 为什么 `dict(id=1, **{'id': 2})` 有时会引发 `KeyError: 'id'` 而不是 TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob:MobileAds.initialize() - 对于某些设备,“java.lang.Integer 无法转换为 java.lang.String” 2024-03-20 03:12:31 +0800 CST

热门标签

python javascript c++ c# java typescript sql reactjs html

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve