oc学习笔记(七)面向对象-核心语法

来源:互联网 发布:com域名免备案 编辑:程序博客网 时间:2024/05/14 06:41

一、点语法

1.可以让其它程序员很容易上手能看懂oc语言

点语法的本质还是方法调用(本质是get或者set方法)

//编译器会自动把点语法,转换成相应的方法

Person *p  = [Person new]; //转成set方法 [p setAge:10];

int a= p.age;                         //转成get方法 [p age];

2.在set和get方法种如下使用可引发死循环

- (void)setAge:(int)age

{

//_age = age;

NSLog(@"age");

//会引发死循环

self.age = age ; // 相当于[self setAge:age];

}

- (int)age

{

NSLog(@"age");

//return _age;

//会引发死循环

          return self.age; // 相当于[self age];

}

二、成员变量的作用域

/* @public : 在任何地方都能直接访问对象的成员变量 @private : 只能在当前类的对象方法中直接访问(@implementation中默认是@private) @protected : 可以在当前类及其子类的对象方法中直接访问  (@interface中默认就是@protected) @package : 只要处在同一个框架中,就能直接访问对象的成员变量  @interface和@implementation中不能声明同名的成员变量 */#import <Foundation/Foundation.h>@interface Person : NSObject{    int _no;        @public // 在任何地方都能直接访问对象的成员变量    int _age;            @private  // 只能在当前类的对象方法中直接访问    int _height;        @protected // 能在当前类和子类的对象方法中直接访问    int _weight;    int _money;}- (void)setHeight:(int)height;- (int)height;- (void)test;@end

三、oc中是单继承

四、@property:自动生成某个成员变量的get和set方法的声明

原理:编译器特性,在编译的时候会自动转换成getter和setter

注意:可连写

@property int age, height;

#import <Foundation/Foundation.h>@interface Person : NSObject{    int _age;    // int age;        int _height;        double _weight;        NSString *_name;}// @property:可以自动生成某个成员变量的setter和getter声明@property int age;//- (void)setAge:(int)age;//- (int)age;@property int height;//- (void)setHeight:(int)height;//- (int)height;- (void)test;@property double weight;@property NSString *name;@end

2.@synthesize 自动生成setter 和getter的实现。

注意1>:还可以连写,看下面代码示例

@synthesize weight = _weight, name = _name;
注意2>:

@synthesize age;
默认是访问 age ,相当于 @synthesize age=age

应该写

@synthesize age = _age;

#import "Person.h"@implementation Person// @synthesize自动生成age的setter和getter实现,并且会访问_age这个成员变量@synthesize age = _age;// -(void)setAge:(int)age//{//  _age = age;//}// - (int)age//{//    return _age;//}@synthesize height = _height;@synthesize weight = _weight, name = _name;//还可以连写@end

3.@synthesize 在生成getter和setter的实现时,如果成员变量不存在,就会自动生成

//@synthesize speed = _speed, wheels = _wheels;

// 会访问_speed这个成员变量,如果不存在,就会自动生成@private类型的_speed变量


4.在xcode4.4之后,如果不存在成员变量和方法的 实现

只需要写@property int age 这样的声明

就会自动生成@private类型的成员变量,和生成实现的方法

所以,@property独揽了声明和实现的功能,(如果没有写就会自动生成,如果已经存在就不会再生成了。)

五、id 关键字

 // id  == NSObject *

 // 万能指针,能指向\操作任何OC对象

    id d = [Person new];


六、构造方法

// 构造方法:用来初始化对象的方法,是个对象方法,-开头

// 重写构造方法的目的:为了让对象创建出来,成员变量就会有一些固定的值

/*

 重写构造方法的注意点

1.先调用父类的构造方法([super init]

2.再进行子类内部成员变量的初始化

 */


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

     1.分配存储空间  +alloc

     2.初始化 -init

    // Person *p = [Person new];   

    // 1.调用+alloc分配存储空间

    // Person *p1 = [Person alloc];

    // 2.调用-init进行初始化

    // Person *p2 = [p1 init];


2.等于如下方式,以后要按如下来书写

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


3.重写构造方法步骤如下:

在.m文件中

////  Person.m//  02-构造方法////  Created by apple on 13-8-8.//  Copyright (c) 2013年 itcast. All rights reserved.//#import "Person.h"@implementation Person// 重写-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;    }        // 3.返回一个已经初始化完毕的对象    return self;}@end

4.自定义构造方法

/*

 自定义构造方法的规范

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

 2.返回值一般是id类型

 3.方法名一般以initWith开头

*/

- (id)initWithName:(NSString *)name;


使用的时候,可以在定义变量的时候直接调用

 Student *p = [[Student alloc] initWithName:@"Jim" andAge:29 andNo:10];

七、分类- Category

1.       基本用途

Ø   如何在不改变原来类模型的前提下,给类扩充一些方法?有2种方式

l   继承

l   分类(Category)

 

2.       格式

Ø   分类的声明

@interface 类名 (分类名称)

// 方法声明

@end

Ø   分类的实现

@implementation 类名 (分类名称)

// 方法实现

@end

 

3.       好处

Ø   一个庞大的类可以分模块开发 (使用模块名命名)

Ø   一个庞大的类可以由多个人来编写,更有利于团队合作



1.分类的作用:在不改变原来类内容的基础上,可以为类增加一些方法

 

 使用注意:

 1.分类只能增加方法,不能增加成员变量

 2.分类方法实现中可以访问原来类中声明的成员变量

 3.分类可以重新实现原来类中的方法,但是会覆盖掉原来的方法,会导致原来的方法没法再使用(不建议这样用)

 4.方法调用的优先级:分类(最后参与编译的分类优先) -->原来类  -->父类

2.开发过程中经常是给系统自带的类,扩充分类

举例:

////  NSString+Number.m//  05-分类的应用////  Created by apple on 13-8-8.//  Copyright (c) 2013年 itcast. All rights reserved.//#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

八、类的本质

1.类本身也是一个对象,是个Class类型的对象,简称类对象

Person *p = [[Person alloc] init]对象创建过程:

>1,利用Class 创建 Person类对象

>2,利用 Person类对象 创建 Person类型的对象


2.获取内存中的的类对象2种方法

>1.调用某个对象的某个对象方法(这里是class方法) 

如下图中p对象中是有class方法的


Class c = [p class];  //c为类对象

》2.第二种方式:

通过这个类的类方法

Class c3 = [Person class]


3.类可以做一个事情:

类可以调用类方法。

Class c = [Person class];

Person *p2 = [c new];


4.类的本质之类的加载

 1.当程序启动时,就会加载项目中所有的类和分类,而且加载后会调用每个类和分类的+load方法。只会调用一次。

 

 2.当第一次使用某个类时,就会调用当前类的+initialize方法

 

 3.先加载父类,再加载子类(先调用父类的+load方法,再调用子类的+load方法)

   先初始化父类,再初始化子类(先调用父类的+initialize方法,再调用子类的+initialize方法)//如果类中有分类,分类优先级高会覆盖原类。


代码示例如下

// 当程序启动的时候,就会加载一次项目中所有的类。类加载完毕后就会调用+load方法

+ (void)load

{

    NSLog(@"Person---load");

}


// 当第一次使用这个类的时候,就会调用一次+initialize方法

+ (void)initialize

{

    NSLog(@"Person-initialize");

}


九、description方法

1. 对象占位符都是%@

2. +description方法

  Class c = [Person class];

    

    // 1.会调用类的+description方法

    // 2.拿到+description方法的返回值(NSString *)显示到屏幕上

         / /    3.默认输出结果是:类名

    NSLog(@"%@", c);

--------------------

3.-description方法

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

    p.age = 20;

    p.name = @"Jack";

    //默认情况下,利用NSLog%@输出对象时,结果是:<类名:内存地址>

    

    // 1.会调用对象p-description方法

    // 2.拿到-description方法的返回值(NSString *)显示到屏幕上

    // 3.-description方法默认返回的是类名+内存地址

    NSLog(@"%@", p);


十、NSLog 增强,输出补充。


void test9()

{

    // 输出当前函数名

    NSLog(@"%s\n", __func__);

}


int main()

{

    // 输出行号

    NSLog(@"%d", __LINE__);

    

    // NSLog输出C语言字符串的时候,不能有中文

    // NSLog(@"%s", __FILE__);

    

    //输出源文件的名称

    printf("%s\n", __FILE__);

    

    test9();

return 0;


十一、SEL 类型

在对象调用方法的时候,把方法包装成SEL类型,去类中查找。

第二次查找时会直接使用之前查找的结果缓存;

经典错误中找不到方法的selector就是这种消息,sel是简称。

内存表示如下:


代码如下:

下方[p performSelector:@selector(test3:) withObject:@"456"]这句中test3方法一定要加冒号(方法名都要加上:)

否刚会报经典错误,如下:




1.       方法的存储位置

Ø   每个类的方法列表都存储在类对象中

Ø   每个方法都有一个与之对应的SEL类型的对象

Ø   根据一个SEL对象就可以找到方法的地址,进而调用方法

Ø   SEL类型的定义

typedef struct objc_selector    *SEL;

 

2.       SEL对象的创建

SEL s = @selector(test);

SEL s2 = NSSelectorFromString(@"test");

 

3.       SEL对象的其他用法

// SEL对象转为NSString对象

NSString*str = NSStringFromSelector(@selector(test));

 

Person *p= [Person new];

//调用对象ptest方法

 [p performSelector:@selector(test)];

4.  每个方法里面都有 SEL类型的 _cmd 代表者当前方法

NSString*str = [p performSelector:@selector(_cmd)];

取出方法名


0 0