Skip to content

Latest commit

 

History

History
283 lines (190 loc) · 7.1 KB

3.对象(三).md

File metadata and controls

283 lines (190 loc) · 7.1 KB

对象(三)

之前我们创建对象的作坊:

// new 是一个类方法,主要用于创建对象
Person *p1 = [Person new];

让1个指针指向1个对象,这个指针就叫做这个对象的名字,其实呢? 其实p1是一个指针。只不过我们都这样叫。

匿名对象

没有名字的对象,如果我们创建了1个对象,没有用1个指针存储这个对象的地址。也就是说没有任何指针指向这个对象,那么这个对象就叫做匿名对象。

[Person new]

我们可以直接使用

[Person new] -> _name = "haha";
[[Person new] sayHi];

static

C语言中的static可以修饰:

  • 局部变量
  • 全局变量
  • 函数

OC中的static关键字:

  • static不能修饰属性,也不能修饰方法
  • static可以修饰方法中的局部变量,如果方法中的局部变量被static修饰,那么这个变量就会变成静态变量。存储在常量区,当方法执行完毕后不会回收,下次再执行这个方法的时候回直接使用,而不会再声明了。

self

self用在对象方法中,指向当前对象,也就是说谁调用方法谁就是当前对象。

- (void)sayHi {
    NSLog(@"self = %@", self);
    NSLog(@"self = %@", self -> _name);
}

[self sayHi]

使用场景:

  • 如果在方法中存在和属性同名的局域变量,你如果想要访问的同名的局部变量,直接写就可以了,但是如果想要访问当前对象的同名属性(成员变量),这时候就必须使用self关键字。

  • 在对象方法中,如果要调用当前对象的其他的对象方法,必须使用self。

  • 用在类方法中,当类加载的时候会将类的代码存储在代码区,self就相当于当前的这个类。

    + (void)sb {
        // 应该是Person类在代码段的地址 0x100001290
        NSLog(@"self :", self);
    }
    

super

super关键字用于调用父类的方法:

[super sayHi];

。语法

OC可以像Java那样通过点去调用属性名

语法:

对象名.去掉下划线的属性名。

它内部会进行转换,将其转换为:
[对象名 set去掉下划线的属性名首字母大写:数据];

Person *p1 = [Person new];
p1.name = @"haha"
p1.age = 10;
// 会转换为
// [p1 setAge : 10];

但是如果我们的setter方法和getter方法不符合规范,那么点语法就会出问题。

@property

我们在写一个类的时候:

  • 先为类写属性。
  • 再声明该属性的getter和setter方法。
  • 再实现getter和setter方法。

有没有更简单的方式呢?

@property就是:它的作用是自动生成getter、setter方法的声明。因为是生成方法的声明,所以要写在@interface类的声明之中。

@interface Person : NSObject {
    NSString *_name;
    int _age;
}

// 自动生成_age的getter和setter方法的声明。 
@propterty int age;
@end

编译器在编译的时候会将@property 数据类型 名称; 生成为:

  • (void)set首字母大写的名称:(数据类型)名称;
  • (数据类型)名称;

@synthesize

作用: 自动生成getter、setter方法的实现,所以要写在类的实现中。

@implementation Person 
@synthesize age;	
@end

这种写法是在Xcode4.4之前的写法,从Xcode4.4以后,Xcode对@property做了一个增强。

只需要写一个@property,编译器就会自动:

  • 生成私有属性。
  • 生成属性的getter、setter的声明。
  • 生成getter、setter的实现。
@interface Student : NSObject 
@property NSString *name;
@end

NSObject

是OC中所有类的基类。根据LSP NSObject指针就可以指向任意的OC对象。 所以NSObject指针是一个万能指针,可以指向任意的OC对象。

但是,如果想要调用指向的子类对象的独有的方法,就必须要做类型转换。

NSObject *obj = [Person new];

id指针

是一个万能指针,可以指向任意的OC对象。

id是一个typedef自定义类型,在定义的时候已经添加了*,所以声明id指针的时候就不需要再添加*了。

但是它与NSObject的不同点在于:通过NSObject指针去调用对象的方法的时候,编译器会做编译检查。通过id类型的指针去调用对象的方法的时候,编译器会直接通过。 但是id指针不能使用点语法,如果使用点语法编译器会直接报错。如果我们声明一个万能指针,千万不要使用NSObject,而是使用id。

id id1 = [Person new];
[id1 sayHid];

new

上面,我们说到在创建对象的时候:

类名 *指针名 = [类名 new];

new实际上是1个类的方法。它的作用主要是:

  • 创建对象
  • 初始化对象
  • 把对象的地址返回。

new方法的内部,其实是先调用的alloc方法,再调用init方法。

alloc方法是一个类的方法,作用是创建该类的对象,并把对象返回。 init方法的作用是初始化对象。

所以

Person *p1 = [Person new];
完全等价于
Person *p1 = [[Person alloc] init];

重写init方法

我们在创建一个对象的时候,它的属性默认值都是nil、NULL、0 但是我们想让默认属性是我们自定义的,这时候就可以重写init方法,在这个方法中按照我们自己的想法为对象的属性赋值。

重写init方法的规范:

  • 必须要先调用父类的init方法,然后将方法的返回值赋值给self
  • 调用init方法初始化对象有可能会失败,如果初始化失败,返回的就是nil
  • 判断父类是否初始化成功,判断self的值是否为nil,如果不为nil说明初始化成功
  • 如果初始化成功,就初始化当前对象的属性
  • 最后,返回self的值
@implemetation Person 
- (instancetype)init {
	self = [super init];
	if (self) {
		self.name = @"jack";
	}
	return self;
}

@end

但是重写init方法后,每次创建出来的对象的属性值都是一样的。有时候创建对象的时候,对象的属性的值由创建对象的人来指定,而不是写死在init方法中。

这时候就需要用到自定义构造方法:

  • 自定义构造方法的返回值必须是instancetype
  • 自定义构造方法的名称必须以initWith开头
  • 方法的实现和init的要求一样。
@interface Dog : NSObject 
@property NSString *name;
@property int age;

- (void)shout;
- (instancetype)initWithName:(NSString *)name andAge:(int)age;
@end
@implementation Dog
- (void)shout {
	NSLog(@"wangwang...");
}
- (instancetype)initWithName:(NSString *)name andAge:(int)age {
    if (self = [super init]) {
    	self.name = name;
    	self.age = age;
    }
	return self;
}
@end

使用:

int main(int argc, const char *argv[]) {
	Dog *d1 = [[Dog alloc] initWithName:@"huang" andAge:2];
}