黑马程序员————IOS学习笔记 第6篇 OC特殊语法(2)

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ------- 

一、构造方法

    在之前的学习的[Person new]可以创建一个类 并且能够初始化对象,实际在开发中new不常用,通常情况下用构造的方法来对成员变量初始化。

1. 完整的创建一个可用的对象分为两步

第一步:分配存储空间    调用的是+alloc方法

第二步:.初始化   -init

[person new]拆分后是:

Person *p1 = [Person alloc];

Person *p1 = [p1 init];

合成一句后:

Person *p1= [[Person alloc] init];

2.init方法的重写过程:

  有时候new给出的初始值并不是所需的值,因此要用到构造方法,用来初始化对象的方法,因此要重写-(id)init,它是NSObject类中的对象方法

在NSObject类中的init初始化过程:
1.一定要调用super类的init:初始化父类中声明的成员变量和其他属性  self=[super init]  然后返回一个对象给self 当前对象   初始化父类声明中的成员变量
2.'如果初始化成功,才对当前的对象进行自己所规定的变量进行初始化
3.返回一个已经初始化话完毕的对象

在类中重写init也要遵循NSObject中的过程:

- (id)init

{

if (self = [super  init])

    {

_age = 10;

    }

return   self;

}

 注意:

init 初始化的顺序是:NSObject    父类    子类

3.自定义的构造方法

       有时想要随时修改初始值,那么就不能重写构造方法,而是要自定义构造方法,这样可以使外部能够灵活改变初始化的值。原则:对于自己的属性就由自己处理,父类有的

属性就交给父类处理,可以避免父类中的东西修改对子类无影响。

  注意:

 1.一定是对象方法,一定以 - 开头

 2.返回值一般是id类型

 3.方法名一般以initWith开头

- (id)initWithAge:(int)age{

if (self = [super init] {

       _age = age;

    }

return self;

}

person.h

#import <Foundation/Foundation.h>

@interface Person : NSObject
@property NSString *name;
@property int age;
- (id)initWithName:(NSString *)name;
- (id)initWithAge:(int)age;
// initWithName:andAge:
- (id)initWithName:(NSString *)name andAge:(int)age;
@end
person.m

#import "Person.h"

@implementation Person

- (id)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
- (id)initWithNo:(int)no
{
    if ( self = [super init] )
    {
        _no = no;
    }
    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;
}

main.m

#import <Foundation/Foundation.h>
#import "Person.h"
#import "Student.h"

int main(int argc, const char * argv[])
{

    @autoreleasepool {
        Student *p = [[Student alloc] initWithName:@"Jim" andAge:29 andNo:10];
        NSLog(@"00000");
    }
    return 0;
}

注意在以上的实例中:

对于student类中如果也对age name 这两个属性进行直接初始化是不恰当的(如以下代码):

- (id)initWithName:(NSString *)name andAge:(int)age andNo:(int)no
{
     if ( self = [super init] )
     {
        
          self.name = name;
         self.age = age;
        
         //[self setName:name];
         //[self setAge:age];
     }
   
   return self;
}

二、分类

    category 依赖于类 ,可以便于模块开发,增加开发的灵活,如多个人共同开发同一个类。通常情况下想要扩充类的方法,可以重新修改类增加方法,可以用继承,但是除了这

两种方法外,还可以在不改变原来类的基础上扩充方法,就是分类。

1.格式:

分类的声明

@interface类名 (分类名称)

// 方法声明

@end

分类的实现

@implementation类名 (分类名称)

// 方法实现

@end

2.分类的应用:

扩展NSTring类,从下面的例子可以感受到分类的好处 ,一个庞大的类可以分模块开发,可以由多个人来编写,更有利于团队合作。

 给NSString增加一个类方法:计算某个字符串中阿拉伯数字的个数
 给NSString增加一个对象方法:计算当前字符串中阿拉伯数字的个数

NSTring+Number.h

#import <Foundation/Foundation.h>

@interface NSString (Number)

+ (int)numberCountOfString:(NSString *)str;

- (int)numberCount;

@end
NSTring+Number.m

#import "NSString+Number.h"

@implementation NSString (Number)

//  @"abc434ab43"
+ (int)numberCountOfString:(NSString *)str
{
    // 1.定义变量计算数字的个数
//    int count = 0;
//    
//    for (int i = 0; i<str.length; i++)
//    {
//        unichar c = [str characterAtIndex:i];
//        
//        if ( c>='0' && c<='9')
//        {
//            count++;
//        }
//    }
//    return count;
    
    return [str numberCount];
}

- (int)numberCount
{
    int count = 0;
    
    for (int i = 0; i<self.length; i++)
    {
        // 取出i这个位置对应的字符
        unichar c = [self characterAtIndex:i];
        
        // 如果这个字符是阿拉伯数字
        if ( c>='0' && c<='9' )
        {
            count++;
        }
    }
    
    return count;
}

@end

3.注意:

分类单独放在一个文件里跟之前创建一个新类一样,分类的声明放在.h,分类的实现放在.m文件

分类可以访问原始类的实例变量,但不能添加变量,只能添加方法。如果想添加变量,可以考虑通过继承创建子类

可以实现原始类的方法,但不推荐这么做,因为它是直接替换掉原来的方法,这么做的后果是再也不能访问原来的方法

多个Category中如果实现了相同的方法,只有最后一个参与编译的才会有效

分类的优先级高于原来的类,在调用方法时,优先到分类中去查找,然后再去原来的类中找,之后再去父类中找。

若方法重写方法调用的优先级:分类(最后参与编译的分类优先)—>子类—>父类


三、类的本质

1.本质

   类其实类也是一个对象,是Class类型的对象,简称“类对象”

    Class类型的定义:typedef  structobjc_class *Class;

     类名就代表着类对象,每个类只有一个类对象

2 .+load

   在程序启动的时候会加载所有的类和分类,并调用所有类和分类的+load方法

   先加载父类,再加载子类;也就是先调用父类的+load,再调用子类的+load

   先加载元原始类,再加载分类

    不管程序运行过程有没有用到这个类,都会调用+load加载

 3.  +initialize

在第一次使用某个类时(比如创建对象等),就会调用一次+initialize方法

一个类只会调用一次+initialize方法,先调用父类的,再调用子类的

4.获取类对象的2种方式

Class c = [Personclass];// 类方法

或者

Person*p = [Personnew];

Class c2 = [p class];// 对象方法

5.类对象调用类方法

Class c = [Person  class];

Person *p2 = [c new];

四、description方法

     使用NSLog和%@输出某个对象时,会调用对象的-description方法,并拿到返回值进行输出。NSLog(@"%@",p)默认情况下输出对象时结果是 :类名:内存地址,如果想把一个对象属性输出,就要重写description 。修改NSLog的默认输出,重写-description或者+description方法即可。

1.+description重写:

+ (NSString *)description
{
    return @"Abc";
}

那么在test2函数执行后就会输出Abc

void test2()
{
    Class c = [Person class];
    
    // 1.会调用类的+description方法
    // 2.拿到+description方法的返回值(NSString *)显示到屏幕上
    NSLog(@"%@", c);
}

2.NSLogs输出补充:

// 输出当前函数名
    NSLog(@"%s\n", __func__);

// 输出行号
    NSLog(@"%d", __LINE__);
    
 // NSLog输出C语言字符串的时候,不能有中文

    NSLog(@"%s", __FILE__);若文件名是中文就无法输出要使用    printf("%s\n", __FILE__);

// 指针变量的地址
    NSLog(@"%p", &p);

// 对象的地址
    NSLog(@"%p", p);

 // <类名:对象地址>
    NSLog(@"%@", p);


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值