oc 基础知识

时间:2023-03-08 18:13:07

一、枚举 结构体

typedef enum{

sexMan,

sexWoman

}Sex;

tydedef struct{
   int year;
   int month;
   int day;
}Date;
二、类方法有参数声明
- (void)pingFang:(int)num;
一个参数对应一个冒号
三、封装
set方法(对参数进行过滤)
1、作用:提供一个方法给外界设置成员变量值。
2、命名规范:
  ①、方法名必须以set开头。
  ②、set后面跟上成员变量的名称,成员变量的首字母必须大写。
  ③、返回值一定void。
  ④、一定接收一个参数,而且参数类型跟成员变量类型一致。
  ⑤、形参名称不能跟成员变量名一致。
get方法
1、作用:返回对象内部的成员变量。
2、命名规范:
  ①、肯定有返回值,返回值类型肯定与成员变量一致。
  ②、方法名跟成员变量一样。
  ③、不需要接收任何参数。
成员变量命名规范:要以下划线开头。
作用:1、让成员变量和get方法的名称区分开。
        2、可以跟局部变量区分开,一看到下划线开头的变量,一般都是成员变量。
四、类方法
1、类方法不能访问成员变量
2、不依赖于对象,执行效率高
3、能用类方法,尽量用类方法
4、场合:当方法内部不需要使用到成员变量时,就可以改为类方法
五、self:指向方向调用者
self->age 访问当前对象的age
self的用途:
1、谁调用了当前方法,self就代表谁
  ①、self出现在对象方法中,self就代表对象方法。
  ②、self出现类方法中,self就代表类方法。
2、在对象方法利用“self->成员变量名”访问当前对象内部的成员变量。
3、[self 方法名]可以调用其他对象/类方法。
六、super(直接调用父类的方法)如:[super walk];
作用:
1、直接调用父类中的某个方法。
2、super处在对象方法中,那么就会调用父类的对象方法;super处在类方法中,那么就会调用父类的类方法。
3、使用场合:子类重写父类方法时,想保留父类的一些行为。
七、多态
多态的局限性:父类类型的变量不能用来调用子类的方法。
错误示范:
      Animal *a = [Doy new];
     [a run]; 报错
解决方法:
    Doy *d = (Doy *)a;//强转为子类
    [d run];
注意:
1、没有继承就没有多态。
2、代码的体现:父类类型的指针指向子类的对象。
3、好处:如果函数/方法参数中使用的是父类类型,可以传入父类,子类对象。
void feed (Animal *a)//a可以传入父类,也可以是子类对象
{ [a eat]; }
八、声明变量
@property int age;//可以系统自动生成某个成员变量的get和set的声明
注意:当自定义getter和setter方法,系统不会实现生成_age变量。
九、万能指针id
id d;//能指向/操作任何oc对象,相当于NSObject *。
tepedef struct objc_object{
    class isa;
}*id;
十、category分类:
分类名称:类名+模块
使用注意:1、分类只能增加方法,不能增加成员变量。
              2、分类方法实现中可以访问原来类中声明的成员变量。
              3、优先去分类中查找方法,然后再去原来类中找到,最后去父类中找。
              4、分类可以重新实现原来类中的方法,但是会覆盖掉原来的方法,会导致原来的方法没法再使用。
              5、多个分类,最后参与编译的分类优先。(点项目 -> Build phases -> complile sources)
              6、如果想添加变量,可以考虑通过继承创建子类。
十一、一些类函数调用时机
当程序启动的时候,就会加载一次项目所有的类。
//1、在类被加载完毕的时候调用load
+ (void)load
{
    NSlog(@"调用了test方法");
}
//2、当第一次使用这个类的时候,就会调用一次 + initialize方法。
+ (void)initialize
{
    NSlog(@"调用了initalize");
}
//有分类时,调用person类,分类initialize覆盖person
//先加载父类再加载子类,先加载原始类再加载分类
//3、决定实例对象的输出结果
打印对象NSLog(@"%@",p);
- (NSString *)description
{
}
①、默认情况下,利用NSlog和%@输出对象时,结果是:<类名:内存地址>
②、会调用对象P的-description方法
③、拿到-description方法的返回值(NSString *)显示在屏幕上。
④、-description方法默认返回的是“类名+内存地址”
⑤、在-description内调用NSLog(@"%@",self);会引起死循环
+ description //决定了类对相当输出结果
十二、 SEL
1、方法的存储位置
①、每个类的方法列表都存储在类对象中
②、每个方法都有一个与之对应的SEL类型的对象
③、根据一个SEL对象就可以找到方法的地址,进而调用方法
④、SEL类型的定义:typedef struct objc_selector  *SEL;
2、SEL对象的创建
SEL s = @selector(test); [p performSelector:s];
SEL s2 = NSSelectoFromString(@"test");
3、_cmd代表当前方法
每个方法里面都有一个_cmd
//也会引起死循环:[self performSelector:_cmd];
4、SEL其实是对方法的一种包装,将方法包装成一个SEL类型的类型,去找对应的方法地址。找到方法地址就可以调用方法。
十三、内存管理
1、对象的基础结构:
每个oc对象都有自己的引用计数器,是一个整数,表示“对象被引用的次数”,即有多少人正在使用这个oc对象,当引用计数器为0时,对象占用的内存被系统回收。
2、给对象发送一条消息:
retain,引用计数器+1,返回的是对象本身。
release,引用计数器-1。
retainlout,获得当前引用计数器值。
3、对象销毁
①、当一个对象被销毁时,系统会自动向对象发送一条dealloc消息。
②、一般会重写dealloc方法,在这里释放相关资源,dealloc就像对象的遗言。
③、一旦重写dealloc方法就必须调用[super dealloc],并且放在最后面调用
④、不要直接调用dealloc方法
⑤、一旦对象被回收了,它占用的内存就不再可用,坚持使用会导致程序奔溃,野指针错误。(野指针:指向僵尸对象的指针)
EXC_BAD_ACCESS(野指针错误):访问了一块坏的内存(已经被回收,已不可用的内存)
野指针错误的解决方法:让指针p=nil;
十四、内存管理规范
1、只要调用alloc,必须有realease(autorelease)
2、set方法的代码规范:
①、基础数据类型:直接复制
- (void)setAge:(int)age
{
    _age = age;
}
②、oc对象类型
- (void)setCar:(Car *)car
{
    //1、先判断是不是新传进来的对象
    if(car != _car)
    {
          //2、对旧对象做一次release
          [_car release];
         //3、对新对象做一次retain
         _car = [car retain];
    }
}
当用@property int age;需要自定义setter和getter。
当自定义setter和getter方法,就不会生成_age变量。
3、dealloc方法的代码规范
①、一定要[super dealloc],而且放到最后。
②、对self(当前)所拥有的其他对象做一次release
- (void)dealloc
{
  [_car release];//被retain过的属性,必须在dealloc方法中release属性
  [super dealloc];
}
十五、@property的参数
1、set方法内存相关的参数
①、retain:release旧值,retain新值(适用于oc对象类型)
②、assign:直接赋值(默认,适用于非oc对象类型)
③、copy:release旧值,copy新值
 2、是否要生成set方法
①、readwrite:同时生成setter和getter的声明、实现(默认)。
②、readonly:只会生成getter的实现、声明。
3、多线程管理
①、nonatomic:性能高,不生成多线程线管代码(一般要选用这个)
②、atomic:性能低(默认)
4、setter和getter方法的名称
①、setter决定了set方法的名称,后面要加冒号:
②、getter决定了get方法的名称(一般用在bool类型)
@property (nonatomic,assign,setter = abc:,getter = cd)int height;
5、指针
①、强指针strong
②、弱指针weak
十六、循环引用
1、开发中引用一个类的规范
①、在.h文件中用@class来声明类
②、在.m文件中用#import来包含类的所有内容
2、当两端循环retain,即A对象retain B对象,B对象retain A对象,导致A,B对象永远无法释放
解决方案:一端用retain,一端用assign
十七、自动释放池autorelease
atorelease会将对象放到一个自动释放池中,当自动释放池被销毁时,会对池子里面的所有对象做一次release操作
int main()
{
@autoreleasepool{
       //开始代表创建了释放池
person *p = [[[person alloc] init]autorelease];
p.age = 10;
 }//结束代表销毁释放池
return 0;
}
 注意:占用内存较大的对象