【Objective-C基础知识-05】关键字self、点语法

一、传统的get方法和set方法

  在Java中,我们可以通过"对象名.成员变量名"来访问对象的公共成员变量,这个就称为"点语法"。在正式学习OC的点语法之前,先来看一下传统的get方法和set方法。定义一个Student类,拥有一个成员变量age和对应的get\set方法。

  Student.h

 1 #import <Foundation/Foundation.h>
 2
 3 @interface Student : NSObject {
 4     int age;
 5 }
 6
 7 - (void)setAge:(int)newAge;
 8 - (int)age;
 9
10 @end

  上面的代码做了这样的操作:

   (1) 在第4行定义了一个成员变量age,是@protected权限的,所以外界不能直接访问它

    (2)在第7、8行分别声明了age变量的set方法和get方法

  Student.m

 1 #import "Student.h"
 2
 3 @implementation Student
 4
 5 - (void)setAge:(int)newAge {
 6     age = newAge;
 7 }
 8
 9 - (int)age {
10     return age;
11 }
12
13 @end

  上面的代码做了这样的操作:

    (1) 在第5行实现了set方法

    (2)在第9行实现了get方法

  main.m

    把定义好的Student类放到main函数中使用

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

int main(int argc, const char * argv[])
{
    @autoreleasepool {
        Student *stu = [[Student alloc] init];

        // 设置age的值
        [stu setAge:10];

        // 取出age的值
        int age = [stu age];

        NSLog(@"age is %i", age);

        [stu release];
    }
    return 0;
}

  上面的代码做了这样的操作:

    (1)在2行包含Student的头文件

    (2)在第7行创建Student对象,在第17行释放Student对象

    (3)在第10行调用set方法设置age的值

    (4)在第13行调用get方法获取age的值

    (5)在第15行输出age的值,输出结果如下:

2015-12-06 01:03:19.002 点语法[6164:303] age is 10

  这就是OC传统的get方法和set方法的简单使用,对初学者来说,这个语法比较奇怪,因为它的方法调用是用方括号[ ]完成的。因此,OC最终引入了点语法。

二、使用点语法代替传统的get方法和set方法

  上面演示了OC传统get\set方法的简单用法,接下来使用点语法来代替。

  前面main.m中main函数的代码可以改为:

 1 int main(int argc, const char * argv[])
 2 {
 3     @autoreleasepool {
 4         Student *stu = [[Student alloc] init];
 5
 6         // 设置age的值
 7         stu.age = 10; // 等价于[stu setAge:10];
 8
 9         // 取出age的值
10         int age = stu.age; // 等价于int age = [stu age];
11
12         NSLog(@"age is %i", age);
13
14         [stu release];
15     }
16     return 0;
17 }

  1.注意第7行代码,把原来的[stu setAge:10]替换成了stu.age = 10。听清楚了,这两种写法是完全等价的。即这里的stu.age并不是代表直接访问stu对象的成员变量age,而是编译器遇到stu.age = 10的时候会自动将代码展开成[stu setAge:10]

  再说,如果是直接访问成员变量的话,OC中应该是这样的语法:stu->age,而不是stu.age。

  2.注意第10行代码,把原来的int age = [stu age]替换成了int age = stu.age。这两种写法又是完全等价的,stu.age并不是直接访问stu对象的成员变量age,而是编译器遇到int age = stu.age的时候会自动将代码展开成int age = [stu age]

  3.因此,OC中点语法的含义跟Java是完全不一样的,OC点语法的本质是方法调用,不是直接访问成员变量。至于这个点语法代表的是get方法还是set方法,那就取决于你是取值还是设值,取值就是get方法(如第10行代码),设值就是set方法(如第7行代码)。

  4.如果你想验证点语法是不是方法调用的话,有很多方法。比如你可以在Student.m的set方法和get方法内部用NSLog加一些打印信息,如果程序运行后有输出打印信息,说明的确是调用了get方法或者set方法

#import "Student.h"

@implementation Student

- (void)setAge:(int)newAge {
    NSLog(@"调用了setAge方法");
    age = newAge;
}

- (int)age {
    NSLog(@"调用了age方法");
    return age;
}

@end

三、点语法和self的陷阱

1  - (void)setAge:(int)newAge {
2      self.age = newAge;
3  }

  第2行中的self代表着当前调用setAge:方法的对象。但是第2行代码是绝对错误的,会造成死循环。因为我在前面已经说过了,OC点语法的本质是方法调用,所以上面的代码相当于:

1  - (void)setAge:(int)newAge {
2      [self setAge:newAge];
3  }

  很明显,会造成循环调用setAge:方法,程序就这样崩溃了

四、一点小建议

  如果是第一次接触OC的点语法,你可能会真的以为stu.age的意思是直接访问stu对象的成员变量age。其实,有一部分原因是因为我这里定义的Student类的成员变量名就叫做age。为了更好地区分点语法和成员变量访问,一般我们定义的成员变量会以下划线 _ 开头。比如叫做 _age 。

  1.Student.h,注意第4行

 1 #import <Foundation/Foundation.h>
 2
 3 @interface Student : NSObject {
 4     int _age;
 5 }
 6
 7 - (void)setAge:(int)newAge;
 8 - (int)age;
 9
10 @end

  2.Student.m,注意第6行和第10行

 1 #import "Student.h"
 2
 3 @implementation Student
 4
 5 - (void)setAge:(int)newAge {
 6     _age = newAge;
 7 }
 8
 9 - (int)age {
10     return _age;
11 }
12
13 @end
时间: 2024-08-25 21:55:14

【Objective-C基础知识-05】关键字self、点语法的相关文章

JS基础知识回顾:ECMAScript的语法(一)

任何语言的核心都必然会描述这门语言最基本的工作原理,而描述的内容通常都要涉及这门语言的语法.操作符.数据类型.内置功能等用于构建复杂解决方案的基本概念. ECMAScript中的一切变量.函数名.操作符都区分大小写. ECMAScript的标识符要符合下列规则:第一个字符必须是字母.下划线或美元符号:其他字符可以是字母.下划线.美元符号或数字. 标识符中的字母也可以包含扩展的ASCII或Unicode字母字符,但是并不推荐. 按照惯例,ECMAScript标识符采用驼峰大小写的格式来书写,尽管没

JS基础知识回顾:ECMAScript的语法(三)

ECMA-262描述了一组用于操作数据值的操作符,包括算术操作符.位操作符.关系操作符和相等操作符. ECMAScript操作符的与众不同之处在于,他们能够适用于很多值,例如字符串.数字值.布尔值.甚至是对象. 在将这些操作符应用于对象时,相应的操作符通常都会调用对象的valueOf()和(或)toString()方法,以便取得可以操作的值. 只能操作一个值的操作符叫做一元操作符. 递增和递减操作符直接借鉴自C,各有前置型和后置型两个版本:a++.++a.a--.--a 这四种操作符不仅适用于整

JS基础知识回顾:ECMAScript的语法(二)

ECMAScript中有五种简单数据类型(也称为基本数据类型):Undefined.Null.Boolean.Number.String ECMAScript还有一种复杂数据类型——Object,Object本质上是由一组无序的名值对组成的. ECMAScript不支持任何创建自定义类型的机制,而所有值最终都将是上述六种数据类型之一,由于ECMAScript的数据类型具有动态性,因此的确没有再定义其他数据类型的必要了. 监狱ECMAScript是松散类型的,因此需要有一种手段来检测给定变量的数据

ios基础知识--05

1.UIView的tag属性 /* 1.所有直接或者间接继承UIVIew的控件都有一个tag属性 2.这个属性,只能用来保存一个数字,对控件的外观没有任何影响 3.但是我们可以通过这个属性的值,来判断是哪个控件 */ 2.transform属性 /* 1. 可以使用动画,叫做变换 2. CGAffineTransformIdentity 如果赋值,那么之前通过transform属性进行的修改都会复原:_imageButton.transform= CGAffineTransformIdentit

C# 基础知识 protected 关键字

class BaseTest { public int a = 10; protected int b = 2; protected void Test() { } } class ChildTest : BaseTest { int c; int d; public void printTest() { //protected 关键字是一个成员访问修饰符. 受保护成员在其所在的类中可由派生类实例访问: //既只有在通过派生类类型发生访问时,基类的受保护成员在派生类中才是可访问的. //=>(1

python基础知识0-5(单双向队列)

#多项队列import collections #导入模块d = collections.deque() #deque方法d.append('1') #添加元素d.appendleft('2')d.append('1')r = d.count('1') #查看队列元素出现次数d.extend(['yy','uu','ii'])#扩展队列也就是在后面添加元素d.extendleft(['a','b','c'])print(d)d.rotate(1) #最后一位挪到首位(从队列得尾部拿数据插入到首位

python基础知识 05 python语言中的大整数

第五课 python语言中的大整数 java中的int 最大可以处理 2^31 -1(2147483647) 最小呢-2^31 (-2147483647)但是在Java中可以使用BigInteger 来处理无线大的数 print(2 ** 60) 结果为 1152921504606846976 print(2 ** 600) 41495155688809929585124078636911611510124462322424368999956573296906528114129081463997

iOS开发基础知识--碎片16

iOS开发基础知识--碎片16  1:Objective-C语法之动态类型 (isKindOfClass, isMemberOfClass,id) 对象在运行时获取其类型的能力称为内省.内省可以有多种方法实现. 判断对象类型 -(BOOL) isKindOfClass: classObj判断是否是这个类或者这个类的子类的实例 -(BOOL) isMemberOfClass: classObj 判断是否是这个类的实例 实例一: Person *person = [[Person alloc] in

C#基础知识之base关键字

前言 其实很早就想写关于C#基础,总是自己给自己找借口,或者去网上搜搜看看,现在想想觉得自己有点懒惰...  作为开发人员,基础知识是重中之重的,只有巩固.理解.实践才能提高自身的技能.同时也希望通过这个系列,能够帮助需要巩固基础的人. base关键字 调用基类已被派生类重写的方法 public class Father { public virtual void Say() { Console.WriteLine("Father Say"); } } public class Son