zoukankan      html  css  js  c++  java
  • oc知识语法

     

    OC1-语法基础


    简介

    本章内容主要对Objective-C语言的基础语法进行阐述,包含以下知识点

    1. OC类的声明语法
    2. OC类的成员变量声明
    3. OC类的方法声明
    4. OC类的实现
    5. OC属性机制
    6. OC对象创建
    7. OC方法调用
    8. OC点语法
    9. Self关键字
    10. 自定义初始化方法

    1,OC类的声明


    OC声明类的关键字为:@interface@end

    关键字后面跟类目和父类名,类名与父类名间用:进行分隔。

    例如:

    @interface Triangle: NSObject
    @end
    

    这样的语句便声明了一个三角形类。 其中NSObject为系统的根类。OC语法中,创建一个类必须指定其父类。当不确定其父类时,用NSObject类作为默认父类。

    2,OC类的成员变量


    为一个类声明成员变量的语法非常简单。如下

    @interface Triangle: NSObject
    {
        //在此大括号内声明成员变量
        double _a;
        double _b;
        double _c;
    }
    @end
    

    其中_a_b_c分别为此类的成员变量。在OC中成员变量通常以_开头。

    成员变量可以设置如下访问权限:

    公开访问@public

    受保护访问@protected

    私有变量@private

    其中受保护的权限是默认权限,也是平时开发常用的权限。在受保护权限下,成员变量只能在本类的方法实现中访问,外界无权访问。

    3,OC类的方法声明


    为一个类声明方法的语法如下

    @interface Triangle: NSObject
    {
        //在此大括号内声明成员变量
        double _a;
        double _b;
        double _c;
    }
    -(void)setA:(double)a;
    -(void)setB:(double)b;
    -(void)setC:(double)c;
    
    -(double)a;
    -(double)b;
    -(double)c;
    
    -(double)area;
    @end
    

    声明方法首先需要确定方法类型。在OC语法中,方法有两种类型分别为

    -(void)test;//减号方法,俗称对象方法
    
    +(void)test;//加号方法,俗称静态方法或类方法
    

    一般情况下都为对象方法,只有在下列特殊情况下使用加号方法

    1. 便利构造器方法
    2. 单例share方法
    3. 对纯过程封装

    这三种情况会在以后的课程中逐步遇到。目前大家统一都只用减号方法。

    声明方法第二步要确定方法的返回值类型。

    -(返回值类型)test;
    

    声明方法第三步确定方法名和参数

    OC声明方法的语法是由参数描述字段 : (形参类型) 形参名

    如果有多个参数,就将此模式依次重复。

    -(void)test;//没有输入参数的方法
    
    -(void)testA:(int)a;//有一个参数的方法声明
    
    -(void)testA:(int)a B:(int)b;//有两个参数的方法声明
    

    方法中有两类较特殊的方法

    类似-(void)setA:(int)a这样为成员变量赋值的方法称为setter方法

    类似-(double)a这样读取成员变量值的方法称为getter方法

    4,OC类的实现


    OC类中所有声明的方法都需要相应实现。实现关键字为@implementation 类名

    例如:

    @implementation Triangle
    
    -(void)setA:(int)a
    {
        _a = a;
    }
    -(void)setB:(int)b
    {
        _b = b;
    }
    -(void)setC:(int)c
    {
        _c = c;
    }
    
    -(double)a
    {
        return _a;
    }
    -(double)b
    {
        return _b;
    }
    -(double)c
    {
        return _c;
    }
    -(double)
    {
        //根据成员变量的值,计算三角形面积
        double s=(_a+_b+_c)/2;
        return sqrt(s*(s-_a)*(s-_b)*(s-_c));
    }
    
    @end
    

    5,OC属性机制


    属性机制是通过声明属性,从而在编译是自动补充代码的一项技术。

    声明一个属性在编译时,会补充一下一系列代码

    1. 声明一个成员变量
    2. 声明一个成员变量的setter方法
    3. 声明一个成员变量的getter方法
    4. 实现一个成员变量的setter方法
    5. 实现一个成员变量的getter方法

    声明属性的关键字为@property代码如下:

    @property double a;
    

    注意:声明的属性为a,但是编译时生成的成员变量为_a。

    通过属性可以把之前的三角形类重构

    @interface Triangle : NSObject
    
    @property double a;
    @property double b;
    @property double c;
    
    -(double)area;
    
    @end
    
    @implementation Triangle
    
    -(double)
    {
        //根据成员变量的值,计算三角形面积
        double s=(_a+_b+_c)/2;
        return sqrt(s*(s-_a)*(s-_b)*(s-_c));
    }
    
    @end
    

    6,OC对象创建


    OC语法中创建对象分三步,缺一不可。

    1. 创建对象指针
    2. 为对象指针分配内存:alloc方法分配内存
    3. 将分配的内存进行初始化:init初始化内存
    Triangle * t;
    t = [[Triangle alloc] init];
    

    7,OC方法调用


    完成对象创建之后,就可以用对象指针调用对象的方法。 OC语言中方法调用使用[]操作符。例如:

    [t setA:10];
    double = [t area];
    

    操作符内有两个参数:第一个参数为对象指针,第二个参数为需要调用的方法。

    -号方法,俗称对象方向,都需要用对象指针进行调用。

    +号方法,俗称类方法,都需要用类目进行调用,例如alloc方法。

    8,OC点语法


    点语法是OC的另一个重要特性。主要用来简化settergetter方法的调用代。

    [t setA:10];//正常语法调用setter方法
    t.a = 10;//使用点语法调用setter方法
    
    double a1 = [t a];//正常语法调用getter方法
    double a2 = t.a;//使用点语法调用getter
    

    使用点语法调用和正常调用完全等价,编译器会根据.和等号的关系自动调用setter还是getter方法。

    9,Self关键字


    在OC语言中,self关键字为方法调用时的隐含参数。self可以在方法的实现中进行使用,代表调用此方法的对象。通常我们使用self调用自己的某些方法

    10,自定义初始化方法


    当一个对象在创建时,需要某些不能缺少的值时。我们可以自己重新定义初始化方法。

    例如三角形对象在创建的时候必须有三个边长信息,不然三角形对象无意义。

    我们就要声明一个新的初始化方法,并实现

    -(instancetype)initWithA:(double)a B:(double)b C:(double)c;
    
    - (instancetype)initWithA:(double)a B:(double)b C:(double)c
    {
        self = [super init];
        if (self) 
        {
            self.a = a;
            self.b = b;
            self.c = c;
        }
        return self;
    }
    

    其中,instancetype为固定写法,表示返回类型有编译检查器自动辨别。在实现中将输入参数依次赋值给本身属性。

    再调用如下代码

    Triangle * t = [[Triangle alloc] initWithA:10 B:11 C:12];
    

    这样就实现了初始化同时赋值。


     

    Objective-C继承与复合


    本章教程主要讨论OC的继承语法以及类的复合编程模式。

    1. OC继承语法
    2. OC语言的动态特性
    3. OC的复合模式
    4. super关键字

    1,OC继承语法


    OC语法只支持单根继承,即一个类只能有一个父类。

    继承关键字为:

    @interface 类目 : 父类名
    

    例如我们昨天声明的三角形类

    @interface Triangle : NSObject
    
    @end
    

    表示Triangle类是继承与NSObject类。Triangle是NSObject的子类,NSObject是Triangle的父类。

    OC语法中规定,通过继承方式,可以继承父类的所有方法和除私有权限以外的所有成员变量。

    例如上一章的三角形类

    @interface Triangle : NSObject
    
    @property double a;
    @property double b;
    @property double c;
    
    -(instancetype)initWithA:(double)a B:(double)b C:(double)c;
    -(double)area;
    
    @end
    
    @implementation Triangle
    
    - (instancetype)initWithA:(double)a B:(double)b C:(double)c
    {
        self = [super init];
        if (self) {
            self.a = a;
            self.b = b;
            self.c = c;
        }
        return self;
    }
    
    -(double)area
    {
        double s=(_a+_b+_c)/2;
        return sqrt(s*(s-_a)*(s-_b)*(s-_c));
    }
    

    本章我们可以通过继承的方法创建一个新的三角形类

    @interface TriangleSub : Triangle
    
    @end
    
    @implementation TriangleSub
    
    @end
    

    可以看到我们新创建的TriangleSub类中没有声明任何方法也没有实现任何方法。但是通过继承语法,我们无偿获得了父类的所有方法和成员变量。

    TriangleSub * subT = [[TriangleSub alloc] initWithA:10 B:11 C:12];
    double s = [subT area];
    NSLog(@"s = %g",s);//NSLog函数是OC中向控制台输出信息的函数
    

    2,OC语言的动态特性


    OC语言是动态类型语言,其表现为调用方法时,不会依据对象指针类型调用对象方法,而根据对象指针使用的内存类型调用响应的方法。

    下面通过代码描述这个特性。

    首先我们创建一个测试类TestClass

    @interface TestClass : NSObject
    
    -(void)test;
    
    @end
    
    @implementation TestClass
    
    -(void)test
    {    
        NSLog(@"这里是TestClass类的test方法");
    }
    @end
    

    我们继续创建两个类:

    SubA继承与TestClass

    @interface SubA : TestClass
    
    
    @end
    
    @implementation SubA
    
    //重写父类的方法
    -(void)test
    {    
        NSLog(@"这里是SubA类的test方法");
    }
    @end
    

    SubB继承与TestClass

    @interface SubB : TestClass
    
    @end
    
    @implementation SubB
    
    //重写父类的方法
    -(void)test
    {    
        NSLog(@"这里是SubB类的test方法");
    }
    @end
    

    现在做如下测试

    SubA * a = [[SubB alloc] init];
    [a test];//这样调用没有编译错误,复合OC的语法规则,那会输出哪个结果。
    

    根据我们之前讲的,OC的动态特性的表现形式

    对象指针在调用方法是,不会根据对象指针类型调用响应方法,而是根据对象指针指向的内存类型调用响应的方法

    由此可见,对象指针a的类型为SubA类型,但其指向的内存类型为SubB类型。所以用对象指针调用test方法时,会调用SubB的test方法。

    其输出结果为:这里是SubB类的test方法。

    由于OC语法动态特性的原因,在编写代码的过程中,对象指针类型只在编译时起作用。在运行过程中没有任何影响。

    OC语法推出一个id关键字,表示在编译过程中不指定类型。

    使用id类型编写代码对运行不会有任何影响。但在IDE环境中,变无法开启代码自动补全功能,因IDE工具并不知道该对象指针是什么类型,所以无法进行代码自动提示和补全。

    3,OC的复合模式


    在OC的复合模式就是把其他对象作为自身的题部分,以提升自身的功能。

    比如我现在要制作一台电脑,电脑需要CPU,显示器,鼠标和键盘等。这些东西的研发都是很复杂的过程。如果现在有成型的CPU等组件,就可以直接用这些组件攒一台电脑。复合模式就是这样。

    所有我们在制作电脑前要先找到这些组件。这些组件并不需要我们来制作,有专业的公司提供这些成型的组件。

    在本章练习的SDK中提供了如下组件。

    KeyBoard    键盘类
    BigMouse    鼠标类
    Monitor        显示器类
    IntelCPU    CPU类
    

    下面就用SDK中提供的各种组件来快速制作一台电脑。

    首先我们进行电脑类的声明。需要使用的组件都声明成属性,作为电脑类的一部分。

    @interface Computer : NSObject
    
    @property(strong, nonatomic) KeyBoard * aKeyBoard;
    @property(strong, nonatomic) BigMouse * aMouse;
    @property(strong, nonatomic) Monitor  * aMonitore;
    @property(strong, nonatomic) IntelCPU * aCPU;
    
    @end
    

    在这里我们先补充一下属性括号中的内容。

    属性括号中的内容为属性控制符,分别对属性的读写权限,内存管理和线程操作做出相关规定。

    1. 读写权限由两个关键字控制,分别为:readonlyreadwrite。其中如果不写默认为readwrite。通常属性的读写权限都为可读可写。
    2. 内存管理权限由四个关键字控制,分别为:assgin,strong,weakcopy。如果不写,默认为assgin。如果属性类型为基本数据类型,那么只能用assgin。如果属性类型为对象指针,一般情况下用strong,特殊情况下用weakcopy。特殊情况在后面的内存管理章节会展开讲解。

      3. 线程操作权限由两个关键字控制,分别为:atomicnonatomic。其中如果不写默认为atomic。通常我们使用nonatomic作为线程操作,其具体内容在后续的多线程章节会展开讲解。

    然后继续实现电脑类,因CPU等组件是电脑的一部分,所以我们需要重新电脑的初始化方法,在电脑初始化的的同时也初始化各种组件,为其分配内存。

    @implementation Computer
    
    - (instancetype)init
    {
        self = [super init];
        if (self) 
        {
            self.aKeyBoard = [[KeyBoard alloc] init];
            self.aMouse = [[BigMouse alloc] init];
            self.aMonitore = [[Monitor alloc] init];
            self.aCPU = [[IntelCPU alloc] init];
        }
        return self;
    }
    
    @end
    

    经过声明组件属性,为组件的对象指针分配内存。我们就使用成型的组件快速的制作好了一个功能完整的电脑。

    4,super关键字


    通常继承和复合会一同使用,来快速构造一个复杂的对象。

    例如现在有一个需求,要求我们快速制作一个可以除甲醛的高级空调。通常我们并不是从零开始研发,而是基于一定基础开始制作。

    在这里,我提供了两个对象作为研发的基础

    1. Kongtiao类,具有制冷方法
    2. ChuJiaquan类,具有除甲醛的方法

    以下是Kongtiao类的声明

    @interface Kongtiao : NSObject
    
    -(void)zhiling;
    
    @end
    

    以下是ChuJiaquan类的声明

    @interface ChuJiaQuan : NSObject
    
    -(void)chuJQ;
    
    @end
    

    首先明确我们制作的是一个空调,所有我们创建一个高级空调类继承与空调类。

    然后高级空调需要有除甲醛的功能,我们通过复合模式,把除甲醛的模块作为高级的空调的一部分。

    最后我们重写父类的制冷方法,在制冷过程中添加除甲醛的步骤。但是在重写的方法会覆盖掉父类原有的方法。这里我们需要在重写方法中手动调用父类原始方法。就需要用到super关键字。

    @interface NewKongtiao : Kongtiao
    
    @property(strong, nonatomic) ChuJiaQuan * cJQ;
    
    @end
    
    @implementation NewKongtiao
    
    - (instancetype)init
    {
        self = [super init];
        if (self) 
        {
            self.cJQ = [[ChuJiaQuan alloc] init];
        }
        return self;
    }
    -(void)zhileng
    {
        [super zhileng];
        [self.cJQ chuJQ];
    }
    
    @end
    

    这样我们在使用高级空调制冷的同时,也同时能够除甲醛

     

    OC3-语言特性


    本章主要讲解OC语言特性

    1. 类目(Category)
    2. 延展(Extension)
    3. 协议(Protocol)

    1,类目


    OC语言中的类目机制只有一个作用:为任何一个类添加方法

    现在我们创建一个Student类

    @interface Student : NSObject
    
    @property(nonatomic,strong)NSString * name;
    
    @end
    
    @implementation
    
    @end
    

    如果想为Student类添加一个方法,现在有两种方法

    1. 直接修改Student类的源码,声明一个方法并实现。
    2. 使用类目。

    在无法获取类的源码且需要给一个类添加方法的情况下,类目的作用就非常重要了。

    创建类目的语法也非常简单,代码如下

    @interface Student (Test)
    
    -(void)test;
    
    @end
    
    @implementation Student (Test)
    
    -(void)test
    {
        NSLog(@"这里是Student类目的test方法");
    }
    @end
    

    声明和实现的关键字都和之前一样。

    不同的是,声明时候不需要指定父类,而是直接写要添加方法的类的名字,但后面一定要加一个括号,且括号里面写上类目名字。一个类可以有多个类目。

    有了这个类目之后,虽然Student类的源码中没有test方法,但仍然可以正常用Student对象去调用这个方法。

    Student * s = [[Student alloc] init];
    [s test];
    

    2,延展


    延展可以看作是一种匿名的类目,类有时需要一些只为自己所见,所用的私有方法这种私有方法可以通过延展的方式来声明。

    比如上文中的Student类有一个作弊的方法,不像被外界看得,但有不影响本身调用。这个方法就可以声明在延展内,而方法的实现仍然在Student的类内。

    @interface Student ()
    -(void)zuobi;
    @end
    

    通常我们会将类的声明放在扩展名为.h的文件内,实现放在扩展名为.m的文件内。在生产的可执行文件包种.m文件会被编译加密成.a文件,且不可逆转。

    Student.h文件

    @interface Student : NSObject
    
    @property(nonatomic,strong)NSString * name;
    
    @end
    

    Student.m 文件

    @interface Student ()
    -(void)zuobi;
    @end
    
    @implementation Student (Test)
    
    -(void)test
    {
        NSLog(@"这里是Student类目的test方法");
    }
    
    -(void)zuobi
    {
        NSLog(@"正在作弊");
    }
    
    @end
    

    通常将延展的声明也放在.m文件中,这样便可以隐藏类的方法,不被外界所发现且类内可以正常使用。

    3,协议


    OC中的协议为一组方法的声明。不需要实现。遵守协议的类负责实现协议中的方法。

    协议使用@protocol关键字进行声明。

    其声明的方法中分为必须实现的方法和可选实现的方法。分别用@required@optional关键字标示。

    如果不写默认为必须实现的方法。

    @protocol Test <NSObject>
    
    @required
    -(void)fun1;//遵守该协议的类,必须实现的方法
    
    @optional
    -(void)fun2;//遵守该协议的类,可选实现的方法
    
    @end
    

    制定协议很简单,我们可以通过协议去规定一个对象的行为。

    例如下面的方法

    -(void)test:(id<Test>)obj;
    

    这个方法便要求,obj对象必须是遵守Test协议的类创建的对象。

    @property id <Test>obj;
    

    同样,属性对象也可以用协议进行规定

     
  • 相关阅读:
    编码导致 html和aspx 样式差异,变形
    Recommand of the Day:Names in English
    NSBundle常用方法及解释
    在K8S 中部署 Spring Boot 应用,爽!
    如果抛开 Spring,如何自己实现 AOP?面试必问。。。
    为什么阿里强制 boolean 类型变量不能使用 is 开头?
    CTO 说禁用 Lombok,看我怼死他。。
    面试官:什么是 YAML?和 Spring Boot 有什么关系?
    面试官:线程池多余的线程是如何回收的?
    JetBrains 发布下一代 IDE,无比轻量,几秒就能启动干活,IDEA 可以扔了。。
  • 原文地址:https://www.cnblogs.com/caomeixiangni-324/p/4699758.html
Copyright © 2011-2022 走看看