Objective c 为什么方法没有被调用

Objective c 为什么方法没有被调用,objective-c,class,methods,Objective C,Class,Methods,我试图学习如何创建类和对象,以及如何在Objective-C中调用方法。我的小程序创建了City类的对象,允许命名该对象,设置年龄、人口,并将这些值打印出来。但当我调用一个方法来设置这些值时,结果是一个(null)和零。这是我的密码: 城市 #import <Foundation/Foundation.h> @interface City : NSObject -(void) setName:(NSString *)theName Age:(int)theAge Populati

我试图学习如何创建类和对象,以及如何在Objective-C中调用方法。我的小程序创建了City类的对象,允许命名该对象,设置年龄、人口,并将这些值打印出来。但当我调用一个方法来设置这些值时,结果是一个(null)和零。这是我的密码:

城市

#import <Foundation/Foundation.h>

@interface City : NSObject

-(void) setName:(NSString *)theName Age:(int)theAge Population:(int)thePopulation;
-(void) getName;
-(void) getAge;
-(void) getPopulation;
-(void) nextDay;
@end
NS_ASSUME_NONNULL_BEGIN

@interface City : NSObject

@property (copy)   NSString *name;
@property (assign) NSInteger age;
@property (assign) NSInteger population;

- (instancetype)initWithName:(NSString *)name
                         age:(NSInteger)age
                  population:(NSInteger)population;

@end

NS_ASSUME_NONNULL_END
main.m

int main()
{
    City *moscow = [[City alloc] init];
    [moscow setName:@"Msk" Age:120 Population:1000];
    [moscow getName];
    [moscow getAge];
    [moscow getPopulation];
}
运行的结果是:

Name is (null)
Age is 0
Population today is 0
Program ended with exit code: 0

我做错了什么

问题在于,
City
的实例变量从未设置。
setName:Age:Population:
中的代码将实例变量(
name
Age
、和
Population
)的值分配给参数变量(
theName
theAge
thePopulation
)。交换这些参数将导致setter将参数分配给实例变量:

name = theName;
age = theAge;
population = thePopulation;

这就是说,Objective-C更惯用的做法是使用属性而不是实例变量和手动getter和setter,并使用初始值设定项来设置初始值。有了这些变化,城市等级将如下所示:

城市

#import <Foundation/Foundation.h>

@interface City : NSObject

-(void) setName:(NSString *)theName Age:(int)theAge Population:(int)thePopulation;
-(void) getName;
-(void) getAge;
-(void) getPopulation;
-(void) nextDay;
@end
NS_ASSUME_NONNULL_BEGIN

@interface City : NSObject

@property (copy)   NSString *name;
@property (assign) NSInteger age;
@property (assign) NSInteger population;

- (instancetype)initWithName:(NSString *)name
                         age:(NSInteger)age
                  population:(NSInteger)population;

@end

NS_ASSUME_NONNULL_END
城市

#import "City.h"

@implementation City
{
    NSString *name;
    int age;
    int population;
}
-(void) setName:(NSString *)theName Age:(int)theAge Population:(int)thePopulation
{
    theName = name;
    theAge = age;
    thePopulation = population;
}
-(void) getName
{
    NSLog(@"Name is %@", name);
}
-(void) getAge
{
    NSLog(@"Age is %d", age);
}
-(void) getPopulation
{
    NSLog(@"Population today is %d", population);
}
#import "City.h"

@implementation City

- (instancetype)initWithName:(NSString *)name
                         age:(NSInteger)age
                  population:(NSInteger)population
{
    self = [super init];
    if (self) {
        _name       = [name copy];
        _age        = age;
        _population = population;
    }
    return self;
}

@end
关于此代码,需要注意两件事:

  • 字符串在初始值设定项和属性中都被复制,以防止
    NSMutableString
    被传递,然后被变异(这也会变异
    name
    的值)。对于传递不可变的
    NSString
    的常见情况,副本相当于“retain”

  • 在初始值设定项中指定值时使用合成实例变量。这是为了防止子类重写任何这些属性,并在对象完全初始化之前运行自定义setter方法(将其所有变量设置为初始值)。这仅适用于初始值设定项、自定义设置项和解除锁定。其他所有内容都应使用属性来访问和修改这些值


  • 问题是,
    City
    的实例变量从未设置。
    setName:Age:Population:
    中的代码将实例变量(
    name
    Age
    、和
    Population
    )的值分配给参数变量(
    theName
    theAge
    、和
    thePopulation
    )。交换这些参数将导致setter将参数分配给实例变量:

    name = theName;
    age = theAge;
    population = thePopulation;
    

    也就是说,使用属性而不是实例变量和手动getter和setter以及使用初始值设定项来设置初始值更为惯用的Objective-C

    城市

    #import <Foundation/Foundation.h>
    
    @interface City : NSObject
    
    -(void) setName:(NSString *)theName Age:(int)theAge Population:(int)thePopulation;
    -(void) getName;
    -(void) getAge;
    -(void) getPopulation;
    -(void) nextDay;
    @end
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface City : NSObject
    
    @property (copy)   NSString *name;
    @property (assign) NSInteger age;
    @property (assign) NSInteger population;
    
    - (instancetype)initWithName:(NSString *)name
                             age:(NSInteger)age
                      population:(NSInteger)population;
    
    @end
    
    NS_ASSUME_NONNULL_END
    
    城市

    #import "City.h"
    
    @implementation City
    {
        NSString *name;
        int age;
        int population;
    }
    -(void) setName:(NSString *)theName Age:(int)theAge Population:(int)thePopulation
    {
        theName = name;
        theAge = age;
        thePopulation = population;
    }
    -(void) getName
    {
        NSLog(@"Name is %@", name);
    }
    -(void) getAge
    {
        NSLog(@"Age is %d", age);
    }
    -(void) getPopulation
    {
        NSLog(@"Population today is %d", population);
    }
    
    #import "City.h"
    
    @implementation City
    
    - (instancetype)initWithName:(NSString *)name
                             age:(NSInteger)age
                      population:(NSInteger)population
    {
        self = [super init];
        if (self) {
            _name       = [name copy];
            _age        = age;
            _population = population;
        }
        return self;
    }
    
    @end
    
    关于此代码,需要注意两件事:

  • 字符串在初始值设定项和属性中都被复制,以防止
    NSMutableString
    被传递,然后被变异(这也会变异
    name
    的值)。对于传递不可变的
    NSString
    的常见情况,副本相当于“retain”

  • 在初始值设定项中指定值时使用合成实例变量。这是为了防止子类重写任何这些属性,并在对象完全初始化之前运行自定义setter方法(将其所有变量设置为初始值)。这仅适用于初始值设定项、自定义设置项和解除锁定。其他所有内容都应使用属性来访问和修改这些值


  • 这看起来像是一个非常非常古老的教程中的代码。现代的ObjC看起来不像这样;一切都是
    @property
    s,getter方法的前缀从来都不是
    get
    。此外,实例变量很少被声明。这看起来像是一个非常古老的教程中的代码。现代的ObjC不需要好的,就像这样;所有内容都是
    @property
    s,getter方法的前缀永远不会是
    get
    。同样,实例变量也很少再声明了。