一、
NSString
1、简单使用
NSStirng *str = @
“
Hello
”
;
char *name = "itcast";
NSLog(@"我在%@上课", str);
2、 length方法算的是字数,包括空格
NSString *name = @"哈哈jack";
int size = [name length];
int size = [name length];
长度是6
3、创建OC字符串的另一种方式
NSString *newStr = [NSString stringWithFormat:@"My age is %d and no is %d and name is %@", age, no, name];
二、点语法
点语法的本质还是方法调用。
Person *p = [Person new];
p.age = 10; // [p setAge:10];
int a = p.age; // [p age];
三、成员变量作用域
@public : 在任何地方都能直接访问对象的成员变量
@private : 只能在当前类的对象方法中直接访问(@implementation中默认是@private)
@protected : 可以在当前类及其子类的对象方法中直接访问 (@interface中默认就是@protected)
@package : 只要处在同一个框架中,就能直接访问对象的成员变量
@interface和@implementation中不能声明同名的成员变量
@private : 只能在当前类的对象方法中直接访问(@implementation中默认是@private)
@protected : 可以在当前类及其子类的对象方法中直接访问 (@interface中默认就是@protected)
@package : 只要处在同一个框架中,就能直接访问对象的成员变量
@interface和@implementation中不能声明同名的成员变量
四、自动生成getter和setter方法
1、@property:可以自动生成某个成员变量的setter和getter声明及实现
@property int age;
2、@synthesize自动生成age的setter和getter实现,并且会访问_age这个成员变量,如果不存在,就会自动生成_age变量
@synthesize age = _age;
默认会访问age这个成员变量,如果没有age,就会自动生成@private类型的age变量
@synthesize age;
3、在代码中可以直接写@property 系统会自动生成get和set方法的声明及实现,而已可以生成下划线开头的@private类型的成员变量。
五、id
万能指针,能指向\操作任何OC对象
id == NSObject *
id内已内置一个*,不能在后面写个*
id内已内置一个*,不能在后面写个*
id d = [Person new];
六、构造方法
1、构造方法:用来初始化对象的方法,是个对象方法,-开头
重写构造方法的目的:为了让对象创建出来,成员变量就会有一些固定的值
重写构造方法的注意点
1.先调用父类的构造方法([super init])
2.再进行子类内部成员变量的初始化
重写构造方法的目的:为了让对象创建出来,成员变量就会有一些固定的值
重写构造方法的注意点
1.先调用父类的构造方法([super init])
2.再进行子类内部成员变量的初始化
2、 剖析
Person *p = [Person new];
完整地创建一个可用的对象
1.分配存储空间 +alloc
2.初始化 -init
1.调用+alloc分配存储空间
Person *p1 = [Person alloc];
2.调用-init进行初始化
Person *p2 = [p1 init];
Person *p = [[Person alloc] init];
3、重写init方法
//- (id)init
//{
// // 1.一定要调用回super的init方法:初始化父类中声明的一些成员变量和其他属性
// self = [super init]; // 当前对象 self
//
//
// // 2.如果对象初始化成功,才有必要进行接下来的初始化
// if (self != nil)
// { // 初始化成功
// _age = 10;
// }
//
// // 3.返回一个已经初始化完毕的对象
// return self;
//}
//{
// // 1.一定要调用回super的init方法:初始化父类中声明的一些成员变量和其他属性
// self = [super init]; // 当前对象 self
//
//
// // 2.如果对象初始化成功,才有必要进行接下来的初始化
// if (self != nil)
// { // 初始化成功
// _age = 10;
// }
//
// // 3.返回一个已经初始化完毕的对象
// return self;
//}
七、自定义构造方法
自定义构造方法的规范
1.一定是对象方法,一定以 - 开头
2.返回值一般是id类型
3.方法名一般以initWith开头
1.一定是对象方法,一定以 - 开头
2.返回值一般是id类型
3.方法名一般以initWith开头
声明:
父类中
- (id)initWithName:(NSString *)name andAge:(int)age;
子类中
- (id)initWithName:(NSString *)name andAge:(int)age andNo:(int)no;
实现:
父类中
- (id)initWithName:(NSString *)name andAge:(int)age
{
if ( self = [super init] )
{
_name = name;
_age = age;
}
return self;
}
子类中
父类的属性交给父类方法去处理,子类方法处理子类自己的属性
- (id)initWithName:(NSString *)name andAge:(int)age andNo:(int)no
{
// 将name、age传递到父类方法中进行初始化
if ( self = [super initWithName:name andAge:age])
{
_no = no;
}
return self;
}
创建对象
Student *p = [[Student alloc] initWithName:@"Jim" andAge:29 andNo:10];
八、分类
在不改变原来类模型的前提下,给类扩充一些方法,
有
2
种方式
>继承
>分类
分类的作用:在不改变原来类内容的基础上,可以为类增加一些方法
使用注意:
1.分类只能增加方法,不能增加成员变量
2.分类方法实现中可以访问原来类中声明的成员变量
3.分类可以重新实现原来类中的方法,但是会覆盖掉原来的方法,会导致原来的方法没法再使用
4.方法调用的优先级:分类(最后参与编译的分类优先) --> 原来类 --> 父类
使用注意:
1.分类只能增加方法,不能增加成员变量
2.分类方法实现中可以访问原来类中声明的成员变量
3.分类可以重新实现原来类中的方法,但是会覆盖掉原来的方法,会导致原来的方法没法再使用
4.方法调用的优先级:分类(最后参与编译的分类优先) --> 原来类 --> 父类
格式
>分类的声明
@interface 类名 (分类名称)
// 方法声明
@end
>分类的实现
@implementation 类名 (分类名称)
// 方法实现
@interface 类名 (分类名称)
// 方法声明
@end
>分类的实现
@implementation 类名 (分类名称)
// 方法实现
@end
好处
>一个庞大的类可以分模块开发
>一个庞大的类可以由多个人来编写,更有利于团队合作
九、类的本质
1.类也是个对象
>其实类也是一个对象,是Class类型的对象,简称“类对象”
>Class类型的定义
typedef struct objc_class *Class;
>类名就代表着类对象,每个类只有一个类对象
>其实类也是一个对象,是Class类型的对象,简称“类对象”
>Class类型的定义
typedef struct objc_class *Class;
>类名就代表着类对象,每个类只有一个类对象
2.+load和+initialize
1.当程序启动时,就会加载项目中所有的类和分类,而且加载后会调用每个类和分类的+load方法(
不管程序运行过程有没有用到这个类)。只会调用一次。
2.当第一次使用某个类时 (比如创建对象等),就会调用当前类的+initialize方法, 一个类只会调用一次
3.先加载父类,再加载子类(先调用父类的+load方法,再调用子类的+load方法)
+ (void)load
{
NSLog(@"Person---load");
}
+ (void)initialize
{
NSLog(@"Person-initialize");
}
{
NSLog(@"Person---load");
}
+ (void)initialize
{
NSLog(@"Person-initialize");
}
3.获取类对象的2种方式
Class c = [Person class]; // 类方法
或者
Person *p = [Person new];
Class c2 = [p class]; // 对象方法
4.类对象调用类方法
Class c = [Person class];
Person *p2 = [c new];
Class c = [Person class]; // 类方法
或者
Person *p = [Person new];
Class c2 = [p class]; // 对象方法
4.类对象调用类方法
Class c = [Person class];
Person *p2 = [c new];
十、description方法
NSLog(@"%@", p);
默认情况下,利用NSLog和%@输出对象时,结果是:<类名:内存地址>
1.会调用对象p的-description方法
2.拿到-description方法的返回值(NSString *)显示到屏幕上
3.-description方法默认返回的是“类名+内存地址”
1.会调用对象p的-description方法
2.拿到-description方法的返回值(NSString *)显示到屏幕上
3.-description方法默认返回的是“类名+内存地址”
1.-description方法
使用NSLog和%@输出某个对象时,会调用对象的-description方法,并拿到返回值进行输出
2.+ description方法
使用NSLog和%@输出某个类对象时,会调用类对象+description方法,并拿到返回值进行输出
3.修改NSLog的默认输出
>重写-description或者+description方法即可
使用NSLog和%@输出某个对象时,会调用对象的-description方法,并拿到返回值进行输出
2.+ description方法
使用NSLog和%@输出某个类对象时,会调用类对象+description方法,并拿到返回值进行输出
3.修改NSLog的默认输出
>重写-description或者+description方法即可
决定了实例对象的输出结果
- (NSString *)description
{
NSLog(@"%@", self); // 代码会引发死循环
return [NSString stringWithFormat:@"age=%d, name=%@", _age, _name];
return @"3424324";
}
决定了类对象的输出结果
- (NSString *)description
{
NSLog(@"%@", self); // 代码会引发死循环
return [NSString stringWithFormat:@"age=%d, name=%@", _age, _name];
return @"3424324";
}
决定了类对象的输出结果
+ (NSString *)description
{
return @"Abc";
}
{
return @"Abc";
}
4.死循环陷阱
>如果在-description方法中使用NSLog打印self
十一、SEL
1.SEL其实是对方法的一种包装,将方法包装成一个SEL类型的数据,去找对应的方法地址。找到方法地址就可以调用方法
其实消息就是SEL.
>每个类的方法列表都存储在类对象中
>每个方法都有一个与之对应的SEL类型的对象
>根据一个SEL对象就可以找到方法的地址,进而调用方法
>每个方法都有一个与之对应的SEL类型的对象
>根据一个SEL对象就可以找到方法的地址,进而调用方法
2.SEL对象的创建
SEL s = @selector(test);
SEL s2 = NSSelectorFromString(@"test");
3.SEL对象的其他用法
// 将SEL对象转为NSString对象
NSString *str = NSStringFromSelector(@selector(test));
Person *p = [Person new];
// 调用对象p的test方法
[p performSelector:@selector(test)];
SEL s = @selector(test);
SEL s2 = NSSelectorFromString(@"test");
3.SEL对象的其他用法
// 将SEL对象转为NSString对象
NSString *str = NSStringFromSelector(@selector(test));
Person *p = [Person new];
// 调用对象p的test方法
[p performSelector:@selector(test)];
代码示例:
//Person.m实现文件
+ (void)test
{
NSLog(@"test-----");
}
- (void)test2
{
// _cmd代表着当前方法
NSString *str = NSStringFromSelector(_cmd);
// 会引发死循环
// [self performSelector:_cmd];
NSLog(@"调用了test2方法-----%@", str);
}
- (void)test3:(NSString *)abc
{
NSLog(@"test3-----%@", abc);
}
//main函数
Person *p = [[Person alloc] init];
[p test2];
// NSString *name = @"test2";
//
// SEL s = NSSelectorFromString(name);
//
// [p performSelector:s];
// 间接调用test2方法
//[p performSelector:@selector(test2)];
//[p test3:@"123"];
// SEL s = @selector(test3:);
//
// [p performSelector:s withObject:@"456"];
//[p test2];
1.把test2包装成SEL类型的数据
2.根据SEL数据找到对应的方法地址
3.根据方法地址调用对应的方法
十二、NSLog输出增强
__FILE__ :源代码文件名
__LINE__ :NSLog代码在第几行
_cmd :代表着当前方法的SEL
__LINE__ :NSLog代码在第几行
_cmd :代表着当前方法的SEL