OC05核心语法总结 2


六、 分类

知识点

主题1:分类category依赖于类,新建时,创建category模板

1.不改变原来类模型的基础上来扩充方法
2.格式:
@interface 类名(分类名称)
 -
@end

@implementation 类名(分类名称)
@end
3.调用:首先把相应的头文件包含进来
[p study];//和以前调用方式一模样
4.如果(庞大的)类方法很多(模块)时,要好多人去写,这时就可以按人去分类,然后调用的时候该咋调用咋调用
5.总结:
    1)不改变原来类内容的基础上为类增加一些方法。
    2)只能增加方法,不能增加成员变量
    3)分类的实现是可以访问原来类里的成员变量
    4)如果扩充的方法名和原来的方法名一样时(重写),会覆盖原来的方法。
因为分类的方法的调用优先级高于原来的类方法,就是先去分类中找,然后再去原来的类去找,最后去父类
    5)那如果多个扩充文件里也存在的一样的呢?测试下,结果:是调用最后编译的分类方法。
    (因为相同名字方法编译一次覆盖一次,只保留最后一个)

主题2:给NSString 类添加类方法

1.系统自带的类,有时不能满足自己的需要:比如:要求求出字符串中含有的阿拉伯数字的个数
2.步骤:
    1*选在分类category模板 在NSString上分
    2*扩充一个类方法 +开头
3.声明和实现文件
//.h
#import <Foundation/Foundation.h>

@interface NSString (Number)

+ (int)numberCountOfString:(NSString *)str;

- (int)numberCount;

@end
//.m
#import "NSString+Number.h"

@implementation NSString (Number)
+ (int)numberCountOfString:(NSString *)str
{
    int count=0;//局部变量要进行初始化,不然后果很严重
    for (int i=0;i<[str length];i++
    {
        unichar c=[str characterAtIndex:i];//获取这个字符串的第i个字符
        if ( c>=‘0’&&c<=‘9’)
              {
            count++;
        }
    }
    return count;
}
@end

主题3:给NSString 类添加对象方法

#import "NSString+Number.h"

@implementation NSString (Number)
- (int)numberCount
{
int count=0;//局部变量要进行初始化,不然后果很严重
    for (int i=0;i<[self length];i++//当前字符串对象的
    {
        unichar c=[self characterAtIndex:i];//获取第一个字符
        if ( c>=‘0’&&c<=‘9’)
              {
            count++;
        }
    }
    return count;
} 
@end
技巧:可以在类方法里调用对象方法,也可以在对象方法里调用类的方法
类库:很多类的集合 包含它分类的头文件 就可以使用别人写好的东西了

七、 类的深入

知识点

1.类的本质

1)实际上类也是一个对象,那么这个对象的类型是什么?是Class类型,Class里已经包含* 里;简称类对象
2)利用Class 创建 Person类对象
3)利用Person类对象,创建 Person类型的 对象 Person *p=[Person new];
4)获取内存中的类对象:Class c=[p class]; //打印地址:%p;
5)获取内存中的类对象2:Class c=[Person class];//和4)结果是一样的

2.类对象的使用

1)调用类方法 + (void)test;
一般:利用类名 调用 [Person test];//类名就代表类对象
现在:Class c=[p class]; [c test];//用类对象调用
2)创建对象:Class c=[p class]; Person *p=[[c new] init];
3)一个类在内存中只拥有一份存储空间,这个空间就叫类对象

3.类的加载和初始化

1)类的加载:在加载时,调用+ (void)load;这个类方法。由系统自动调用(当程序用没用类时,都会做这件事)://程序一启动加载类时
2)利用这个特性,来监听
3)当程序使用类时,又会做更深调用:+(void)initialize;

4)测试,重写这些类方法打印下
5)分类category里,也会具有上述特性,优先选择分类的初始化,类的初始方法不再调用;但是加载时,类和分类都会加载

6)当程序启动时,就会加载项目中所有类和分类,而且加载后会调用每一个类和分类的+load方法,只会调用一次
7)当第一次使用某个类时,就会调用当前类的+initialize方法

8)先加载父类,再加载子类(先调用父类的+load再调用子类的+load)先加载原始类,再加载分类
当有分类时,分类优先调用+initialize,类不再调用+initialize)

9)想类第一次使用的时候,做些事情;这时就利用+initialize方法 //监听

代码举例

#import "Person.h"

@implementation Person
+ (void)test
{
    NSLog(@"调用了test方法");
}


// 当程序启动的时候,就会加载一次项目中所有的类。类加载完毕后就会调用+load方法
+ (void)load
{
    NSLog(@"Person---load");
}

// 当第一次使用这个类的时候,就会调用一次+initialize方法
+ (void)initialize
{
    NSLog(@"Person-initialize");
}

@end
//对应的main函数 注意把相应的头文件导入
int main()
{
    // 利用Person这个类创建了2个Person类型的对象
    Person *p = [[Person alloc] init];

    Person *p2 = [[Person alloc] init];

    Person *p3 = [[Person alloc] init];

    // 获取内存中的类对象
    Class c = [p class];

    Class c2 = [p2 class];

    // 获取内存中的类对象
    Class c3 = [Person class];


    NSLog(@"c=%p, c2=%p, c3=%p", c, c2, c3);
}

八、 description方法

知识点

description方法:在NSObject.h文件里可以找到

1.一种是-开头 类的
2.一种是+开头 对象的
3.需求:一个类的所有属性打印出来
方法1:NSLog(@“%@”,p);//打印OC对象,默认打印的时类名和对象地址;但是打印字符串,打印的却是字符串???;不能满足需求
原理:首先去调用对象p的-description方法,这个方法的返回值(NSString *),NSLog让这个返回值显示在屏幕上

-description方法默认返回的时 类名+内存地址

方法2:重写description方法来覆盖父类NSObject的description
-(NSString *)description()
{
    return @“13333”;
}
//实现需求
-(NSString *)description()//由NSLog的p调用;决定实例对象的输出结果
{
    return [NSString stringWithFomat(@“name=%d”,_name)];
}
4.+开头的description
需求:拿到类对象后,想输出类对象时,
打印时,会先调用类的+description方法,拿到这个的返回值,显示在屏幕上;默认返回值是类名;所以这个方法决定了类对象的输出结果
5.总之重写description可以更改输出样式,注意不能在这个方法里用NSLog,否则会造成死循环

九、 NSLog

知识点

1*指针变量的地址NSLog(@“%@”,&p)和p里存储的对象地址NSLog(@“%@”,p)不是一个概念
2*下划线下划线 __LINE__//输出行号;这个在文档帮助里的 Objctive-C→improved log。。。文件里可以找到
3*NSLog输出C语言字符串(char= “ddd就”)时,不能有中文,否则输不出任何东西
4*__func__:输出当前函数名
5*__FILE__:输出源文件名
6*_cmd :代表着当前方法的SEL
// 下面的代码会引发死循环
- (void)test {
    [self performSelector:_cmd];
}

十、 SEL

一种数据类型:SEL:一个SEL数据就代表一个方法

知识点

1.方法本身是怎么存的???
首先分配存储空间给这个类,类里面有个方法列表,但是这些方法是怎么存的呢?
注意:每一个方法在内存中都有一个SEL的数据和它对应。
方法调用:利用对象的isa找到它的类,然后去找这个方法
2.程序首先会把这个test包装成SEL类型数据,通过这个数据去找到这个方法地址,
最终通过这个地址找到所要调用方法,显然这个SEL数据里有方法的地址
注意:有个缓存列表存储上次查询后的结果,所以先到缓存去找,找不到,再去内存去找

3.怎么创建SEL数据:SEL s=@selector(方法名:);//有参数的方法 的 方法名是由冒号:的;然后可以用%d 输出
4.通过SEL间接调用方法:[p perfomSelector:s] //可以传参的 WithObject(id)特别注意→_→:有参数的方法 的 方法名是由冒号:的
5.打印字符串:%@
6.SEL:@selector的前三个字母的大写,它就是对方法的一个包装,所以可以通过它也能找到方法
7.方法都存在类对象中的

9.每个方法内部都有一个SEL类型的变量:_cmd//它代表当前方法;要打印出来它的值需要先转换成字符串 NSStringFormSelector(_cmd);
10.在方法里写:[self performSelector:_cmd];//会自己调用自己,陷入死循环
11.SEL其实是对方法的一种包装,将方法包装成一个SEL类型的数据,去找对应的方法地址。找到方法地址就可以调用方法
12.调用的方法很频繁时,可以直接把方法地址搞过来,直接去找到这个方法。高效
13.说的发消息就是发一个SEL类型的数据,根据这个数据找到方法的地址找到方法。所以本质上消息就是SEL。

代码举例

#import <Foundation/Foundation.h>
#import "Person.h"

int main()
{
    Person *p = [[Person alloc] init];

    [p test2];

    NSString *name = @"test2";

    SEL s = NSSelectorFromString(name);//把test2包装成SEL类型的数据

    [p performSelector:s];//根据SEL数据找到对应的方法地址

    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值