Object-c的一些基本概念
自学了一个多月的IOS,对Object-C也有了初步的认识,也有很多观点不知道是否正确,所以整理了一下,和小伙伴们分享分享
1.OC中使用的消息机制代替调用方法
区别:使用消息结构的语言,其运行时缩引执行的代码是由环境来决定的,而函数调用的语言则是用编译器来决定的
2.对象等同性
判断两个对象是否想同,不要使用 ==操作符来判断,因为该操作符比较的是两个指针本身,而不是指针所指的对象,应该用NSObject协议中声明的isEquel方法来判断两个
对象的等同性!两个不同的对象总是不想等的!
NSString *oneStr = @"abc123";
NSString *twoStr = [NSString stringWithFormat:@"abc%i",];
BOOL equalA = (oneStr == twoStr);//NO
BOOL equalB = [oneStr isEqual:twoStr];//YES
BOOL equalC = [oneStr isEqualToString:twoStr];//YES
判断两个对象等同性的关键方法
(BOOL)isEqual:(id)object;
@property (readonly) NSUInteger hash;
注意:
若想监测对象的等同性,提供
isEqual:
与 hash 方法相同的对象必须具有相同的哈希码,但是两个哈希码相同的对象却未必相同
不要盲目逐个检测每条属性,而是应该依照具体需求来制定监测方案
编写 hash 方法时,应该是用计算速度快而且碰撞低的算法
3.setter 方法 getter 方法
setter 方法:
》1.一定是对象方法
》2.一定没有返回值
》 3.方法名称一定以set开头,后面要设置的属性去掉下划线,首字母大写
》 4.一定要有参数,参数的类型需要和设置的属性类型一致,并且参数名称就是属性名称去掉下划线
getter 方法:
》1.一定是对象方法
》2.一定有返回值,且返回值类型一定与属性类型一致
》 3.方法名称就是属性名称去掉下划线
》4.一定没有参数
4.继承
》1,子类方法名和父类方法名相同,我们称之为方法重写
》2,对象方法和类方法都可以重写
》3,成员变量不能重写
》何时使用继承?
XXX是xxx 或者 XXX is a xxx
》 [super 方法名]/[self 方法名]
supper 指定调用父类的方法
self:先在子类中查找,再在父类中查找
supper:直接在父类中查找
5.多态:父类指针指向子类对象
6.动态类型(id):在编译的时候只会检查当前类型对应的类中有没有需要调用的方法,在运行时,才会判断它的真实类型! 动态数据类型一般用于多态
7.构造方法
》[Person new]和[[Person alloc]init]的区别
他们两基本相同,只是 new初始化只能调用init方法,init初始化的时候能调用其他方法;
》new 做了三件事
1.开辟存储空间 +alloc方法
2.初始化所有的属性(成员变量) -init方法
3.返回对象地址
》动态数据类型与静态数据类型的区别
8.重写init 方法
》注意:必须按照苹果的规定格式来,否则会引发错误
1.必须先初始化父类,再初始化子类
2.必须判断父类是否初始化成功,只有父类初始化成功,才能继续初始化子类
3.返回当前对象的地址
4.instancetype只能作为返回值类型,不能作为形参和变量类型
5.为什么不使用ID?因为ID是动态类型,程序在编译时不会检查类型,而在运行时检查,为了使程序编译时发现错误,使用了instancetype
不带参数初始化:
-(instancetype)init
{
self=[super init];//先初始化父类
if (self!=nil) {//必须判断父类是否初始化成功
_age=;
}
return self;
}
带参数初始化
//initWithAge W要大写 属性名称不要以new开头,否则有可能引发未知错误,方法名也不要以new开头
-(instancetype)initWithAge:(int)age WithName:(NSString *)name
{
self=[super init];
if (self!=nil) {
_age=age;
_name=name;
}
return self;
}
9.自定义类工厂方法
》自定义类工厂方法是苹果的一个规范,一般情况下,我们会给一个类提供自定义构造方法和自定义类工厂方法用于创建一个对象
》提供对象方法 叫做构造方法
》提供类方法 叫做类工厂方法
Person*p=[Person person];
p.age=;
NSLog(@"%i",p.age);
Person *p2=[Person personWithAge:];
NSLog(@"%i",p2.age);
/*
》什么是类工厂方法:
用于快速创建对象的类方法,我们称之为类工厂方法
类工厂方法主要用于 给对象分配存储空间和初始化这块存储空间 》规范:
1.一定是类方法 +
2.方法名称以类名开头,首字母小写
3.一定有返回值,返回值是 id/instancetype
*/
@interface Person : NSObject
@property int age;
//定义一个无参数类工厂方法
+(instancetype)person;
//带参数的类工厂方法
+(instancetype)personWithAge:(int)age;
@implementation Person
//实现无参数类工厂方法
+(instancetype)person
{
return [[self alloc]init];//这里最好使用self来调用,否则有继承关系时会出错 }
+(instancetype)personWithAge:(int)age
{
Person *p= [[self alloc]init];
p.age=age;
return p;
}
@end
10.类的本质
》1. 类其实也是一个对象,这个对象会在这个类第一次被使用时创建
2.只要有了类对象,将来就可以根据类对象来创建实例对象
3. 实例对象中有一个isa指针,指向创建自己的类对象
》 类对象中保存了当前对象所有的对象方法
当给一个实例对象发送消息时,会根据实例对象中的isa指针去对应的类对象中查找
Person *p1=[[Person alloc]init];
Person *p2=[[Person alloc]init];
//1.如何创建类对象
//[实例对象 class],[类名 class]
//一个类在内存中只有一个类对象
Class c1=[p1 class];
Class c2=[p2 class];
Class c3=[Person class];
NSLog(@"c1:%p,c2:%p,c3:%p",c1,c2,c3);//结果 c1:0x100001140,c2:0x100001140,c3:0x100001140 //2.类对象的应用场景
//》1.用于创建实例对象
Person *p3=[[Person alloc]init];
//》2.用于调用类方法
[p3 test];
11.load和initialize方法何时加载
/*
只要程序启动,就会将所有类的代码加载到内存中,放到代码区
load方法会在当前类被加载到内存的时候调用,有且只调用一次
如果存在继承关系,会先调用父类的load方法,再调用子类的load方法
*/
+(void)load
{
NSLog(@"类第一次被加载的时候调用");
} //当前类第一次被使用的时候调用(也会是创建类对象的时候)
//initialize在整个程序的运行过程中只会调用一次,不管这个类被使用了多少次,都只会调用一次
//initialize用于对某个类一次性的初始化(如果有些东西只需要做一次,就把这些东西写在initialize里面)
//如果存在继承关系,会先调用父类的initialize方法,再调用子类的load方法
+(void)initialize
{
NSLog(@"类第一次被使用时调用了");
}
12.SEL
int main(int argc, const char * argv[]) {
@autoreleasepool {
//》SEL类型的第一个作用,配合对象/类来检查对象/类中有没有实现某一个方法
SEL sel=@selector(setMyage:);
Person *p=[[Person alloc]init];
//》判断person 中有没有setMyage:这个方法,如果有,就会返回true(1),如果没有,就会返回false(0)
//》respondsToSelector 如果通过对象来调用该方法,则会判断对象中有没有实现-号开头的方法
//》 如果通过类来调用该方法,则会判断该类中有没有实现+号开头的方法
BOOL b= [p respondsToSelector:sel];
NSLog(@"b:%i",b);
BOOL c= [p respondsToSelector:@selector(test)];
NSLog(@"b:%i",c);
BOOL d= [Person respondsToSelector:@selector(test)];
NSLog(@"b:%i",d);
//》2.SEL类型的第二个作用:配合对象/类来调用某一个SEL方法
[p performSelector:@selector(demo)];
//》withObject需要传递参数,
//注意:参数必须是对象类型,也就是说方法的形参必须是对象类型,因为withObject只能传递对象,否则会报错
//withObject最多只能传递2个参数
[p performSelector:@selector(demo:)withObject:@""]; //》3.SEL类型的第三个作用:
//配合对象 将sel对象作为方法的形参
Car *car=[[Car alloc]init];
SEL selcar=@selector(run);
Person *pp=[[Person alloc]init];
[pp makeObject:car andSel:selcar]; }
return ;
}
13.内存管理
》只要一个对象被释放了,我们就称为这个对象为“僵尸对象”
》当指针指向一个僵尸对象,我们就称这个指针为野指针
》只要给一个野指针发送消息就会报错
》 空指针:没有指向存储空间的指针 nil 0
》为了避免给野指针发送消息会报错,一般情况下,当一个对象被释放后我们会将这个对象的指针设置为空指针
》在OC中给空指针发送消息不会报错
》当A对象使用B对象时,一定要对B对象进行一次retain,这样才能保证A对象存在时,B对象也存在,也就是说,无论什么时候,A对象都可以使用B对象
当A对象释放时,一定要对B对象进行一次release,这样才能保证A对象释放时,B对象也会被释放,避免内存泄露!
》例如Person对象使用Room对象:
#import "Person.h" @implementation Person
-(void)setRoom:(Room *)room
{
if (_room!=room) {//判断传入的对象是否与当前对象一样
[_room release];//release以前的对象
//retain传入的对象
_room=[room retain];//retain 不仅会让引用计算器+1,还会返回当前对象
} }
-(void)dealloc
{
[_room release];
NSLog(@"%s",__func__);
[super dealloc];
}
@end
14.分类-Category
》方法分为:方法的声明,方法的实现,所以通过某个类扩充方法,也分为方法的声明和方法的实现
》分类的作用:
1.可以在不修改原有类的基础上,给这个类扩充一些方法
2.一个庞大的类可以分模块开发
3.一个庞大的类可以由多个人来编写,更有利于团队合作
》注意点:
1.分类是给原有类扩充方法的,它只能添加方法,不能添加属性
2.分类中使用@property,只会生成getter和setter的声明,不会生成实现,以及私有的成员变量
3.可以在分类中访问原有类的.H文件
4.一个类可以有很多分类
5.如果在分类中有和原有类重名的方法,会先调用分类中的方法,也就是说会忽略原有类的方法
6.如果多个分类都有重名的方法,那么执行谁是由编译器决定,谁最后被编译,就执行谁(在开发中尽量不要写重名的方法)
7方法的调用顺序:分类-->子类-->父类
15.Block
》1.block可以访问外界的变量
2.block中可以定义和外界同名的变量,如果和外界定义的是同名的对象,那么在block访问的是Block中的变量
3.默认情况下不可以在block中修改外界变量的值
因为block和外界的变量不是同一个变量
如果block中访问到外界的变量,block会将外界的变量copy一份到堆内存中
因为block中使用的外界的变量是copy的所以调用之前修改外界的变量是不会影响到block中copy的值
4.如果想在block中修改外界变量的值,必须在外界变量前加_block,
》block是存储在堆中还是栈中?
默认情况下是存储在栈中,如果对block进行copy,block会转移到堆中
如果在栈中,block访问了外界的变量,那么不会对对象进行retain操作
但如果在堆中,block访问了外界的变量,那么会对对象进行一次retain操作
//block和函数一样,可以没有返回值也没有形参,也可以有
//void(*roseBlock)();指向函数的指针
void(^roseBlock)(int);//定义一个block
roseBlock= ^(int num){
for (int i=; i<=num; i++) {
printf(" {@}\n");
printf(" |\n");
printf(" \\|/\n");
printf(" |\n");
}
};
//要想执行block保存的代码,必须调用
roseBlock();
//无返回值,有参数
void(^testBlock)(int)=^(int num)
{
for (int i=; i<num; i++) {
NSLog(@"---");
}
};
testBlock();
//有返回值,有参数
int(^sumBlock)(int,int);
sumBlock=^(int value1,int value2){
return value1+value2;
};
NSLog(@"sun:%i",sumBlock(,));
16:协议protocol
》协议的注意点:
1.协议只能声明方法,不能声明属性
2.父类遵守某个协议,子类也会自动遵守这个协议
3.在OC中一个类可以继承多个协议
但OC中的类只能有一个父类,也就是说OC中的类只有单继承(支持多层继承,不支持多继承)
4.OC中的协议可以遵守其他协议
#import <Foundation/Foundation.h> @protocol SportProtocol <NSObject>
//注意:如果没有任何修饰符修饰协议中的方法,默认情况下是@required(必须实现) 如果没有实现,则会报警告
//如果协议中的方法是@optional 如果遵守该协议的类,没有实现该方法,则不会报警告
//@required @optional仅仅是程序员之间的交流,不能控制是否一定实现该方法
@required
-(void)playFootball;
-(void)playBaskball;
@optional
_(void)play; @end
IOS交流群:5883244
Object-c的一些基本概念的更多相关文章
- Object.prototype和Function.prototype一些常用方法
Object.prototype 方法: hasOwnProperty 概念:用来判断一个对象中的某一个属性是否是自己提供的(主要是判断属性是原型继承还是自己提供的) 语法:对象.hasOwnProp ...
- Java中 VO、 PO、DO、DTO、 BO、 QO、DAO、POJO的概念
PO(persistant object) 持久对象 在 o/r 映射的时候出现的概念,如果没有 o/r 映射,没有这个概念存在了.通常对应数据模型 ( 数据库 ), 本身还有部分业务逻辑的处理.可以 ...
- Java中PO、DO、TO、DTO、 VO、 BO、POJO 、DAO的概念
本文系转载-原创@HollisChuang :http://www.hollischuang.com/archives/553 1.PO(persistant object) 持久对象 在 o/r ...
- Java中 VO、 PO、DO、DTO、 BO、 QO、DAO、POJO的概念(转)
PO(persistant object) 持久对象 在 o/r 映射的时候出现的概念,如果没有 o/r 映射,没有这个概念存在了.通常对应数据模型 ( 数据库 ), 本身还有部分业务逻辑的处理.可以 ...
- (1)Object类 (2)包装类和数学处理类 (3)String类
1.Object类1.1 基本概念 java.lang.Object类是Java类层次结构的根类,任何类都是Object类的直接/间接子类. 1.2 常用的方法(重点) Object() - 无参构造 ...
- Object的原型拷贝-create、assign、getPrototypeOf 方法的结合
一.实现原型拷贝 1.1.代码 tips:为了体现原型链,写了继承实现的代码,这部分可跳过- <script> /* 创建包含原型链的实验对象obj1-- start */ ...
- Java中 实体类 VO、 PO、DO、DTO、 BO、 QO、DAO、POJO的概念
PO(persistant object) 持久对象 在 o/r 映射的时候出现的概念,如果没有 o/r 映射,没有这个概念存在了.通常对应数据模型 ( 数据库 ), 本身还有部分业务逻辑的处理.可以 ...
- java对象 Java中 VO、 PO、DO、DTO、 BO、 QO、DAO、POJO的概念
PO(persistant object) 持久对象 在 o/r 映射的时候出现的概念,如果没有 o/r 映射,没有这个概念存在了.通常对应数据模型 ( 数据库 ), 本身还有部分业务逻辑的处理.可以 ...
- Java中POJO及其细分XO、DAO的概念
各层命名规约: A) Service/DAO 层方法命名规约 1) 获取单个对象的方法用 get 做前缀. 2) 获取多个对象的方法用 list 做前缀. 3) 获取统计值的方法用 count 做前缀 ...
- Java中PO、DO、DTO、 VO、 BO、POJO 、DAO、TO的概念
1. PO(persistant object) 持久对象 在 O/R 映射的时候出现的概念,如果没有 O/R 映射,没有这个概念存在了. 通常对应数据模型 ( 数据库 ), 本身还有部分业务逻辑的 ...
随机推荐
- java操作mysql的增删改查
prepareStatement(sql)是statement的子类,比statement好用. 如果数据库中定义的是int值,那么sql语句中要把int单独提出来.如".....value ...
- UVA 10003 Cutting Sticks 切木棍 dp
题意:把一根木棍按给定的n个点切下去,每次切的花费为切的那段木棍的长度,求最小花费. 这题出在dp入门这边,但是我看完题后有强烈的既是感,这不是以前做过的石子合并的题目变形吗? 题目其实就是把n+1根 ...
- #include <iomanip>
1 setfill 2 setprecision 3 setw 1 setfill setfill( 'c' ) 设填充字符为c ▲setfill(char c) 用法 : 就是在预设宽度中如果已存在 ...
- iOS 开发的几种手势
今天为大家介绍一下IOS 的七种手势,手势在开发中经常用到,所以就简单 通俗易懂的说下, 话不多说,直接看代码: // 初始化一个UIimageView UIImageView *imageView ...
- 系统学习Linux的11点建议
一.从基础开始 常常有些朋友在 Linux 论坛问一些问题,不过,其中大多数的问题都是很基础的.例如为什么我使用一个命令的时候,系统告诉我找不到该目录,我要如何限制使用者的权限等问题,这些问题其实都不 ...
- [置顶] ※数据结构※→☆非线性结构(tree)☆============树结点 链式存储结构(tree node list)(十四)
结点: 包括一个数据元素及若干个指向其它子树的分支:例如,A,B,C,D等. 在数据结构的图形表示中,对于数据集合中的每一个数据元素用中间标有元素值的方框表示,一般称之为数据结点,简称结点. 在C语言 ...
- ActionBar隐藏修改图标和标题
有时候在一些子页面或者内容页面,不需要显示ActionBar的标题栏图标.可用如下方式进行设置. 首先获取到ActionBar对象 ActionBar actionBar=getActionBar() ...
- CSS或者JS实现鼠标悬停显示另一元素
想达到鼠标悬停到元素a上,显示另一个元素b,可以通过css实现也可以通过js实现.js:写两个函数:mouseenter,mouseleave,例如:其中 $("#a").mous ...
- 在SQL Server 2008 中使用SQL脚本创建登录用户并授权
到处都使用超级用户sa显然是不安全的,因此有创建用户并让其只能访问某个数据库的必要.当然可以使用SQL Server自带的图形界面向导,但是太难用用了!有时候代码比较直接,比如这里: --使用已经创建 ...
- MyEclipse中jquery文件报错