------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
黑马程序员-iOS基础-Objective-C基础(五)
核心语法(下)
1、构造方法
是对象的对象方法,用在类中
构造方法是用来初始化对象的方法,- 开头
如:创建对象[类名 new]
Person *p = [Person new];
/*
完整的创建一个可用对象
1.分配存储空间 +alloc类方法
2.初始化 -init对象方法
*/
//[Person new]等价于以下两句
//1.调用+alloc分配存储空间
Person *p1 = [Person alloc];
//2.调用-init进行初始化
Person *p2 = [p1 init];
//以上两句可以缩写成:
Person *p3 = [[Person alloc] init]; // 常用,有的情况下不一定会使用-init方法进行初始化
重写构造方法的目的
让对象创建出来,成员变量就会有一些固定的值
重写构造方法的注意点
1.调用父类的构造方法[super init]
2.再进行子类内部成员变量的初始化
子类父类-init方法执行过程
构造方法代码举例
Person.h
#import <Foundation/Foundation.h>
@interface Person : NSObject
@property int age;
@end
Person.m
#import "Person.h"
@implementation Person
- (id)init // 重写-init方法
{
/*
// 1.一定要调用回super的init方法:初始化父类中声明的一些成员变量和其他属性
self = [super init]; // 当前对象 self
// 2.如果对象初始化成功,才有必要进行接下来的初始化
if(self != nil)
{
//初始化成功
_age = 10;
}
// 3.返回一个已经初始化完毕的对象
return self;
*/
//可以简写为:以后用这种
if(self = [super init])
{
_age = 10;
}
return self;
}
@end
main.m
#import <Foundation/Foundation.h>
#import "Person.h"
int main(int argc, char const *argv[])
{
Person *p = [Person new];
/*
完整的创建一个可用对象
1.分配存储空间 +alloc类方法
2.初始化 -init对象方法
*/
//[Person new]等价于以下两句
//1.调用+alloc分配存储空间
Person *p1 = [Person alloc];
//2.调用-init进行初始化
Person *p2 = [p1 init];
//以上两句可以缩写成:
Person *p3 = [[Person alloc] init]; // 常用,有的情况下不一定会使用-init方法进行初始化
//要求每个Person对象创建出来,他的_age都是10,重写-init方法
Student *stu = [Student new];
return 0;
}
自定义构造方法
初始化时根据需要提供不同的变量得到不同的初始化结果
父类的属性交给父类方法处理,子类方法处理子类的属性
举例:
Person.h
#import <Foundation/Foundation.h>
@interface Person : NSObject
@property NSString *name;
@property int age;
/* 自定义构造方法的规范
1.一定是对象方法,一定以 - 开头
2.返回值一般是id类型
3.方法名一般以initWith开头
*/
- (id)initWithName:(NSString *)name;
- (id)initWithAge:(int)age;
- (id)initWithName:(NSString *)name AndAge:(int)age;
@end
Person.m
#import "Person.h"
@implementation Person
- (id)init // 重写-init方法
{
//可以简写为:以后用这种
if(self = [super init])
{
_name = @"Jack";
}
return self;
}
//自定义构造方法
- (id)initWithName:(NSString *)name
{
if(self = [super init])
{
_name = name;
}
return self;
}
- (id)initWithAge:(int)age
{
if(self = [super init])
{
_age = age;
}
return self;
}
- (id)initWithName:(NSString *)name AndAge:(int)age
{
if(self = [super init])
{
_name = name;
_age = age;
}
return self;
}
@end
Student.h
#import "Person.h"
@interface Student : Person
@property int no;
- (id)initWithNo:(int)no;
- (id)initWithName:(NSString *)name andAge:(int)age andNo:(int)no;
@end
Student.m
#import "Student.h"
@implementation Student
// 学生对象初始化完毕后,年龄是10,学号是1
- (id)initWithNo:(int)no
{
if(self = [super init])
{
_no = no;
}
return self;
}
- (id)initWithName:(NSString *)name andAge:(int)age andNo:(int)no
{
/*
if(self = [super init])
{
_no = no;
self.name = name; // [self setName:name]
self.age = age; // [self setAge:age]
}
*/
if(self = [super initWithName:name AndAge:age]) // 如果父类的成员变量应该尽量调用父类方法进行处理,可以避免父类变量改变后还需要在子类中修改
{
_no = no;
}
return self;
}
@end
main.m
#import <Foundation/Foundation.h>
#import "Person.h"
#import "Student.h"
int main(int argc, char const *argv[])
{
Person *p = [[Person alloc] initWithName:@"Rose"];
Student *stu = [[Student alloc] initWithName:@"Jim" andAge:15 andNo:7];
NSLog(@"Name=%@, Age=%d, No=%d", stu.name, stu.age, stu.no);
return 0;
}
更改Xcode模版
路径:应用程序-Xcode.app-右键显示包内容-Contents-Developer-Library-Xcode-Templates
2、分类Category
分类依赖于类,不允许修改原类、不允许继承的情况下给类扩充方法
格式:声明/实现
//声明
@interface 类名 (分类名称)
@end
//实现
@implementation 类名 (分类名称)
@end
文件名: "类名+分类名".h/.m
分类命名规则:分类名一般是作者姓名或者模块功能名称
作用:在不改变原来类内容的基础上,可以为类增加一些方法
使用注意
分类只能增加方法,不能增加成员变量;如果想添加变量,可以考虑继承
分类方法实现中可以访问原来类中声明的成员变量
分类可以重新实现原来类的方法,但是会覆盖掉原来的方法,会导致原来的方法失效
分类方法优先级最高,原来类/父类中同名的方法会被分类覆盖掉(不推荐)
方法调用的优先级:分类(最后参与编译的分类优先)-原来类-父类
好处
一个庞大的类可以分模块开发
一个庞大的类可以由多个人来编写,更有利于团队合作
练习:给NSString增加方法
#import <Foundation/Foundation.h>
/*
1.给NSString增加一个类方法:计算某个字符串当中阿拉伯数字的个数
2.给NSString增加一个对象方法:计算当前字符串中阿拉伯数字的个数
*/
//仅实现
@implementation NSString (Number)
//给NSString增加一个类方法:计算某个字符串当中阿拉伯数字的个数
+ (int)numberCountOfString:(NSString *)string
{
int count = 0;
for(int i=0;i<string.length;i++)
{
//取出i位置的对应字符
unichar c = [string characterAtIndex:i];
if(c >= '0' && C <= '9') // c >= 48 && C <= 57
{
count++;
}
}
return count;
}
//给NSString增加一个对象方法:计算当前字符串中阿拉伯数字的个数
- (int)numberCount
{
return [NSString numberCountOfString:self];
}
@end
3、类的深入研究
类的本质
类本身也是一个对象,是个class类型的对象,简称类对象
类对象 == 类
用Class创建类对象
利用类对象创建类类型对象
获取内存中的类对象
Class c=[p class];
Class c2 = [Person class];
类的加载过程
1.当程序启动的时候,就会加载一次项目中所有的类和分类
类加载完毕后就会调用+ (void)load方法,只会调用一次
2.当第一次使用这个类的时候(如创建对象),就会调用一次+ (void)initialize
3.先加载父类,再加载子类(先调用父类的+load方法,再调用子类的+load方法)
先初始化父类,再初始化子类(先调用父类的+initialize方法,再调用子类的+initialize方法)
4、description方法
打印OC对象用%@
-description
默认情况下,利用NSLog和%@输出对象时结果是:<类名:内存地址>
1.调用对象的-description方法
2.拿到-description方法的返回值(NSString *)显示到屏幕上
3.-description方法默认返回值是“类名+内存地址”
决定了实例对象的输出结果
+description
用NSLog和%@输出类的信息
1.会调用类的+description方法
2.拿到+description方法的返回值(NSString *)显示到屏幕上
决定了类对象的输出结果
如果要用NSLog(@"%@",p);打印出p的所有属性,就需要重写+/-description方法
注意:不要在description输出self,会死循环
5、NSLog补充
对象内存地址%p
NSLog(@"%p", p);取出p所指向对象的地址
NSLog(@"%p", &p);取出p的地址
NSLog(@"%@", &p); <类名: 对象地址>
用NSLog输出C语言字符串时,不能有中文,否则无法显示
6、SEL数据类型
一个SEL类型的数据就对应一个方法地址
SEL是对方法的一种包装,将方法包装成一个SEL类型的数据,去找对应的方法地址,找到方法地址就可以调用方法
当对象调用方法时
1.把方法名包装成SEL类型的数据
2.根据SEL数据找到对应的方法地址
3.根据方法地址调用对应的方法
调用方法的方式
[对象名 performSelector:@selector(方法名)];
[对象名 方法名]; (有的方法名包括冒号)
每个方法中都有一个隐藏的_cmd,代表着当前方法
NSStringFromSelector // 将SEL数据转换为字符串
NSSelectorFromString // 将字符串转换为SEL数据
不能使用[self performSelector:_cmd];会引发死循环
发消息就是发送SEL