黑马程序员——03OCNSString类和核心语法学习

                                              -----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、点语法与settergetter有关

#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

帮助类自动生成settergetter,也属于编译器特性

1、@property@synthesize定义

a、@property 数据类型 成员变量名(去下划线_ ):可以自动生成某个成员变量的settergetter声明;@property用在@interface @end之间

例如:@property int age

b、@synthesize成员变量名(去下划线_ ) = 成员变量名:可以自动生成某个成员变量的settergetter实现,并且访问_age这个成员变量;

     @synthesize用@implementation@end之间

     @synthesize在.m文件中会访问_speed这个成员,如果不存在,就会自动生成@private的_speed成员变量

例如:@synthesize age = _age

2、定义成员变量的最简写法

@interface Car : NSObject

// 生成@private的数据类型为double的成员变量_height,并生成_heightsettergetter的声明和实现

@property double height; // Xcode 4.4版本以后

@end

3、若手动实现了setter,编译器只会自动生成getter和自动生成不存在的成员变量(@private);

      若手动实现了getter,编译器只会自动生成setter和自动生成不存在的成员变量(@private);

      若手动实现了settergetter,编译器就不会自动生成不存在的成员变量;

五、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、一定要调用回superinit方法:目的是初始化父类中声明的一些成员变量和其他属性

    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参数);





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值