码迷,mamicode.com
首页 > 其他好文 > 详细

Objective-C:06_面向对象-核心语法

时间:2014-09-24 17:47:57      阅读:286      评论:0      收藏:0      [点我收藏+]

标签:des   style   color   io   使用   ar   strong   for   文件   

点语法:
 
  点语法的本质还是方法调用
   当使用点语法时,编译器会自动展开成相应的方法
 
     Person *p = [Person new];
     p.age=10;  //编译器编译的时候会自动将这一行代码转换成 [p setAge:10];
     
     int a=p.age;  //编译器编译的时候会自动将这一行代码转换成 int a  = [p age];
    
    使用点语法的时候要注意不要形成死循环:
        
          - (void)setAge:(int)age

    //下面的代码将引发死循环,相当于[self setAge:age] 
    self.age = age; 

- (int)age 

    //下面的代码将引发死循环,相当于[self age] 
    return self.age; 
}
 
成员变量的4种作用域:
     @private:只能在当前类的对象方法中直接访问(@implementation中不写默认是@private)
@protected:可以再当前类及其子类的对象方法中直接访问(@interface中不写默认是@protected)
@public:任何地方都可以访问对象的成员变量
@package:只要处在同一个框架中,就能直接访问对象的成员变量,介于@private和@public之间
        
    什么都不写的时候默认的访问级别是protected
     
    成员变量也可以写在实现部分,也就是.m文件中,访问级别默认是@private
        在 .m文件中声明的成员变量不能和 .h文件中声明的成员变量重名(也就是@implementation和@interface文件)
    
    OC中只能单继承
        父类\超类 superclass
        子类 subclass\subclasses
        
 
@property和@synthesize
        这两个关键字是编译器特性
    @property:可以自动生成某个成员变量的set和get方法声明    
 
    成员变量:
        int  _age;
        int  _height;
        NSString *_name;
 
    get和set方法的声明:
        @property  int  age;就相当于下面的两句声明代码
         - (void)setAge:(int)age;
         - (int)age;
        @property NSString *name;
 
        当多个成员变量的类型一致的时候,可以使用@property 类型  成员1,成员2,成员3;
    get和set方法的实现:
        @synthesize age=_age; //相当于下面两个方法(@synthesize自动生成age的set和get方法,并且访问_age这个成员变量)
            如果是@synthesize age;//这样的写法的话默认访问的就不是成员变量_age了,而是成员变量age
 
        -  (void)setAge:(int)age
        {
            _age=age;
        }
        - (int)age
        {
            return _age;
        }
 
    不写成员变量,但是写@property的话,那么在@implementation中使用@synthesize的话,访问成员变量,如果不存在的话,就会自动生成@private的成员变量,数据类型根据@property中的数据类型。(这个变量是生成在@implementation中的)
 
    最简单的写法:
        直接写一个@property int age;
                这句话将会完成的任务:
                    1、生成age的get和set方法声明
                    2、生成一个int类型的成员变量  int _age;(因为生成的变量是@private,所以如果子类需要访问的话,还是需要我们自己写成员变量,这样就不会生成私有的成员变量了)
                    3、生成age的get和set方法的实现
 
    @synthesize的细节
       @synthesize age=_age
        1、setter和getter实现中会访问成员变量_age;
        2、如果成员变量不存在,就会自动生成一个@private的成员变量_age
       @synthesize age
          1、setter和getter实现中会访问age变量
          2、如果成员变量age不存在,就会自动生成一个@private的成员变量age
       手动实现
          1、若手动实现setter方法,编译器就只会自动生成getter方法
          2、若手动实现getter方法,编译器就只会自动生成setter方法
          3、若手动同时实现了setter和getter方法,编译器就不会自动生成不存在的成员变量
        
id         
    id是万能指针,能指向\操作任何OC对象
    id内部包含*,所以声明变量的时候不需要带 *
    NSString * (字符串)也是OC对象,所以id也可以指向字符串
    也就是说 id 相当于  NSObject  *
 
    id类型的定义:
        typedef  struct objc object{
            Class isa;
        } *id;
 
    局限性:
        调用一个不存在的方法的时候,编译器会马上报错
 
 
构造方法:对象方法
    构造方法:用来初始化对象的方法,是个对象方法,以 -号开头
    重写构造方法的目的:为了让对象创建出来,成员变量就会有一些固定的值
    
    Person *p = [Person new];
    new方法完整的创建一个对象(分别调用两个方法完成下面的工作):
        1、分配存储空间(+alloc)
        2、初始化(-init)
    
    new方法内部进行的工作:
    //调用+alloc方法分配存储空间
    Person *p1 = [Person alloc];
    //调用-init方法进行初始化
    Person *p2 = [p1  init];
 
    init方法就是构造方法:
    等价于:Person *p = [[Person alloc] init];
 
    对象初始化之后,对象的成员变量默认为0
 
    当要求每个Person对象创建出来的时候,他的成员变量_age都是10
        构造方法的注意点:
        1、先调用父类的构造方法 ([super init])
        2、在进行子类内部成员变量的初始化
        //重写-init方法
- (id)init
{
   //1、一定要调用super的init方法:初始化父类中声明的一些成员变量和其他属性
 
    //2、如果对象初始化成功,才有必要进行接下来的初始化
    if (self = [super init])
    {
        //初始化成功
        _age = 10;
    }
    //3、返回一个已经初始化完毕的对象
    return self;
}
 
自定义构造函数:
    上面的重写init方法,只能在内部给成员变量赋初始值,声明的对象都一样
    
    自定义构造函数分两步:
        第一步:声明
        第二步:实现
        
    自定义构造方法的规范:
        1、一定是对象方法,一定以   -   开头
        2、返回值一般是id类型
        3、方法名一般以initWith开头
    声明:
     - (id)initWithName:(NSString *)name;
 
    实现:
      - (id)initWithName:(NSString *)name
        {
            if(self = [super init])
            {
                _name=name;
            }
            return self;
        }
      当子类中的初始化方法需要使用父类的成员变量的时候,原则是:子类中的成员变量在子类中初始化,父类的成员变量在父类中初始化。(父类中提供初始化方法,然后子类将值传递过来)
        这样做的好处就是:当父类中的成员变量发生变化的时候,子类不需要更改不会报错。直接改父类就行了
        
 
Category:分类
    分类:可以给某一个类扩充一些方法(不修改原来类的代码)-》相当于C#中的partial
    
    //声明
    @interface 类名 (分类名称)
 
    @end
    
    //实现
    @implementaion 类名 (分类名称)
 
    @end
 
    使用注意:
        1、分类只能增加方法,不能增加成员变量
        2、分类方法实现中可以访问原来类中声明的成员变量
        3、如果分类中的方法与原来类中的方法重名,那么优先调用的是分类中的方法。(这样就会覆盖原来类中的方法,原来类中的方法将不能使用)
        4、方法调用的优先级:分类(最后参与编译的分类优先)-->原来类-->父类
 
 characterAtIndex:<#(NSUInteger)#>:字符串的这个方法是获取指定位置上的字符(位置序号从0开始)
 
 
类的本质:
    1、类也是个对象。简称“类对象”
        ->其实类也是一个对象,是一个Class类型的对象。
            Class关键字内部包含 * ,使用的时候后面不需要加 *
        利用Person类对象,创建Person类型的对象
        
        //获取内存中的类对象(获取到的类对象可以调用类方法)
        Person *p = [[Person alloc] init];
        Class c = [p class];
        或者:Class  c = [Person class];
    
      类的加载过程:
        + (void)load:方法,在类被加载的时候调用
        程序启动的时候会加载所有的类和分类,并调用所有类和分类的+load方法
        先加载父类,再加载子类,也就是先调用父类的+load,再调用子类的+load
        先加载原始类,再加载分类
        不管程序运行过程中有没有用到这个类,都会调用+load加载
 
        +initialize
        在第一次使用某个类时(比如创建对象等),就会调用一次+initialize方法
        一个类只会调用一次+initialize方法,先调用父类的,在调用子类的
 
        当程序启动时,就会加载项目中所有的类和分类,而且加载后会调用每个类和分类的+load方法,先调用原始类的load方法,后调用分类的load方法
        当第一次使用某个类时,就会调用当前类的+initialize方法
        先加载父类,再加载子类(先调用父类的+load方法,在调用子类的+load方法)
            先初始化父类,再初始化子类(先调用父类的+initialize方法,再调用子类的+initialize方法)
        
    
description方法:
    -description(决定实例对象的输出结果)
 
    Person *p = [[Person alloc] init];
    //默认情况下,利用NSLog和%@输出对象时,结果是: <类名:内存地址>
    NSLog(@"%@",p);
    打印OC对象使用的占位符是%@
    打印OC对象的话(除了NSString *),显示的是类名加上类在内存中的地址
    
    执行NSLog(@"%@",p);这句代码的时候:
        1、首先会调用对象p的-description方法
        2、拿到-description方法的返回值(NSString *)显示到屏幕上
        3、-description方法默认返回的是“类名:内存地址”
    当想输出对象的内容的时候,可以在类的实现中重写-description方法:
          - (NSString *)description
{
    return [NSString stringWithFormat:@"age=%d,name=%@",_age,_name];
}
    
    不要在description中尝试输出self:NSLog(@"%@",self),这样会引发死循环
 
    +description(决定类对象的输出结果)
    
    Class c = [Person class];
 
    //会调用类的+description方法
    //拿到+description方法的返回值(NSString *)显示到屏幕上(默认返回的是类名)
    NSLog(@"%@",c);
    
 
NSLog():   
    打印指针中存储的对象的内存地址:
        NSLog(@"%p",p);
    打印指针变量自己的内存地址:
        NSLog(@"%p", &p);
 
    NSLog()输出C语言字符串的时候,不能有中文
        NSLog(@"%s",_func_);//输出当前方法名称
        NSLog(@"%d",_LINE_);//输出当前行号
        NSLog(@"%s",_FILE_);//输出当前源文件的完整路径
        NSLog(@"%s",__PRETTY_FUNCTION__ );//返回当前方法或函数的完整的函数名(包括返回值和参数)
    
 
SEL类型   
       是一种类型
    一个类中都有SEL类型数据,一个SEL数据对应一个方法的地址
    Person *p = [[Person alloc] init];
    [p test2];
    
    1、把test2包装成SEL类型的数据
    2、根据SEL数据找到对应的方法地址
    3、根据方法地址调用对应的方法(这里使用的缓存技术,第一次会查找,以后就会使用第一次查找的结果)
 
    间接调用test2方法
        [p performSelector:@selector(test2)];
    
   方法的存储位置:
        每个类的方法列表都存储在类对象中
        每个方法都有一个与之对应的SEL类型的数据
        根据一个SEL对象就可以找到方法的地址,进而调用
        SEL类型的定义
        typedef struct objc_selector   *SEL;
 
    SEL对象的创建
        SEL s=@selector(test);
        SEL s2=NSSelectorFormString(@"test");
 
    NSSelectorFormString(@"test");//将一个字符串类型的数据传进去转换成SEL数据
 
    每个方法内部都有一个SEL类型的数据_cmd,指向当前方法
    
        在方法中不能使用[self performSelector:_cmd];
    
    SEL其实是对方法的一种包装,将方法包装成一个SEL类型的数据,去找对应的方法地址,找到方法地址就可以调用方法了。
    其实消息就是SEL
 
 
 
 
 
 

Objective-C:06_面向对象-核心语法

标签:des   style   color   io   使用   ar   strong   for   文件   

原文地址:http://www.cnblogs.com/yaofch107/p/3990794.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!