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

点语法:

 

 点语法的本质还是方法调用

当使用点语法时,编译器会自动展开成相应的方法

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

时间: 2024-08-01 23:23:28

Objective-C:06_面向对象-核心语法的相关文章

C#编程语言与面向对象——核心

面向对象的核心 (1).封装 封装的类=数据+对此数据所进行的操作(即算法) 封装起外界不必需要知道的东西,指向外界展现可供展示的东西. 小到一个简单的数据结构,大到一个完整的软件子系统.静态的如某软件系统要收集数据信息项,动态的如某个工作处理流程,都可以封装到一个类中. 具备这种意识,是掌握面向对象分析与设计技巧的关键. (2).抽象 在使用面向对象的方法设计一个软件系统时,首先就要区分出现实世界中的事务所属的类型,分析它们拥有哪些性质与功能,再将他们抽象为在计算机虚拟世界中才有意义的实体——

Day7 - 面向对象高级语法

参考文章:http://www.cnblogs.com/alex3714/articles/5213184.html 本节内容: 面向对象高级语法部分 静态方法.类方法.属性方法 类的特殊成员方法 反射 静态方法                                                                                   通过 @staticmethod 装饰器即可把其装饰的方法变为一个静态方法,什么是静态方法呢?其实不难理解,普通的方法,可

PHP核心语法总结

这些天学习了PHP的核心编程语法,PHP核心语法概括起来不多,大致分为php标签,语法规范.数据类型.变量.常量.当然还有预定义的,还有操作符.循坏等等,最后几天学习了函数,其中数组的常用函数非常多.例如array_merge.rand.asort.arsort这些,在日后项目中会用的比较多. 数组的函数里,foreach()与while-list-each()两个遍历数组的函数最为强大,不仅能解决访问数组的问题,而且它的返回值各有特点,可以灵活运用在往后数据库数据的处理中. 平时的应用PHP语

黑马程序员— OC核心语法之构造方法、Category分类、类的本质、description和SEL

------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 上一章我们学习了OC的一些核心语法,初步了解了OC作为一门开发语言的一些较为深层次的知识.本章我们继续学习OC的核心语法,主要包括OC的构造方法,Category分类,类的本质及深入研究,以及description关键字和SEL关键字. 第一讲     构造方法 1. 构造方法 构造方法是用来初始化对象的方法,是一个对象方法,以减号"-"开头,构造方法其实就是init方法,初始化完毕

关情纸尾-----OC面对对象的核心语法

有点愧疚,这几个月荒废了,也浪费了很多时间. 接下来是我看的关于核心语法的一些笔记,可能不全也可能有错误,希望大家可以指出来. 一.点语法 点语法的本质是调用. 例如: Person *p = [Person new]; //赋值 p.age = 10; // 等价于[P setAge:10];调用setter //取值 int a = p.age;// 等价于[P age];调用getter 二.成员变量的作用域 @public  任何地方都能直接访问 @private 只能在当前类的对象方法

Python自动化 【第七篇】:Python基础-面向对象高级语法、异常处理、Scoket开发基础

本节内容: 1.     面向对象高级语法部分 1.1   静态方法.类方法.属性方法 1.2   类的特殊方法 1.3   反射 2.     异常处理 3.     Socket开发基础 1.     面向对象高级语法部分 1.1   静态方法.类方法.属性方法 1)   静态方法 通过@staticmethod装饰器即可把其装饰的方法变为一个静态方法.普通的方法,可以在实例化后直接调用,并且在方法里可以通过self.调用实例变量或类变量,但静态方法是不可以访问实例变量或类变量的,一个不能访

Java和C#在面向对象上语法的区别

做了几年了开发一直没有总结什么,回到了家乡的小城做了一名培训班的教员,教授软件开发的知识.细小的知识从头细细嚼来,别有一番滋味.或是以前遗漏的太多,或是确实没有系统的学习过,教学生的过程中自己也对教材有了一遍系统深入的学习.虽然教的和学的都很肤浅,但是为了帮助学生们理解,然后自己也会思考为什么会这样?这种来自于最基础的思考,一直向上反馈,发现这种思考原来可以令自己进步的非常快.虽然目前还在思考入门阶段的问题,已经受益良多了.那么如果把之前的开发中的问题都思考一遍,又能收获多少能?写写博客吧,一直

重温面向对象核心 下 : 你一定能看懂的委托和事件

实例解读面向对象核心,所有例子基于 C#,涉及我们实务中最常关心的问题: 1.封装.继承.多态: 2.抽象类.接口: 3.委托.事件. 三.委托和事件 通俗的说,我们使用委托的目的是“实现将方法作为参数传递的效果”,直接结合例子说明. 我们还是用基于上次的示例往下更改. 场景设定:根据图形的不同,返回不同的面积算法. // 参数为图形形状, 返回该图形的面积计算公式 public string GetAreaAlg(string shapeName) { if (shapeName=="矩形&q

3.2面向对象基础语法

面向对象基础语法 目标 dir 内置函数 定义简单的类(只包含方法) 方法中的 self 参数 初始化方法 内置方法和属性 01. dir 内置函数(知道) 在 Python 中 对象几乎是无所不在的,我们之前学习的 变量.数据.函数 都是对象 在 Python 中可以使用以下两个方法验证: 在 标识符 / 数据 后输入一个 .,然后按下 TAB 键,iPython 会提示该对象能够调用的 方法列表 使用内置函数 dir 传入 标识符 / 数据,可以查看对象内的 所有属性及方法 提示 __方法名