Objective-C 中的不可变对象:大 init 方法?

2024-02-13

我想要一个 Objective-C 中具有不可变字段的对象。

在 C# 中,我将使用具有私有 setter 和大型构造函数的 Properties。

我会在 Objective-C 中使用什么?

使用 @property 似乎不允许我将 setter 声明为私有。

Using

initWithData: (NSString*) something createDate: (NSDate*) date userID: (long) uid

如果我要设置 4 个以上的属性,则似乎过于冗长。

我是否会在 .h 文件中声明 getter,而仅在 .m 文件中声明 setter?

我需要对某些内容和日期使用保留或复制(顺便说一句:我应该使用这两个中的哪一个?),所以我需要在设置器中使用一些代码。

或者还有其他类似不可变关键字的东西吗?


您可以拥有一个公共只读属性,并使用私有读写属性为您的类中的属性提供设置器(如果您确实需要)。但是,您应该考虑是否有必要。

作为示例,请考虑以下不可变 Person 类的声明和定义:

// Person.h
#import <Foundation/Foundation.h>

@interface Person : NSObject {
@private
    NSString *name_;
    NSDate *dateOfBirth_;
}

@property (readonly, copy) NSString *name;
@property (readonly, copy) NSDate *dateOfBirth;

/*! Initializes a Person with copies of the given name and date of birth. */
- (id)initWithName:(NSString *)name dateOfBirth:(NSDate *)dateOfBirth;

@end

// Person.m
#import "Person.h"

@implementation Person

@synthesize name = name_;
@synthesize dateOfBirth = dateOfBirth_;

- (id)initWithName:(NSString *)name dateOfBirth:(NSDate *)dateOfBirth {
    self = [super init];
    if (self) {
        name_ = [name copy];
        dateOfBirth_ = [dateOfBirth copy];
    }

    return self;
}

- (void)dealloc {
    [name_ release];
    [dateOfBirth_ release];

    [super dealloc];
}

@end

首先,请注意我did not声明一个类扩展Person.m重新声明了name and dateOfBirth属性为readwrite。这是因为类的目的是不可变的;如果实例变量只在初始化时设置,则不需要设置器。

另请注意,我声明的实例变量的名称与属性的名称不同。这清楚地表明了属性之间的区别编程接口类和实例变量作为的实施细节班上。我见过太多的开发人员(尤其是那些刚接触 Mac OS X 和 iOS 的开发人员,包括许多来自 C# 的开发人员)将属性与可用于实现它们的实例变量混为一谈。

第三件事要注意的是我将这两个属性声明为copy即使它们是只读的。有两个原因。首先,虽然此类的直接实例是不可变的,但没有什么可以阻止创建 MutablePerson 子类。事实上,这甚至可能是可取的!所以copy明确指定超类的期望是什么 - 超类的值name and dateOfBirth属性本身不会改变。这也暗示着-initWithName:dateOfBirth:可能也是复制品;它的文档注释应该清楚地说明这一点。其次,NSString和NSDate都是值类;不可变子类的副本应该很便宜,并且您不想保留将从您自己的类下更改的可变子类的实例。 (现在实际上没有 NSDate 的任何可变子类,但这并不意味着有人无法创建自己的......)

最后,不必担心指定的初始值设定项是否冗长。如果对象的实例除非处于某种特定状态,否则无效,那么您指定的初始值设定项需要将其置于该状态,并且需要采用适当的参数来执行此操作。

还有一件事:如果您要创建这样的不可变值类,您可能还应该实现自己的-isEqual: and -hash快速比较的方法,并且可能也符合 NSCopying 。例如:

@interface Person (ImmutableValueClass) <NSCopying>
@end

@implementation Person (ImmutableValueClass)

- (NSUInteger)hash {
    return [name_ hash];
}

- (BOOL)isEqual:(id)other {
    Person *otherPerson = other;
    // Using [super isEqual:] to allow easier reparenting
    // -[NSObject isEqual:] is documented as just doing pointer comparison
    return ([super isEqual:otherPerson]
            || ([object isKindOfClass:[self class]]
                && [self.name isEqual:otherPerson.name]
                && [self.dateOfBirth isEqual:otherPerson.dateOfBirth]));
}

- (id)copyWithZone:(NSZone *)zone {
    return [self retain];
}

@end

我在它自己的类别中声明了它,以便不重复我之前作为示例显示的所有代码,但在实际代码中,我可能会将所有这些放在 main 中@interface and @implementation。请注意,我没有重新声明-hash and -isEqual:,我只定义了它们,因为它们已经由 NSObject 声明了。因为这是一个不可变的值类,所以我可以实现-copyWithZone:纯粹通过保留self,我不需要制作该对象的物理副本,因为它的行为应该完全相同。

但是,如果您使用的是 Core Data,请不要这样做; Core Data 实现了您独有的对象,因此您must not有你自己的-hash or -isEqual:执行。为了更好的衡量,你也不应该真正遵守 Core Data NSManagedObject 子类中的 NSCopying ; “复制”属于 Core Data 对象图一部分的对象意味着什么,需要仔细思考,并且通常更多是控制器级别的行为。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Objective-C 中的不可变对象:大 init 方法? 的相关文章

  • 如何检测 UIImage 的非透明部分何时与 UIImage 的另一个非透明部分接触

    我在完成一些我认为会容易得多的事情时遇到了困难 每当 UIImage 中图片的非透明部分接触 UIImage 中包含的图像的另一个非透明部分时 我试图运行一个方法 我举了一个例子来帮助进一步解释我的问题 正如您在上图中看到的 我有两个三角形
  • 如何使用文档提供者扩展?

    我正在学习更多有关 ios 扩展的知识 例如 今日扩展 照片编辑扩展 动作延伸 自定义键盘扩展 在所有这些中 我在学习上没有困难 但最近我尝试学习 文档提供程序扩展 令我惊讶的是 在互联网上没有找到任何相关教程谈论如何使用它 与其他人一样一
  • 如何随机化 NSArray? [复制]

    这个问题在这里已经有答案了 假设我有一个 NSArray 里面有 50 100 个对象 如何将数组按随机顺序排列 有很多方法可以做到这一点 但大多数只涉及生成随机数 也许您可以使用 NSMutableArray 使用此技术 生成 0 到 4
  • 将数据从子模态 VC 传递到父视图控制器的最佳方法?

    将数据从子模式视图传递到父视图控制器的最佳方法是什么 我的 iPad 应用程序上有一个子模式登录屏幕 我想将用户信息传回父级分割视图控制器 我正在考虑使用 NSNotification 但我不确定这是否是将数据传递回父级的最简单 最有效的方
  • iOS通过AVAssetWriter反转音频

    我正在尝试使用 AVAsset 和 AVAssetWriter 在 iOS 中反转音频 以下代码可以正常工作 但输出文件比输入文件短 例如 输入文件的持续时间为 1 59 但输出文件的持续时间为 1 50 且音频内容相同 void reve
  • 动态更新 UIAlertView 消息和换行符问题

    我需要在 UIAlertView 的消息中显示多行文本 我尝试过添加 n 但没有效果 它仍然显示 这是一个示例 但是 如果我将 iPhone 切换为横向模式 它会按照我的预期显示该消息 然后 如果我切换回纵向模式 它也会正确显示 更新 经过
  • 了解 malloc_history 转储

    如果您曾经问 过如何调试 Objective C 中的释放 分配问题 您将遇到这些可以帮助跟踪问题的环境设置 NSZombieEnabled 释放后保留对象 以便您可以获得指针等 MallocStackLogging 保留对象历史记录以供以
  • 如何更改标签栏图标颜色从默认蓝色?

    我有四个标签 我能够将选项卡图标颜色从默认的蓝色更改为红色 或可能任何颜色 并且效果非常好 问题是它仅适用于三个选项卡项目 最后一个选项卡默认为蓝色 下面是代码 我正在编码这个rootviewcontrollerAppDelegate m您
  • 在 Objective C 中断言每个对象创建都成功是必要的吗?

    我最近阅读了Apple的示例代码MVC网络 http developer apple com library ios samplecode MVCNetworking 由 Apple 开发者技术支持大师 Quinn The Eskimo 撰
  • 如何执行 UIAlertAction 的处理程序?

    我正在尝试编写一个帮助程序类以允许我们的应用程序支持两者UIAlertAction and UIAlertView 然而 当写alertView clickedButtonAtIndex 方法为UIAlertViewDelegate 我遇到
  • 如何创建一个 NSMutableArray 并为其分配一个特定的对象?

    我刚刚开始接触 Obj C 并且希望创建一个 MKAnnotations 数组 我已经创建了名为的 MKAnnotation 类TruckLocation其中包含名称 描述 纬度和经度 这是到目前为止我所拥有的数组 NSMutableArr
  • 应用程序在第二次运行 nsnull 计数的循环时崩溃

    我有一个循环 第一次运行正常 但第二次循环时我得到 NSNull count unrecognized selector sent to instance 0x3a094a70 Terminating app due to uncaught
  • 在 Objective C 中使用下划线作为属性名称前缀 [重复]

    这个问题在这里已经有答案了 我以前避免在变量名中使用下划线 这可能是我大学 Java 时代的遗留下来的 因此 当我在 Objective C 中定义属性时 我自然会这样做 In the header interface Whatever N
  • 从 Plist 中存储和检索 [重复]

    这个问题在这里已经有答案了 可能的重复 iOS 在 plist 文件中存储两个 NSMutableArray https stackoverflow com questions 6070568 ios store two nsmutable
  • Objective-C 实例变量?

    我确信我在这里的困惑只是因为陷入 Java 思维方式 并且不理解 Obj C 在这种情况下有何不同 在Java中 我可以在类中声明一个变量 就像这样 并且每个instance该类的 将会有它自己的 MyClass String myVar
  • 在 iOS 中录制音频并永久保存

    我制作了 2 个 iPhone 应用程序 可以录制音频并将其保存到文件中并再次播放 其中之一使用 AVAudiorecorder 和 AVAudioplayer 第二个是苹果的在这里说话 http developer apple com l
  • 如何从 NSString 中删除十六进制字符

    我面临一个与字符串中的某些十六进制值相关的问题 我需要从字符串中删除十六进制字符 The problem is when i print object it prints as BLANK line And in debug mode it
  • 使用 Guava 联合两个 ImmutableEnumSets

    我想联合两个ImmutableEnumSets来自番石榴 这是我的尝试 public final class OurColors public enum Colors RED GREEN BLUE YELLOW PINK BLACK pub
  • iPhone SDK - 在后台线程中运行重复进程

    我有一个iPhone我想在其中每隔一段时间在后台执行一个方法的应用程序1第二 所以在我的主线程中 我有以下代码UIViewController viewDidLoad NSTimer timerWithTimeInterval 1 0 ta
  • 为什么 GDB 调试器不断冻结 Xcode 4?

    这真是一个奇怪的错误 我正在开发一个使用相机源的 iPhone 项目 并通过 OpenGL 着色器运行它以对其应用效果 然而 每次我在代码中简单地创建一个新的 GLfloat 时 调试器都会在启动时冻结 我无法复制和粘贴文本 因为整个 XC

随机推荐