002-对象与使用

对象与使用

创建类

objective-c 中的类可以视作一种单元,也包括 .h 接口文件和 .m 定义文件两部分。对于一个类,基本元素包括数据、属性和方法等。

类的接口文件

创建一个与类名一致的 .h 接口文件,在接口文件中通过 @interface 来声明类的详细接口。

@interface Animal : NSObject
{
    NSString * name;
    NSString * size;
    NSString * color;
}
@property (nonatomic, retain) NSString * hobbit;

-(void)eat: (NSString *) food;

@end

要注意必须用 @end 结束 @interface。

在类的声明中,类名紧跟的冒号后指定类的直接父类,有且只有一个。

在紧跟类名的大括号中可以定义类的成员变量即实例变量,也称作 ivar,其作用域是作为类的一部分定义的任何方法,也即在类的方法中均可以访问,但外部无法访问。

对于类的方法,其返回类型在方法名前的括号定义,其参数在方法名后的冒号后定义。

类的定义文件

创建一个与类名一致的 .m 文件,定义文件中用 @implementation 和 @end 来定义类接口的具体实现。

@implementation Animal

@synthesize hobbit = _hobbit;

-(id)init
{
    if (self = [super init])
    {
        name = @"Animal";
    }
    return self;
}

-(void)eat: (NSString *)food
{
NSLog(@"%@ eat %@", name, food);
}

-(void)dealloc
{
    name = nil;
}

@end

方法

在 objective-c 中,调用方法又称为发送消息,objective-c 会首先寻找接收消息的对象,也叫做实例,然后通过对象的 isa 指针找到对象的类,再通过类的指针找到需要调用的方法。

1. 类的方法

类的方法是指不需要生成实际对象实例就可以调用的方法,在声明和实现时用 + 号修饰。

接口声明

+(NSString *)getType;

方法定义

+(NSString *)getType
{
    return @"Animal";
}

2. 对象方法

对象方法是只有在对象实例化以后才能调用的方法,用于计算或改变对象内的数据,用 - 号修饰。

接口声明

-(void)eat: (NSString *) food;

方法定义

-(void)eat: (NSString *)food
{
NSLog(@"%@ eat %@", name, food);
}

3. 特殊对象方法

特殊对象方法是指一些具有特定功能和标准行为的方法,最常见的有初始化方法和析构方法。

  • 初始化方法

    -(id)init
    {
        if (self = [super init])
        {
            name = @"Animal";
        }
        return self;
    }
    

    初始化方法函数名以 init 打头,返回值类型为 id,初始化方法第一步要先调用指定父类的初始化函数,然后判断是否初始化成功,如果失败则返回 nil 对象,如果成功则继续初始化类的数据成员。当然在指定父lei的初始化函数之前,应该声明当前类所直接继承的父类。

    对于 id 数据类型,可以理解为一种指向对象的指针,可以表示所有对象的特殊数据类型,但 id 类型由于不是确定的类型,因此编译器在编译时将无法检测一些错误,并且会在运行时因为查找数据类型而带来性能上的缺失。

    很多时候对于一个对象我们需要多种不同的初始化方法来满足具体的初始化条件

    -(id)init
    {
        if (self = [super init])
        {
            name = @"Animal";
        }
        return self;
    }
    
    -(id)init: (NSString *) name
    {
      if (self = [self init]) //内存泄漏
        {
            self->name = name;
        }
        return self;
    }
    

    在初始化函数中也可以调用 self 的其他初始化函数,或是指定初始化函数并被其他初始化函数调用。

    self 是一个隐蔽的参数,它在调用方法即发送消息时被传递进方法内,它所引用的就是消息的接受对象。

    在方法中用 - 引用成员变量即实例变量。

    而 super 既不是参数也不是实例变量,而是一种功能,作用是向该类的超类发送消息,按照继承链依次向上寻找。

  • dealloc 方法

    dealloc 方法用于释放对象所分配的资源。

  • description 方法

    类似 Java 的 toString 方法,实现对一个对象的字符串表示。

    -(NSString *)description
    {
        return @"I am an animal";
    }
    
    NSLog(@"%@", animal);
    

对象

对象是类的实例,声明和初始化一个对象方式如下。

Animal * animal = [[Animal alloc]init];

这里要注意,在 objective-c 中,对于对象和类的方法的调用是通过中括号来调用的,如果方法有参数则放在冒号后面

[animal eat: @"rabbit"];

alloc 函数是一个类方法,用于开辟一个内存空间给对象,它会返回一个对象,对象类型就是调用 alloc 函数的类的类型。

对于不希望被外部调用和访问的方法,可以不在接口文件中声明,但要注意,这类私有方法必须要在使用方法前声明该方法或直接定义该方法。这段描述来自书上,但我的测试来看是没有这一限制的。

属性

在 objective-c 中,属性和数据成员是不一样的,成员数据会在内存中真正存储数据,而属性只是提供对于成员数据的存取器函数,如赋值函数和取值函数。

属性声明对象的状态

在这里继续对于 Animal 类的完善,如果我们加上属性的话,那么可以写成如下形式

接口文件

@interface Animal : NSObject
{
    NSString * name;
    NSString * size;
    NSString * color;
    NSString * birthDate;
}
@property(nonatomic, retain) NSString * name;
@property(nonatomic, retain) NSString * size;
@property(nonatomic, assign) NSString * color;
@property(nonatomic, retain) NSString * birthDate;
@property(nonatomic, readonly) NSString * age;

-(id)init;
-(id)initWithName:(NSString *)name;
-(void)eat: (NSString *) food;

+(NSString *)getType;

@end

定义文件

@implementation Animal

@synthesize name;
@synthesize size;
@synthesize color;
@synthesize birthDate;
@dynamic age;

-(NSString *)calculateAge: (NSString *)birthDate
{
    return @"";
}

-(NSString *)age;
{
    return [self calculateAge:birthDate];
}

-(id)init
{
    if (self = [super init])
    {
        name = @"Animal";
    }
    return self;
}

-(id)initWithName: (NSString *) aname
{
    if (self = [self init])
    {
        self->name = aname;
    }
    return self;
}

-(void)eat: (NSString *)food
{
NSLog(@"%@ eat %@", name, food);
}

+(NSString *)getType
{
    NSLog(@"Animal");
    return @"Animal";
}

-(void)dealloc
{
    name = nil;
}

@end

这里看到对于声明的数据成员,都用同样命名的属性提供了相应的存取方法,同时还带有对于属性的描述特性,简单总结一下。

  • getter=<name>, setter=<name>,可以指定存取器函数
  • readwrite,readonly,可读可写或仅可读
  • assign,retain,copy,针对赋值操作,这里涉及到对内存管理和引用次数的内容,因此简单记录下
    • assign 是默认特性,简单进行赋值操作,常用于NSInteger等OC基础类型,以及short、int、double、结构体等C数据类型,因为这些类型不存在被内存回收的问题
    • retain 赋值时保留传入参数,实际是保留一个引用次数
    • copy 复制传入参数到成员变量
  • nonatomic 和 atomic,atomic 可以保证原子性操作,也即线程安全,但会带来性能损失,默认是 atomic,如果是在单线程环境下可以用 nonatomic 特性
  • strong,weak,分别表示该属性对于数据成员的强弱饮用,强引用可以保证对象不会被自动回收
  • unsafe_unretained,与 weak 不同,被 unsafe_unretained 指针所引用的对象被回收后,unsafe_unretained 指针不会被赋为 nil,可能会导致程序出错

这些特性大部分与内存管理相关。

而针对定义文件,我们需要对属性进行实现,关键字有两个

  • synthesize,使编译器生成属性的存取器代码
  • dynamic,手动创建存取器函数

这里可以看到,我们将 age 设为了 dynamic,所以我们手动提供了相应的存取器函数,在这里我们实际上没有创建一个 age 的实际数据成员,而是用计算函数来确定,这就是属性对于内部数据的隔离保护和透明存取。

没有要求属性名和数据成员名保持一致,当然如果按照习惯可以将成员数据命名前加上下划线_,在 c# 中这样的变量表示字段。

属性的使用

属性使用有两种方式,传统方式就是一般的类或对象方法的调用。

NSLog(@"%@", [animal getColor]);

但属性还支持点标记访问

NSLog(@"%@", animal.color);

这里要注意对于自定义存取器函数,传统方式只能调用定义的存取器函数来访问,因为属性本身会被内部编译成赋值方法和取值方法。

依赖关系

依赖关系是两个实体之间的关系,前面在类文件头部加入的 import 语句就是建立依赖关系。当依赖的文件发生变化时,需要重新编译所依赖的文件,这种重新编译是从缘端至最末端的,因此有时会带来严重的编译问题。

所以可以用 @class 关键字代替 import语句,告知编译器当前依赖的文件仅仅是一个指向对象的指针,依据objective-c 的动态内存特性,可以稍后再得知其具体的内存空间。同时对于相互依赖的文件,用 import 语句也会报错,可以用 @class 代替。

但对于继承关系来说,由于编译器需要知道超类的所有信息才可以成功编译子类,所以依赖关系不能用 @class 代替。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容