黑马程序员——OC分类和本质探索

------- Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

一、分类

1、什么是分类

分类是为了给某一个类扩充方法,并且不修改原来的类。

2、分类的格式

// 声明

@interface 类名(分类名)

@end

// 分类的实现

@implementaion 类名(分类名)

@end

下面以为Person类添加分类来举例:

先定义一个类Person,下面是它的简单声明和实现:

//
//  Person.h
//  04-Category-分类
//
//  Created by rui on 4/3/15.
//  Copyright (c) 2015 itcast. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface Person : NSObject

- (void)test;

@end
#import "Person.h"

@implementation Person

- (void)test
{
    NSLog(@"调用了test方法");
}

@end
下面为Person类定义一个分类,分类名为HR:

//
//  Person+HR.h
//  04-Category-分类
//
//  Created by rui on 4/3/15.
//  Copyright (c) 2015 itcast. All rights reserved.
//

#import "Person.h"

@interface Person (HR)
// 创建一个学习的方法
- (void)study;

@end
#import "Person+HR.h"

@implementation Person (HR)

- (void)study
{
    NSLog(@"学习!");
}

@end

主测试程序:

//
//  main.m
//  04-Category-分类
//
//  Created by rui on 4/3/15.
//  Copyright (c) 2015 itcast. All rights reserved.
//

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

int main(int argc, const char * argv[]) {
    
    Person *p = [[Person alloc] init];
    
    [p test];
    [p study];
    
    return 0;
}
运行结果为:

2015-04-03 21:22:14.531 04-Category-分类[676:21021] 调用了test方法
2015-04-03 21:22:14.532 04-Category-分类[676:21021] 学习!

3、分类的好处

(1)一个庞大的类可以分模块开发
(2)一个庞大的类可以由多个人来编写,更有利于团队合作

4、分类的使用注意

(1)分类只能增加方法(包括类方法和对象方法),不能增加成员变量

(2)在分类方法的实现中可以访问原来类中的成员变量;

(3)分类中可以重新实现原来类中的方法,但是会覆盖掉原来的方法,导致原来的方法无法再使用(警告);

(4)方法调用的优先级:分类->原来的类->父类,若包含有多个分类,则最后参与编译的分类优先;

(5)在很多的情况下,往往是给系统自带的类添加分类,如NSObject和NSString,因为有的时候,系统类可能并不能满足我们的要求。

(6)在大规模的应用中,通常把相应的功能写成一个分类,可以有无限个分类,对原有类进行扩充,一般分模块写,一个模块一个分类。

(7)个Category中如果实现了相同的方法,只有最后一个参与编译的才会有效

5、给NSString类添加类方法

为NSString类添加一个计算字符串中阿拉伯数字个数的方法,所以为NSString添加一个Number分类Category

分类Category的声明:

//
//  NSString+Number.h
//  05-分类的应用
//
//  Created by rui on 4/3/15.
//  Copyright (c) 2015 itcast. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface NSString (Number)

+ (NSUInteger)numberCountOfString:(NSString *)str;
- (NSUInteger)numberCount;

@end
分类Number的实现:

//
//  NSString+Number.m
//  05-分类的应用
//
//  Created by rui on 4/3/15.
//  Copyright (c) 2015 itcast. All rights reserved.
//

#import "NSString+Number.h"

@implementation NSString (Number)

+ (NSUInteger)numberCountOfString:(NSString *)str
{
    // 获取NSString字符串的长度
    NSUInteger length = str.length;
    
    // 定义一个NSUInteger变量来接收字符串中阿拉伯数字的个数
    NSUInteger count = 0;
    
    // 遍历NSString字符串,取出所有的字符,判断是否是处于'0'和'9'之间
    for (NSInteger i = 0; i < length; i++){
        unichar c = [str characterAtIndex:i];
        if (c >= '0' && c <= '9'){
            count++;
        }
    }
   
    // 获取返回值
    return count;
}

- (NSUInteger)numberCount
{
    return [NSString numberCountOfString:self];
//    NSUInteger length = self.length;
//    
//    NSUInteger count = 0;
//    for (NSUInteger i = 0; i < length; i++){
//        unichar c = [self characterAtIndex: i];
//        if (c >= '0' && c <= '9')
//            count++;
//    }
//    
//    return count;
}

@end
测试主程序:

//
//  main.m
//  05-分类的应用
//
//  Created by rui on 4/3/15.
//  Copyright (c) 2015 itcast. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "NSString+Number.h"

int main(int argc, const char * argv[]) {
    NSString *str = @"hr199202rui05";
    NSUInteger count = [NSString numberCountOfString:str];
    
    NSLog(@"%ld", count);
    NSLog(@"%ld", [str numberCount]);
    
    return 0;
}
测试结果运行:

//
//  main.m
//  05-分类的应用
//
//  Created by rui on 4/3/15.
//  Copyright (c) 2015 itcast. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "NSString+Number.h"

int main(int argc, const char * argv[]) {
    NSString *str = @"hr199202rui05";
    NSUInteger count = [NSString numberCountOfString:str];
    
    NSLog(@"%ld", count);
    NSLog(@"%ld", [str numberCount]);
    
    return 0;
}

二、类的本质

1、类的本质

概念:其实类也是一个对象,是Class类型的对象,简称“类对象”

原理:类在内存中只创建一次,相对于内存来说,类是内存里的一个对象,是一个Class类型的对象。

以Person类来举例,一个Class类型的Person类类对象,在执行代码 Person *p = [[Person alloc] init]; 时会创建一个Person类的实例对象。而实例对象,我们知道在内存中可以创建任意多个(只要内存充足)。

Class类型的定义:

Typedef struct obj class *class;

类名就代表着类对象,每个类只有一个类对象。

创建实例对象有两种方式:

(1)利用class 创建 Person类--------------------->Class c = [Person class]; Person *p = [[class alloc] init];

(2)利用Person 创建Person类型的对象-------> Person *p=[[Person alloc] init];

获取类对象有两种方式:

(1)通过类对象来获取:Class c = [Person class];此处使用的是类方法

(2)通过实例对象来获取:Person *p = [[Person alloc] init]; Class c = [p class];此处使用的是对象方法

2、类的加载和初始化

类的加载和初始化涉及到两个类方法:

+load和+initialize

1、+load()

(1)在程序启动的时候会加载所有的类和分类,并调用所有类和分类的+load方法

(2)先加载父类,再加载子类;也就是先调用父类的+load,再调用子类的+load

(3)先加载元原始类,再加载分类

(4)不管程序运行过程有没有用到这个类,都会调用+load加载

2、+initialize()

(1)在第一次使用某个类时(比如创建对象等),就会调用一次+initialize方法

(2)一个类只会调用一次+initialize方法,先调用父类的,再调用子类的

定义一个Person类:

//
//  Person.h
//  06-类的本质
//
//  Created by rui on 4/3/15.
//  Copyright (c) 2015 itcast. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface Person : NSObject

@property int age;

+ (void)test;

@end
//
// Person.m
// 06-类的本质
//
// Created by rui on 4/3/15.
// Copyright (c) 2015 itcast. All rights reserved.
//

#import "Person.h"

@implementation Person

+ (void)test
{
NSLog(@"Class method test()");
}

// 在类被加载的时候调用,而且只会被加载一次
+ (void)load
{
NSLog(@"Person ---- load");
}

// 此函数当类第一次被使用到时会被调用
+ (void)initialize
{
NSLog(@"Person initialize");
}

@end
定义一个继承Person类的Student类:

//
//  Student.h
//  06-类的本质
//
//  Created by rui on 4/3/15.
//  Copyright (c) 2015 itcast. All rights reserved.
//

#import "Person.h"

@interface Student : Person

@end
//
//  Student.m
//  06-类的本质
//
//  Created by rui on 4/3/15.
//  Copyright (c) 2015 itcast. All rights reserved.
//

#import "Student.h"

@implementation Student

// 在类被加载的时候调用,而且只会被加载一次
+ (void)load
{
    NSLog(@"Student ---- load");
}

// 当类第一次被使用时会被调用
+ (void)initialize
{
    NSLog(@"Student initialize");
}

@end
定义一个Student的i类GoodStudent类:

//
//  GoodStuent.h
//  06-类的本质
//
//  Created by rui on 4/4/15.
//  Copyright (c) 2015 itcast. All rights reserved.
//

#import "Student.h"

@interface GoodStudent : Student

@end
//
//  GoodStuent.m
//  06-类的本质
//
//  Created by rui on 4/4/15.
//  Copyright (c) 2015 itcast. All rights reserved.
//

#import "GoodStudent.h"

@implementation GoodStudent

+ (void)load
{
    NSLog(@"Good Student ---- load");
}

+ (void)initialize
{
    NSLog(@"GoodStudent initialize");
}

@end
定义一个Person的分类:

//
//  Person+Test.h
//  06-类的本质
//
//  Created by rui on 4/4/15.
//  Copyright (c) 2015 itcast. All rights reserved.
//

#import "Person.h"

@interface Person (Test)

@end
//
//  Person+Test.m
//  06-类的本质
//
//  Created by rui on 4/4/15.
//  Copyright (c) 2015 itcast. All rights reserved.
//

#import "Person+Test.h"

@implementation Person (Test)

+ (void)load
{
    NSLog(@"Person (Test) load");
}

+ (void)initialize
{
    NSLog(@"Person (Test) initialize");
}
@end
在主测试函数中:

//
//  main.m
//  06-类的本质
//
//  Created by rui on 4/3/15.
//  Copyright (c) 2015 itcast. All rights reserved.
//

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

int main(int argc, const char * argv[]) {
//    Person *p = [[Person alloc] init];
//    Student *stu = [[Student alloc] init];
//    [[Person alloc] jnit];
    [[GoodStudent alloc] init];
    
    return 0;
}
编译运行函数之后得到:

2015-04-04 00:13:39.266 06-类的本质[1258:70964] Person ---- load
2015-04-04 00:13:39.268 06-类的本质[1258:70964] Student ---- load
2015-04-04 00:13:39.268 06-类的本质[1258:70964] Good Student ---- load
2015-04-04 00:13:39.268 06-类的本质[1258:70964] Person (Test) load
2015-04-04 00:13:39.269 06-类的本质[1258:70964] Person (Test) initialize
2015-04-04 00:13:39.269 06-类的本质[1258:70964] Student initialize
2015-04-04 00:13:39.269 06-类的本质[1258:70964] GoodStudent initialize


(1)当程序启动时,就会加载项目中所有的类和分类,而且加载后会调用每个类和分类的+load方法,只会调用一次;

(2)当第一次使用某个类时,就会调用当前类的+initialize方法;

(3)先加载父类,再加载子类(先调用父类的+load方法,再调用子类的+load方法,最后调用分类的+load方法),先初始化父类,再初始化子类(先调用父类的+initialize方法,再调用子类的+initialize方法)。

(4)注意:在初始化的时候,如果在分类中重写了+initialize方法,则会覆盖掉父类的。

(5)重写+initialize方法可以监听类的使用情况。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值