-----Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
一、NSString
1、NSString是字符串处理类,OC的字符串也是一个对象
2、输出方式:%@ ;
3、最简单的字符串创建方式
NSString *str = @"学生"
NSLog(@"我是一个%@", str);
4、创建OC字符串的另一种形式
int age = 10;
NSString *name = @”张三”;
NSString *newstr = [NSString stringWithFormat:@"姓名%@,年龄%d岁", name, age];
NSLog(@”%@”, newstr);
5、计算字符串长度
int size = [newstr length]; //算的是字数,并不是字符数。
例如:"哈哈jack"输出结果为6
6、 BOOL类型使用注意:返回值是BOOL类型的,方法名一般都是以is开头。
例:- (BOOL) isPoor;
二、点语法
属于编译器特性
1、点语法与setter和getter有关
#import <Foundation/Foundation.h>
@interface Person : NSObject
{
int _age;
NSString *_name;
}
- (void)setAge:(int)age;
- (int)age;
- (void)setName:(NSString *)name;
- (NSString *)name;
@end
@implementation Person
- (void)setAge:(int)age
{
_age = age;
NSLog(@"setAge");
// 会引发死循环
// self.age = age; // 相当于[self setAge:age];
}
- (int)age
{
NSLog(@"age");
// 访问的两种方法
return _age;
// return self->_age;
// 会引发死循环
// return self.age; // 相当于[self age];
}
- (void)setName:(NSString *)name
{
_name = name;
}
-(NSString *)name
{
return @"Rose";
}
@end
int main(int argc, const char * argv[])
{
Person *p = [Person new];
[p setAge:10];
int a = [p age];
NSLog(@"%d",a);
p.age = 15;
int b = p.age;
NSLog(@"%d",b);
p.name = @"jack";
NSString *s = p.name;
NSLog(@"%@",s);
return 0;
}
三、成员变量的作用域
有4种类型:
1、@public:任何地方都能直接访问对象的成员变量
2、@private:只能在当前类的对象方法中直接访问 (@implementation中默认就是@private)
3、@protected:可以在当前类和子类的对象方法中直接访问 (@interface中默认就是@protected)
4、@package:只要处于同一个框架中,就能直接访问对象的成员变量,介于@private和@public之间的。
子类中想要访问父类中得@private成员变量只能用setter和getter
四、@property和@synthesize
帮助类自动生成setter和getter,也属于编译器特性
1、@property和@synthesize定义
a、@property 数据类型 成员变量名(去下划线_ ):可以自动生成某个成员变量的setter和getter声明;@property用在@interface @end之间
例如:@property int age
b、@synthesize成员变量名(去下划线_ ) = 成员变量名:可以自动生成某个成员变量的setter和getter实现,并且访问_age这个成员变量;
@synthesize用在@implementation@end之间
@synthesize在.m文件中会访问_speed这个成员,如果不存在,就会自动生成@private的_speed成员变量
例如:@synthesize age = _age
2、定义成员变量的最简写法
@interface Car : NSObject
// 生成@private的数据类型为double的成员变量_height,并生成_height的setter和getter的声明和实现
@property double height; // Xcode 4.4版本以后
@end
3、若手动实现了setter,编译器只会自动生成getter和自动生成不存在的成员变量(@private);
若手动实现了getter,编译器只会自动生成setter和自动生成不存在的成员变量(@private);
若手动实现了setter和getter,编译器就不会自动生成不存在的成员变量;
五、id
1、id(内部已包含*)是万能指针,能指向/操作任何OC对象(只适用于OC对象);
2、id 可以认为 id == NSObject *;例如:(以下三行代码一样)
Person *p = [Person new];
NSObject *p = [Person new];
id p = [Person new];
六、构造方法
1、完整地创建一个可用的对象:
a、分配存储空间(+alloc)
b、初始化 (-init)
以后创造对象不要用new,应使用Person *p =[[Person alloc] init];
2、构造方法:用来初始化对象的方法,是个对象方法,减号 - 开头;
3、重写构造方法的目的:为了让对象创建出来,成员变量就会有一些固定的值。
4、想改成员变量的初始化值,重写 -init方法
- (id)init
{
// 1、一定要调用回super的init方法:目的是初始化父类中声明的一些成员变量和其他属性
self = [super init]; // 当前对象 self
// 2、如果对象初始化成功,才有必要进行接下来的初始化
if (self != nil) {
// 初始化成功
_age = 10;
}
// 3、返回一个已经初始化完毕的对象
return self;
}
最终写法
- (id)init
{
if( self = [super init])
{
_age = 10;
}
return self;
}
5、重写构造方法的注意点
a、先调用父类的构造方法([super init])
b、再进行子类内部成员变量的初始化
6、自定义构造方法规范
a、一定是对象方法,一定以 - 开头
b、返回值一般是id类型
c、方法名一般以init开头,例如- (id) initWithAge: (int)age;
#import <Foundation/Foundation.h>
@interface Person : NSObject
@property NSString *name;
@property int age;
- (id) initWithName:(NSString *)name;
- (id)initWithAge:(int)age;
- (id) initWithName:(NSString *)name andAge:(int)age;
@end
@implementation Person
- (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]) {
_age = age;
_name = name;
}
return self;
}
- (id)init
{
if (self = [super init]) {
_name = @"jack";
}
return self;
}
@end
@interface Student : Person
@property int no;
- (id)initWithNo:(int)no;
- (id) initWithName:(NSString *)name andAge:(int)age andNo:(int)no;
@end
@implementation Student
- (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.age = age;
// 第二种写法
// [self setName:name];
// [self setAge: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;
}
@end
int main(int argc, const char * argv[])
{
@autoreleasepool {
Person *p = [[Person alloc] init];
NSLog(@"%@",p.name);
Person *p1 = [[Person alloc] initWithName:@"Rose"];
NSLog(@"%@",p1.name);
Person *p2 = [[Person alloc] initWithAge:20];
NSLog(@"%d",p2.age);
Person *p3 = [[Person alloc] initWithName:@"jim" andAge:19];
NSLog(@"name = %@, age = %d",p3.name,p3.age);
Student *stu = [[Student alloc] initWithNo:2];
NSLog(@"no = %d",stu.no);
Student *stus = [[Student alloc] initWithName:@"张三" andAge:16 andNo:5];
NSLog(@"name = %@, age = %d, no = %d",stus.name,stus.age,stus.no);
}
return 0;
}
七、category分类
1、分类的作用:在不改变原来类模型(内容)的基础上,可以为类增加一些方法。
2、格式
a、分类的声明
@interface 类名 (分类名称)
// 方法声明
@end
b、分类的实现
@implementation
// 方法实现
@end
3、使用注意:
a、分类只能增加方法,不能增加成员变量
b、分类方法实现中可以访问原来类中的成员变量
c、分类可以重新实现原来类中的方法,但是会覆盖掉原来类的方法,会导致原来类的方法没法再使用
d、方法调用的优先级:分类(最后参与编译的分类优先) -->原来类 -->父类
/*
➢给NSString增加一个类方法:计算某个字符串中阿拉伯数字的个数
➢给NSString增加一个对象方法:计算当前字符串中阿拉伯数字的个数
*/
#import <Foundation/Foundation.h>
@interface NSString (Number)
- (int)numberCount;
+ (int)numberCountOfString:(NSString *)str;
@end
@implementation NSString (Number)
//+ (int)numberCountOfString:(NSString *)str
//{
// // 1、定义变量计算数字的个数
// int count = 0;
// for (int i = 0; i < str.length; i++) {
// // 2、取出i这个位置对应的字符
// unichar c = [str characterAtIndex:i];
//
// // 3、如果这个字符是阿拉伯数字,count自增1
// if ( c >= '0' && c <= '9' ) {
// count++;
// }
// }
// return count;
//}
+ (int)numberCountOfString:(NSString *)str
{
return [str numberCount];
}
- (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
int main(int argc, const char * argv[])
{
@autoreleasepool {
int count = [NSString numberCountOfString:@"sfa7sf6a78gsdfa7"];
NSLog(@"%d",count);
int counts = [@"hjsdhj4389jsdjk94" numberCount];
NSLog(@"%d",counts);
}
return 0;
}
八、类的深入研究
1、类的本质:类也是一个对象,是Class类型的对象,简称类对象
// 利用Person这个类创建了Person类型的对象
Person *p = [[Person alloc] init];
Person *p1 = [[Person alloc] init];
// 获取内存中的类对象
Class c = [p class]; // 对象的class方法
Class c1 = [p1 class]; // 对象的class方法
Class c2 = [Person class]; // 类的class方法
NSLog(@"c = %p, c2 = %p, c2 = %p",c,c1,c2); //输出结果都是一样的
本质是:1>利用Class 创建Person类对象
2>利用Person类对象 创建Person类型的对象
3>类名就代表类对象:类对象== 类
4>打印OC对象用:%@
2、+load方法和+initialize方法
a、当程序启动时,就会加载项目中所有的类和分类,而且加载完毕后就会调用每个类和分类的+load方法。只会调用一次;
b、当第一次使用某个类的时候,就会调用当前类和父类的+initialize方法,如果类有分类,按优先级加载+initialize方法;
c、先加载父类、再加载子类(先调用父类的+load方法,再调用子类的+load方法),先初始化父类、再初始化子类(先调用父类的+initialize方法,再调用子类的+initialize方法);
可以用+initialize监听类的初始化过程
九、description
1、-description方法
使用NSLog和%@输出某个对象时,会调用对象的-description方法,并拿到返回值进行输出,默认输出<类名:内存地址>
2、+ description方法
使用NSLog和%@输出某个类对象时,会调用类对象+description方法,并拿到返回值进行输出,默认输出类名
3、修改NSLog的默认输出:重写-description或者+description方法即可
@implementation Person
// 决定了实例对象的输出结果
- (NSString *)description
{
// 下面代码会引发死循环
// NSLog(@"%@",self);
return [NSString stringWithFormat:@"name = %@, age = %d",_name,_age];
}
// 决定了类对象的输出结果
+ (NSString *)description
{
return @"sdf";
}
@end
4、NSLog输出补充
//输出代码行号
NSLog(@"%d",__LINE__);
// NSLog输出C语言字符串的时候,不能有中文
// 输出源文件的名称
NSLog(@"%s",__FILE__);
printf("%s\n",__FILE__);
// 输出当前函数名
NSLog(@"%s",__func__);
十、SEL
SEL是一种类型,这种类型的数据就代表方法;
1、SEL其实是对方法的一种包装,将方法包装成一个SEL类型的数据,去找对应的方法地址,找到方法地址就可以调用方法;
a、每个类的方法列表都存储在类对象中;
b、每个方法都有一个与之对应的SEL类型的对象;
c、根据一个SEL对象就可以找到方法的地址,进而调用方法;
@interface Person :NSObject
+ (void)test;
- (void)test2;
- (void)test3:(NSString *)abc;
@end
@implementation Person
+ (void)test
{
NSLog(@"+test");
}
- (void)test2
{
// _cmd代表着当前方法;每个方法内部都有一个内置的_cmd
NSString *str =NSStringFromSelector(_cmd);
// 会引发死循环
// [self performSelector:_cmd];
NSLog(@"-test2 -- %@",str);
}
- (void)test3:(NSString *)abc
{
NSLog(@"test -- %@",abc);
}
@end
int main(int argc, constchar * argv[])
{
@autoreleasepool {
Person *p = [[Personalloc]init];
// 间接调用test2方法
[pperformSelector:@selector(test2)];
[ptest3:@"ddff"];
[pperformSelector:@selector(test3:)withObject:@"vxwe"];// 注意方法名为test3:
SEL s =@selector(test3:);
[pperformSelector:swithObject:@"sdf"];
[ptest2];
// 1、首先会把test2包装成SEL类型的数据
// 2、根据SEL数据找到对应的方法地址
// 3、根据方法地址调用对应的方法
NSString *name =@"test2";
SEL sl =NSSelectorFromString(name);
[pperformSelector:sl];
[ptest2];
}
return0;
}
2、获取到方法的ID也就是我们所说的SEL,反之亦然。具体的使用方法如下:
1> SEL 变量名 = @selector(方法名字);
2> SEL 变量名 = NSSelectorFromString(方法名字的字符串);
3> NSString *变量名 = NSStringFromSelector(SEL参数);