iOS开发之OC入门(OC类的基础知识)

类的定义

  • 类名需要大写开头
  • 属性开头下划线
 @inteface 类名: NSObject {
     @public // 外部可以访问
     NSString *_name;
     int _age;
 }
 @end

类加载

  • 程序运行期间,当类被第一次访问,会将其存储到代码段区域,叫做类加载
  • 直到程序结束才会被释放

对象在内存中存储

代码段
指针变量对象(属性) isa指针
  • 内存中申请一块空间存放指针变量
  • 内存创建一块大小合适的空间,根据类的模板创建对象
  • 对象会有isa指针指向代码段的对象所属的类
  • 初始化对象的属性,如果是基本数据类型为零,C语言指针为NULL,OC的类指针类型为nil
  • 访问对象属性:指针名->属性名;
  • 调用方法:[指针名 方法名];
  • 根据指针名找到在的对象,发现对象调用方法,再根据对象的isa指针在代码段找到类,然后调用类里面的方法
  • 每个对象的方法代码实现一样,没必要为每个对象保存一个方法,浪费空间,所有将其存在代码段里面
  • 代码段中每个类都有isa指针,指向他的父类,父类指向他的父类,最后指向元类

对象作为参数或者返回值

- (void)test:(Dog *)dog; 
- (Dog *)test:(Dog *)dog; 
  • 本质是地址传递
  • instancetype作为返回值指返回类型为该类

对象方法

  • 对象方法需要创建对象 ,可以直接调用类方法
- (返回值类型)方法名;

类方法

  • 类方法不依赖对象,直接通过类名调用
  • 优点:节约空间,提高效率,跳过堆,直接执行类中的类方法
  • 缺点:不能直接访问属性,也不能通过self直接调用当前类的其他的对象方法,但是可以在类方法创建对象并访问属性,
// 声明
+ (返回值类型)方法名;
// 调用
[类名 类方法名]
  • 类方法的规范:如果要求这个类提供一个和类同名的类方法,这个方法创建一个最纯洁的对象返回
  • 类方法和对象方法可以重名

对象方法中的self

  • self是一个指针,在对象方法中self指向当前对象,在类方法中指向当前类
  • 如果在方法中存在和属性同名的局部变量,访问局部变量直接写,访问对象同名属性,必须用self
  • 在对象方法中调用当前对象其他对象方法,必须使用self

匿名对象

  • 没有名字的对象,没有指针存储其地址,只能使用一次,每次创建都是不同的对象
  • new实际上是一个类方法,可以创建匿名对象

面向对象的三大特征(封装、继承、多态)

封装

  • 屏蔽内部实现,方便操作,后期维护方便
  • 实现方法:去掉@public,方法名需要set/get开头,首字母大写,去掉下划线

对象之间的关系

  • 组合关系:一个类是由其他几个类组合起来的
  • 依赖关系:一个对象的参数是另一个对象
  • 关联关系:一个类拥有另外一个类

继承

  • 继承后拥有父类所有成员,属性,方法
  • 不继承默认NSObject
  • 只能有一个父类,不能同时继承多个
  • 子类不能再定义一个同名的属性
@interface 类名 :父亲类的名称

@end

A从B继承,A是子类,B是父类
A从B派生,A是派生类,B是基类

重写

直接在类的实现中将方法重写

多态

同一个行为,不同事物不同表现

  • 通过继承+重写+里氏替换原则
  • 或者通过设计模式

里氏替换原则

子类可以替换父类的位置,并且程序并不受影响

	// 里氏替换原则
	Father *p = [Son new];
  • 1个指针不仅可以存储本类对象的地址,还可以存储子类对象的地址
  • NSOject类型指针可以存储任意OC对象的地址
  • 数组元素是OC指针类型,这个数组可以存储子类和父类对象
  • 数组元素是NSObject指针类型,任意OC对象都可以存储
  • 当父类指针指向子类对象的时候,这个父类指针只能去调用子类对象中的父类成员,子类独有的无法访问,如果重写则是重写完的方法
  • 如果指向子类对象的独有方法,就必须做类型转换
	NSObject *obj1 = [Person new];
	// 强制转换数据类型
	[(Person *)obj1 sayHi];

NSObject类

NSObject类是Foundation框架的类,这类有个类方法new,这个方法是用来创建对象,方法的返回值是创建这个对象的指针,这个类有个属性叫做isa指针
NSObject类是所有OC类的基类,根据LSP NSObject指针就可以指向任意OC对象,所有NSObject指针是一个万能指针

id指针

万能指针,可以指向任意的OC对象
id是一个typedef自定义类型,在定义的时候已经加了*,所有声明不需要再加
id指针不能用点语法

  • id指针和NSObject指针的相同点:万能指针,都可以执行任意的OC对象
  • id指针和NSObject指针的不同点:NOSject指针调用对象方法,编译器会检查,而id指针不会,故正常用id指针
/// 可被继承的创建自身类对象
+ (id)newself {
	return [self new];
}

instancetype类型

方法的返回值是instancetype,代表方法的返回值是当前这个类的对象

  • idinstancetype的区别:instancetype只能做方法的返回值,不能在别的地方使用,id既可以声明指针变量,也可以作为参数和返回值

Super关键字

  • 只可以用在类方法和对象方法中,不可以调用属性
  • 在对象方法和类方法中可以使用super关键字调用当前对象从父类继承过来的对象方法,也可以通过self来调用

访问修饰符

@private // 私有的,只能在本类的方法实现中访问,子类继承属性但不能直接访问,但可以调用父类的方法
@protected // 受保护的,只能在本类和子类中的方法访问
@package // 可以在当前框架中访问
@public // 可以在任意地方访问
  • 不指定默认为protected
  • 作用域是修饰符到另一个修饰符为止
  • 修饰符只能修饰属性,不能修饰方法

私有属性

@implementation {
	属性 // 真正的私有属性,修饰符无效,外界不显示
}

私有方法

方法不写声明只写实现,只能在本类中的其他方法调用,不能被外界调用

@class的使用

  • 当两个类相互包含的时候,Person.h中包含Book.h,而Book.h又包含Person.h的时候,就会出现循环引用的问题,无限递归导致编译无法通过
  • 解决方案:其中一边不要使用#import引入对方的头文件,而是使用@class 类名;来标注这是一个类,在.m文件中再引入对方的头文件

#import是将指定文件的内容拷贝到写指令的地方
@class并不会拷贝任何内容,只是告诉编译器这个一个类

结构体和类的区别

  • 结构体和类都能将多个数据封装为一个整体
  • 结构体只能封装数据,类还能封装行为
  • 结构体分配在栈空间,空间小但是访问效率高
  • 对象分配在堆空间,空间大但是访问效率低

方法的本质是SEL

SEL全称叫做selector选择器
SEL是一个数据类型,需要在内存中申请空间存储数据
SEL是一个类,SEL对象是用来存储一个方法
SEL是一个typedef类型,自定义时候已经加*了,声明时不需要再加

创建一个SEL对象 -> 将方法的信息存储在这个SEL对象之中 -> 再将这个SEL对象作为类对象的属性

// 获取SEL对象
SEL s1 = @selector(方法名); 
// 发送SEL消息
[p1 performSelector:s1]; 

// 等价于
[p1 方法名]
  • OC最重要的机制:消息机制
  • 调用方法的本质其实就是为对象发送SEL消息

动态类型检测

// 检测是否有这个对象方法(常用)
-(BOOL)respondsToSelector:(SEL)aSelector;
// 检测是否有这个类方法
-(BOOL)instanceRespondToSelector:(SEL)aSelector;
// 判断对象是否为指定类的对象或者子类的对象
-(BOOL)isKindOfClass:(Class)aClass;
// 判断对象是否为指定类的对象,不包括子类对象
-(BOOL)isMemberOfClass:(Class)aClass;
// 判断类是否为指定类的子类
+(BOOL)isSubclassOfClass:(Class)aClass;

Person *p1 = [Person new];
BOOL b1 = [p1 respondsToSelector:@selector(length)];
BOOL b2 = [p1 isKindOfClass:[Person class]];
BOOL b3 = [p1 isMemberOfClass:[Person class]];

new方法

  • new方法的内部是先调用alloc方法,再调用init方法
  • alloc方法是一个类方法,一个类调用这个方法 就创建那个类的对象,并把对象返回
  • init方法是一个对象方法,作用是初始化对象
Person *p1 =[Person new];
// 等价于
Person *p1 = [[Person alloc] init];

重写init方法规范

init方法是一个对象方法,作用是初始化对象

- (instancetype)init {
	// 调用父类初始化
	self = [super init]; 
	// 检查初始化是否成功 if(self)也可以
	if (self != nil) {	
		self.name = @"jack";
	}
	// 返回初始化的对象
	return self;
}

重写构造方法

initWith开头的函数才能是构造函数

- (instancetype)initWithName:(NSString *)name andAge:(int)age {
	if(self = [super init]) {
	self.name = name;
	self.age = age;
	}
	return self;
}

// 调用
Dog *d1 = [[Dog alloc] initWithName:@"huang" andAge:2];
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值