一、NSString
NSString存在于Foundation框架中,用于定义字符串变量。
int main()
{
//定义字符串
NSString *str = @”itcast”;
//打印字符串使用%@占位符
NSLog(@”%@”, str);
return 0;
}
stringWithFormat方法介绍:
int age = 15;
int no = 5;
NSString *str = [NSString stringWithFormat:@”age is %d, no is %d”, age, no];
length方法介绍:
NSString *str = @”jack”;
int size = [str length]; //返回str字符串的长度,返回类型为unsigned long类型
NSLog(@”size is %d, str length is %ld”, size, [str length]);
NSString API文档:
XCode->Help->Documentation and API Reference->搜索“NSString”
二、点语法
利用点语法替换set方法和get方法
Student *stu = [Student new];
//[stu setAge:100];
stu.age = 100; // 同上
//int age = [stu age];
int age = stu.age; // 同上
点语法的本质还是方法调用;
当使用点语法的时候,编译器会自动将点语法展开成相应的方法。
三、成员变量的作用域
@private: 只能在当前类的对象方法里访问(@implementation中默认是@private)
@protected: 可以在当前类以及子类的对象方法中直接访问(@interface中默认是@protected)
@public: 任何地方都能直接访问对象的成员变量
@package: 同一个体系内(框架内)可以访问,介于@private和@public之间(很少用)
一、@property和@synthesize
情况一:
@interface Person : NSObject
{
int _age;
}
@property int age; //生成_age的set和get方法的声明
@end
@implementation Person
@synthesize age = _age; //实现名为age的property,并且访问名为_age的成员变量。如果写成“@synthesize age;”,则访问名为“age”的成员变量
@end
情况二:
@interface Person : NSObject
@property int age; //生成_age的set和get方法的声明
@end
@implementation Person
@synthesize age = _age; //实现名为age的property,并且访问名为_age的成员变量,如果没有_age,则在@implementation中自动生成一个@private的成员变量
@end
情况三:
@interface Person : NSObject
@property int age; //生成_age的set和get方法的声明;生成@implementation中的property实现;生成@private的_age成员变量
@end
情况三是最简洁的写法,但是缺点是生成的成员变量为@private的,所以继承的子类不拥有此成员变量,如果子类希望拥有,则如下写法:
情况四:
@interface Person : NSObject
{
int _age; //默认为@protected
}
@property int age;
@end
如果代码如下时:
@interface Person : NSObject
@property int age;
@end
@implementation Person
- (void)setAge:(int)age
{
}
- (int)age
{
}
@end
不自动生成_age成员变量,因为set和get实现已经存在,所以编译器认为不需要访问_age属性,所以不自动生成,此时的类中不存在_age这个成员变量。
五、id
id是OC语言中的关键字,是一种类型,所以当自定义名称的时候,不可以取名为“id”。
id是万能指针,可以指向\操作任何OC对象。id中已经包含*
id相当于NSObject *
使用情况一:
指向对象,操作对象(包括字符串)
id d = [Person new];
d.age = 10;
int a = d.age;
使用情况二:
作为形参(或成员变量),意为可以传入任何对象(继承于NSObject),包括字符串,因为字符串是NSString类型的对象
void test(id d)
{
}
六、构造方法(init)
用来初始化对象的方法,是个对象方法,“-”开头
Person *p = [Person new];
完整的创建一个可用的对象
1>分配存储空间 +alloc
2>初始化 -init
new方法内部会调用两个方法 +alloc、-init
//new拆开:
//调用+alloc分配存储空间
Person *p = [Person alloc];
//调用-init进行初始化
Person *p1 = [p init];
//相当于:
Person *p = [[Person alloc] init];
//在@implementation中重写init方法
@implementation
- (id)init
{
//重写构造方法的条件
//1.一定要调用super的init方法,意为初始化父类中的所有可继承的属性
if( self = [super init] ) //把父类的可继承属性赋值给self当前对象
{
//2.如果不为空(取决于OC运行时特性),开始初始化子类特有成员变量(此成员变量是包含在self中的)
_age = 10;
}
//返回self
return self;
}
@end
自定义构造方法:
1.一定是对象方法,一定以“-”开头
2.返回值一般是id类型
3.方法名一般以init开头
@interface Person : NSObject
@property NSString *name;
- (id)initWithName:(NSString *)name;
- (id)initWithName:(NSString *)name andAge:(int)age;
@end
@implementation Person
- (id)initWithName:(NSString *)name
{
if(self = [super init])
{
_name = name;
}
return self;
}
- (id)initWithName:(NSString *)name andAge:(int)age
{
if(self = [super init])
{
_name = name;
_age = age;
}
return self;
}
@end
自定义构造方法规范:
各自的成员变量在各自的类实现中赋值
- (id)iniWithName:(NSString *)name andAge:(int)age andNo:(int)no
{
//将name、age传递到父类方法中进行初始化
if(self = [super initWithName:name andAge:age])
{
_no = no;
}
return self;
}
七、分类(Category)
分类的好处,可以模块化开发,一个模块的功能放到一个分类中。在不改变原来类内容基础上,为类增加一些方法。
//分类名称:Person+MJ.h、Person+MJ.m
#import “Person.h” // 导入Person类
@interface Person (MJ)
- (void) test;
@end
@implementation Person (MJ) // 一般MJ的位置写模块名
- (void)study
{
}
@end
使用注意:
1.只能增加方法,不能增加成员变量
2.分类方法实现中可以访问原来类中声明的成员变量
3.分类可以重新实现原来类中的方法,但是会覆盖原来的方法
4.方法调用的优先级:分类(最后参与编译的分类中的方法优先)-->原来类-->父类
八、类
类本身也是一个对象,是个Class类型的对象,简称类对象
所有类都是由Class创建的类对象,再由类对象创建类的对象
获取类对象:
1.Class c = [p class]; //p为对象
2.Class c = [Person class]; //Person为具体类
类对象的使用:
1.类对象 == 类
2.类对象和类一样,可以调用类方法
3.内存中一个类只有一个类对象
类的加载和初始化
1.OC程序启动时,会加载所有类和分类,即调用所有类和分类的+(void)load方法,并且只调用一次(先加载父类,再加载子类)
2.当使用某个类时候,会先初始化其父类,然后初始化其自身,即先调用父类的+(void)initialize方法,然后调用自身的+(void)initialize方法
3.当使用某个类的时候,若其有分类,则调用分类中的+(void)initialize方法,而不调用自身的+(void)initialize方法。分类方法调用优先级最高
九、description方法
默认情况下,利用NSLog和%@输出对象时,结果是:<类名:内存地址>
1.会调用对象的-description方法
2.拿到-description方法的返回值(NSString *)显示到屏幕上
- (NSString *)description
{
return [NSString stringWithFormat:@”age is %d, name is %@”, _age, _name];
}
十、SEL(运行时机制)
当内存中加载一个类后,类中会存在方法列表,罗列所有的对象方法和类方法。每一个方法的地址都对应着各自的SEL消息值。当调用方法时候,会首先将方法名封装成SEL数据,然后通过performSelector方法发送SEL数据,根据SEL值在类的方法列表中找到相应的方法,并执行。
1.把方法名包装成SEL类型的数据
2.根据SEL数据找到对应的方法地址
3.根据方法地址调用对应的方法
无参方法调用:
[p performSelector:@selector(test)];
有参方法调用:
[p performSelector:@selector(test) withObject:@”123”];
用字符串方式调用方法:
NSString *name = @”test”;
SEL s = NSSelectorFromString(name);
[p performSelector:s];
每个方法中都内置一个SEL对象“_cmd”,_cmd代表当前方法,打印_cmd如下:
-(void)test
{
// _cmd == @selector(test);
NSString *str = NSStringFromSelector(_cmd);
NSLog(@”%@”, str); // 打印为“test”,说明_cmd指向当前方法
[self performSelector:_cmd]; //会引发死循环
}
消息就是SEL。