Ios 使用「;“复制”;属性来维护不可变的NSString

Ios 使用「;“复制”;属性来维护不可变的NSString,ios,properties,attributes,copy,Ios,Properties,Attributes,Copy,我对Objective-C中的iOS开发和编程非常陌生。我一直在应用程序开发库上做练习 这是我正在努力理解的当前练习。 3.测试如果您将一个可变字符串设置为此人的名字,然后在调用修改后的sayHello方法之前对该字符串进行变异,会发生什么情况。通过添加copy属性并再次测试来更改NSString属性声明 但是,尽管使用了copy property属性,我修改的NSString实际上还是会改变 这里是我的声明和实现,以及我的测试代码 XYZPerson.h #import <Foundat

我对Objective-C中的iOS开发和编程非常陌生。我一直在应用程序开发库上做练习

这是我正在努力理解的当前练习。 3.测试如果您将一个可变字符串设置为此人的名字,然后在调用修改后的sayHello方法之前对该字符串进行变异,会发生什么情况。通过添加copy属性并再次测试来更改NSString属性声明

但是,尽管使用了copy property属性,我修改的NSString实际上还是会改变

这里是我的声明和实现,以及我的测试代码

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

@interface XYZPerson : NSObject

@property (copy) NSString *firstName;
@property NSString *lastName;
@property NSDate *dob;

- (void)sayHello;
- (void)saySomething:(NSString *)greeting;

+ (id)init;
+ (id)personWithFirstName:(NSString *)firstName lastName:(NSString *)lastName dob:(NSDate   *)dateOfBirth;


@end

//XYZPerson.m
#import "XYZPerson.h"

@implementation XYZPerson

@synthesize firstName = _firstName;
@synthesize lastName = _lastName;
@synthesize dob = _dob;


- (void)sayHello {
    [self saySomething:@"Hello World!"];
    NSLog(@"This is %@ %@", self.firstName, self.lastName);
}

- (void)saySomething:(NSString *)greeting {
    NSLog(@"%@", greeting);
}

+ (id)init {
    return [self personWithFirstName:@"Yorick" lastName:@"Robinson" dob:8/23/1990];
}

+ (id)personWithFirstName:(NSString *)firstName lastName:(NSString *)lastName dob:(NSDate   *)dateOfBirth{
    XYZPerson *person = [[self alloc] init];
    person.firstName = firstName;
    person.lastName = lastName;
    person.dob = dateOfBirth;

    return person;
}

@end

//Test code
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#import "XYZPerson.h"
#import "XYZShoutingPerson.h"


int main(int argc, char *argv[])
{
    @autoreleasepool {
        XYZPerson *guy = [XYZPerson init];
        [guy sayHello];

        //I thought that this change would never be made, but it is everytime I run the code.
        guy.firstName = @"Darryl";
        [guy sayHello];

        XYZShoutingPerson *girl = [XYZShoutingPerson init];
        [girl sayHello];
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}
XYZPerson.h
#进口
@接口XYZPerson:NSObject
@属性(副本)NSString*firstName;
@属性NSString*lastName;
@财产日期*dob;
-(无效)说你好;
-(void)说点什么:(NSString*)问候;
+(id)init;
+(id)名为:(NSString*)名为lastName:(NSString*)名为dob:(NSDate*)出生日期;
@结束
//XYZPerson.m
#导入“XYZPerson.h”
@XYZPerson的实现
@合成名字=_名字;
@合成lastName=\u lastName;
@合成dob=_-dob;
-(无效)您好{
[自言自语:@“你好,世界!”;
NSLog(@“这是%@%@”、self.firstName、self.lastName);
}
-(void)说点什么:(NSString*)问候语{
NSLog(@“%@”,问候语);
}
+(id)init{
return[个人名:@“约里克”姓:@“罗宾逊”出生日期:1990年8月23日];
}
+(id)名为:(NSString*)名为lastName:(NSString*)名为dob:(NSDate*)出生日期{
XYZPerson*person=[[self alloc]init];
person.firstName=firstName;
person.lastName=lastName;
person.dob=出生日期;
返回人;
}
@结束
//测试代码
#进口
#导入“AppDelegate.h”
#导入“XYZPerson.h”
#导入“XYZShoutingPerson.h”
int main(int argc,char*argv[])
{
@自动释放池{
XYZPerson*guy=[XYZPerson init];
[盖伊说你好];
//我原以为永远不会进行这种更改,但每次我都会运行代码。
guy.firstName=@“Darryl”;
[盖伊说你好];
XYZShoutingPerson*女孩=[XYZShoutingPerson init];
[女孩说你好];
返回UIApplicationMain(argc、argv、nil、NSStringFromClass([AppDelegate类]);
}
}

考虑这个较短的示例(在btw中运行):


我认为你误解了复制的作用

NSMutableString *string = [NSMutableString stringWithString:@"test"];

XYZPerson *guy = [XYZPerson init];
guy.firstName = string;
guy.lastName = string;

[string replaceCharactersInRange:NSMakeRange(1, 1) withString:@"x"];

[guy sayHello];

输出

This is test txst
在本例中,
firstName
是copy do,它在
string
更改时不会更改,
lastName
不是copy,因此它的值在可变字符串
string
更改时更改



这里发生的是
lastName
string
是同一个对象,因此当
string
更改时,
lastName
作为副作用更改。这被认为是非常糟糕的,你永远不会想要这种行为。使用copy可以确保
firstName
string
是不同的对象,对
string
的更改不会影响
firstName

我在写同一本书时遇到了这个问题。我添加了copy,发生了完全相同的事情,当我向我用于firstName的NSMutableString变量添加某些内容时,它不断发生变化。然后我读了这一节:

如果需要直接设置副本属性的实例变量,例如在初始化器方法中,请不要忘记设置原始对象的副本:

-(id)initWithSomeOriginalString:(NSString*)aString{
self=[super init];
如果(自我){
_instanceVariableForCopyProperty=[aString copy];
}
回归自我;
}

所以,我回到我的XYZPerson.m中,查看我的初始化代码

我改变了:

- (id)initWithFirstName:(NSMutableString *)aFirstName lastName:(NSString *)aLastName
        dateOfBirth:(NSDate *)aDate    {
self = [super init];

if (self) {
    _firstName = aFirstName;
    _lastName = aLastName;
    _dateOfBirth = aDate;
}

return self;
}

致:

}


普雷斯托·昌戈:它的工作方式是正确的!它复制了我使用的NSMutableString,当我在方法调用之前在它的末尾添加了一些东西时,它没有发生变化。

你能澄清你的问题吗?是的,当然。我所读到的关于copy属性的所有内容都表明,设置为该属性的属性不会更改以反映传递对象中的更改。在我的代码中,我认为修改guy对象的“firstName”属性不会有任何影响,因为该属性是用copy属性声明的。谢谢你的帮助。这有助于我以不同的方式看待这个问题。不过我对这个问题还是有点模糊。你能给出一个简短的(可能更实际的)例子吗?在这个例子中,使用这个属性真的可以防止相关数据被破坏吗?有些人甚至认为应该声明任何具有可变子类的不可变对象-copy@smitty举个例子,在任何情况下,有人可能会把地毯从你脚下拉下来。例如,NSMutableDictionary是一个哈希表,即计算索引的数组,将键转换为数字并将其映射到数组位置。如果将对象存储在关键点上,然后更改该关键点,则对象会突然位于错误的阵列位置(因为新关键点映射到阵列中的其他位置)。要防止类的客户端对其执行这种可怕的操作,最简单的方法是让NSMutableDictionary复制key.ok。这是有道理的。我从来没有这样想过。正如我所说,我对Objective-C编程非常陌生,所以我还没有遇到任何这种性质的编码问题。谢谢你的帮助。
This is test txst
- (id)initWithFirstName:(NSMutableString *)aFirstName lastName:(NSString *)aLastName
        dateOfBirth:(NSDate *)aDate    {
self = [super init];

if (self) {
    _firstName = aFirstName;
    _lastName = aLastName;
    _dateOfBirth = aDate;
}

return self;
- (id)initWithFirstName:(NSMutableString *)aFirstName lastName:(NSString *)aLastName
        dateOfBirth:(NSDate *)aDate    {
self = [super init];

if (self) {
    _firstName = [aFirstName copy];
    _lastName = aLastName;
    _dateOfBirth = aDate;
}

return self;