C++快速学习Objective-C语言核心语法

   本文将Objective-C讨论了语言的核心语法。这部分开始详述一些具体的语法。正如你期待的一样,涉及到了定义和类。

  类并不是特殊的

  在Smalltalk中,类是具有一些特性的对象。在Objective-C中也一样。一个类是一个对象,对象回应消息。Objective-C和C++都分离了对象分配和初始化。

  在C++中,对象分配通过新的操作。在Objective-C中,这样的操作是通过给类发送分配消息—调用malloc()或者一个等价。

  C++中的初始化是通过调用一个与类同名的函数。Objective-C并没有区别初始化方法和其他方法,但出于惯例缺省的初始化方法就是初始化。

  当你声明一个方法让实例去回应,声明通常已“-”开头,并且“+”用作类的方法。在文档中对这些消息使用一些前缀是很普遍的,所以你也可以说+alloc和-init来暗示alloc是传给一个类,init传给实例。

  类在Objective-C中,正如在其他一些面向对象语言,都是对象工厂。大多数类不用自行实现+alloc,而是从他们的父类中继承。在 NSObject中,父类在大多数Objective-C程序中,+alloc方法调用+allocWithZone:.使NSZone作为一个参数,一 个C结构包含对象分配的一些策略。回顾19世纪80年代,当Objective-C用在NeXTstep来实现设备驱动和只有8MB内存25MHZ的 CPU机器的GUI上面时,NSZone对优化非常重要。同时,这或多或少的被Objective-C程序员所忽视。(很有可能成为象NUMA构架一样流 行,更普遍。)

  众多优秀的特性之一就是对象创建语义是由库定义的并且语言不是类簇的思想。当你传一个-init消息给对象时,它返回一个初始化对象。这可能是你发送消息的那个对象,但不一定肯定就是。这和其他初始化程序一致的。很有可能一些公共类的特殊子类在不同数据上更有效。

  实现这个特性的通用方法叫做isa-swizzling。正如我前述,Objective-C对象是C结构,这些结构第一个元素是指向类的指针。这 个元素是可存取的,正如其他实例变量一样;你可以在运行时通过分配新值来改变对象的类。当然,如果你对对象的类设置在内存中有着不同的布局,这些设置可能 严重错误。

  然而,你可以通过一个父类来定义布局和通过子集的集合定义行为,举例来说,这个技术用在标准化字符串类(NSString),它对不同的文本字符集、静态事物和其它一些有着各种各样的实例。

  因为类是对象,你可以象操作对象一样操作他们。举例来说,你可以把他们放在集合。当我有一些输入事件需要通过不同的类的实例来处理时我就使用这种格 式。你需要创建一个目录映射事件命名到类,然后为每一个输入事件实例化一个对象。如果你在一个库中这么做,它允许代码的使用者轻松的注册属于他们自己的句 柄。

  类型和指针

  Objective-C没有公开允许在堆栈上定义对象。但并不是真的—很有可能在堆栈上定义对象,但有些困难,因为它破坏了对内存管理的一种假设。 结果,每一个Objective-C对象都是一个指针。一些类型由Objective-C定义;这些类型在头部定义作为C类型。

  在Objective-C中最普遍的3种类型就是id,Class和SEL。id就是指向Objective-C对象的指针,它等价于C语言中的void*,你可以映射任何对象指针类型指向它并且映射他指向其它的对象指针类型。

  你可以传任何消息给id,但如果不支持的话会返回一个运行时异常。

  类是指向Objective-C类的指针。类是对象,所以也可以接收消息。类名是一种类型,不是可变的。标识符NSObject是一个NSObject实例的类型,但也可作为消息接受者。你可以获得一个类,如下:

  [NSObject class];

  发送一个+class消息给NSObject类,然后返回一个指向代表类的类结构指针。

  这对我们回顾是非常有用的[FS:PAGE],正如我们在这个系列第二部分看到的一样。

  第三种类型SEL,代表一个选择器—一个代表方法名的抽象。你可以在编译时通过@selector()直接创建,或在运行时通过C字符串调用运行时 库函数,或用OpenStep NSSelectorFromString()函数,这个函数给Objective-C字符串一个选择器。这个技术允许你通过名字调用方法。你可以在C中 通过使用类似dlsym(),但在C++中非常不同。在Objective-C中,你可以做的如下:

  [object perfomSelector:@selector(doSomething)];

  这等价于如下:

  [object doSomething];

  显然,第二种格式速度稍微快些,因为第一种传送两个消息。后面,我们会看到通过选择器处理的一些细节。

  C++没有与id相同的类型。因为对象总是可以类型化的。在Objective-C,你可以选择类型系统。下面的两种都是有效的:

  id object = @”a string”;

  NSString *string = @”a string”;

  常量字符串实际上是NSConstantString类的一个实例,NSConstantString类是NSString的子类。将它引用到 NSString* 使编译时对消息进行类型检查和存储公共实例变量(这在Objective-C从未使用过)。注意你可以通过如下改变这一设置:

  NSArray *array = (NSArray*)string;

  如果给数组发送消息,编译器将会检查NSArray能接收的消息。这并不是非常有用,因为对象是一个字符串。如果发送一个NSArray和NSString实现的消息,可能会有作用。如果你发送的消息NSString没有实现,一个异常将会抛出。

  强调Objective-C和C++的不同的这件事看起来比较奇怪。Objective-C有类型-值语法,而C++有类型-变量语法。在Objective-C,对象类型是对象专有的一种属性。在C++,类型取决于变量的类型。

  在C++中,当你指派一个指针指向一个对象到一个变量定义一个指向父类的指针,两个指针可能没有相同的数值(这可以通过多继承实现,而Objective-C不支持这种。)

  定义类

  Objective-C类定义有一个接口和一个实现部分。与C++有相似的地方,但两个稍微有些混。

  Objective-C中的接口仅定义位并且明确的需要公开。对于实现的原因,这包括私有实例变量在大部分的实现中,因为你无法继承一个类除非你知道它多大。最近的一些实现,象Apple的64位运行时则没有这种限制。

  Objective-C对象的接口如下:

  @interface AnObject : NSObject

  {

  @private

  int integerivar

  @public

  id anotherObject;

  }

  + (id) aClassMethod;

  - (id) anInstanceMethod:(NSString*)aString with:(id)anObject

  @end

  第一行包含3个部分。标识符AnObject 是新类的名字。冒号后面的名字是NSObject。(这是可选的,但每一个Objective-C 对象都应拓展NSObject)。在括号内的名字是协议——与Java中的接口相似——通过类来实现。

  正如C++实例变量(C++中的域)可以存取修饰符,不象C++,这些修饰符以@为前缀是为了避免与C标识符冲突。

  Objective-C不支持多继承,所以只有一个父类。所以,对象第一部分的布局总是与父类实例的布局一致。这在过去常常定义为动态,意味着改变 类中实例变量需要它所有子类重新编译。在较新的运行时这种限定并不要求,在存取实例实例变量上开支稍微大些。这种决策的另一个影响就是 Objective-C其他特性中的一个。

  struct_AnObject

  {

  @defs(AnObject);

  };

  @def表示着对特定对象所有域都插入这种结构,所以struct_AnObject 和AnObject类的实例有着相同的内存结构。举个例子来说,你可以通过这种规则可以直接存取实例变量。一个通常的用法就是允许C函数直接操作 Objective-C对象,是基于性能原因。

  正如我前面暗示的,与这个特性相关的另一件事就是可以在堆栈上创建对象。因为结构和对象在[FS:PAGE]内存布局中有着相同的结构,你可以简单的创建 结构,设置他的指针指向正确的类,然后映射一个指针指向一个对象指针。然后你可以当做对象来使用,虽然你不得不小心没有什么可以保持指针不越界。(现实世 界中我从没有使用这种方法,仅仅理论上可能。)

  不象C++,Objective-C没有私有的或受保护的方法。Objective-C对象上的任何方法可以被其他对象调用。如果你在接口中没有声明方法,就是非正式私有的。将会得到运行时警告:对象不回应这种消息,但是你任然可以调用它。

  接口和C中头部声明很相似。但它仍然需要一个实现,这并不奇怪,可以使用@implementation来定义。

  @implementation AnObject

  + (id) aClassMethod

  {

  ...

  }

  - (id) anInstanceMethod:(NSString*)aString with:(id)anObject

  {

  ...

  }

  @end

  注意参数类型是特定的,在括号里。这是从C重用映射语法来展示值映射到类型;他们可能不是类型。准确来说当映射时应用相同的规则。这意味着映射在不兼容对象指针类型间会导致一个警告(不是错误)。

  内存管理

  传统的,Objective-C不提供任何内存管理。在早期版本中,对象类实现一个+new方法调用malloc()来创建一个新对象。当使用完这 个对象,传一个-free消息。任何一个对象从NSObject继承回应一个-retain和-release消息。当你使用完这个对象,你传一个 -free消息。OpenStep添加了参考计算。

  每一个从NSObject继承的对象都回应-retain和-release消息。当你想要保留一个指向对象的指针,你可以发送一个-retain消息。当你使用完以后,你可以发送一个-release消息。

  这个设计有个细微问题。通常你不需要保持一个指向对象的指针,但是你也不想释放。一个典型的例子在返回一个对象时候,调用者需要保持指向对象的指针,但你不想这么做。

  这个问题的解决方案就是NSAutoreleasePool类。加上-retain和-release,NSObject也回应 -autorelease消息。当你发送其中一个,和现前的自动释放池一同注册。当这个池对象被注销,它发送一个-release消息给每个对象,而对象 在这之前先收到-autorelease消息。在OpenStep应用中,一个NSAutoreleasePool实例在循环开始的时候创建,在结束的时 候销毁。你也可以创建属于你自己的实例来自动释放对象。

  这个机制减少了一些C++所需的复制。其实也不值得这么做,在Objective-C,易变性是对象的属性,不是参考。在C++,有常量指针和非常量指针。不允许在常量对象上调用非常量方法。这保证不了对象不会被改变——仅仅因为你不想改变。

  在Objective-C中,一个常态模式定义了一个不变的类和可变的子类。NSString就是一个典型例子;

  它有一个可变的子类NSMutableString。如果你得到NSString并且想保存下来,你可以传一个-retain消息并且不用复制操作 就可以保存指针。相反地,你可以传一个+stringWithString:message给NSString。不管这个参数是否可变都会检查并返回原始 指针。

  在Apple和GNU运行时,Objective-C都支持存储性的垃圾回收,这会避免对-retain和-release的需要。在现存的框架中对语言的附加并不总是很好的支持的,并且在用的时候需要格外小心。

  总结

  既然我们已经浏览了Objective-C语言的核心,在这部分的总结我们将会看到更多的一些高级话题。

时间: 2024-11-01 01:06:20

C++快速学习Objective-C语言核心语法的相关文章

15个快速学习苹果Swift编程语言的入门教程

要说今年最火的编程语言是什么.那就非Swift莫属了.当然最主要还是市场炒的比较热,加上官方Swift教程<The Swift Programming Language>在北航的大三学生发起在github上进行协同翻译获得了很高的人气,短短几天时间内<Swift中文版>第一版就发布.这真是不火不行了. Swift是苹果公司在WWDC2014上发布的全新开发语言.从演示视频及随后在appstore上线的标准文档看来,语法内容混合了OC,JS,Python,语法简单,使用方便,并可与O

60分钟Python快速学习(转)

60分钟Python快速学习(给发哥一个交代) 阅读目录 第一步:开发环境搭建: 第一个Python功能:初识Python 02.Python中定义变量不需要数据类型 03.在Pythod中定义方法 04.在Python中书写自己的类 60分钟Python快速学习     之前和同事谈到Python,每次下班后跑步都是在听他说,例如Python属于"胶水语言啦",属于"解释型语言啦!",是"面向对象的语言啦!",另外没有数据类型,逻辑全靠空格缩进

C++开发者快速学习Objective-C语言核“.NET研究”心语法

本文将Objective-C讨论了语言的核心语法.这部分开始详述一些具体的语法.正如你期待的一样,涉及到了定义和类. 类并不是特殊的 在Smalltalk中,类是具有一些特性的对象.在Objective-C中也一样.一个类是一个对象,对象回应消息.Objective-C和C++都分离了对象分配和初始化. 在C++中,对象分配通过新的操作.在Objective-C中,这样的操作是通过给类发送分配消息-调用malloc()或者一个等价. C++中的初始化是通过调用一个与类同名的函数.Objectiv

Lua脚本语言基本语法快速入门教程_Lua

Lua语法与C语言有些相似也不太一样,写了语句学一下 微笑 --begin a = --[[explain]] "ha"; print(a) if a == "ha" then print("if test passed") else print("if used wrong") end b,c=2,3 print(b,c) b,c=c,b if b==3 and c==2 then print("swap test

新手快速学习JavaScript免费教程资源汇总

  这篇文章主要介绍了新手快速学习JavaScript免费教程资源汇总,都是非常不错的学习站点,有需要的小伙伴可以参考下. "JavaScript"的名头相信大家肯定是耳熟能详,但只有一小部分人群了解它的使用与应用程序构建方式.这"一小部分"人指的当然是技术过硬的有为青年.网络程序员以及IT专业人员.但对于一位新手或者说外行人而言,"JavaScript"只不过是复杂计算机编程学科当中的另一个不知所云的术语. 那么,JavaScript到底是什么

阿里巴巴Java开发手册快速学习

Java作为一门名副其实的工业级语言,语法友好,学习简单,大规模的应用给代码质量的管控带来了困难,特别是团队开发中,开发过程中的规范会直接影响最终项目的稳定性. 善医者"未有形而除之",提高工程健壮性最好的方式是在代码出现问题之前就排除掉,不给Bug出现的机会.一份好的开发规范就可以起到这样的作用,大大减少产品上线后的问题.  <阿里巴巴Java开发手册>是阿里巴巴的内部编码规范,阿里官方的Java代码规范标准, 手册以Java应用开发为维度,分为编程规约.异常日志规约.M

Javascript核心读书有感之语言核心_基础知识

读此书之前,感谢淘宝技术团队对此javascript核心的翻译,感谢弗拉纳根写出此书.感谢你们无私的分享,仅以此笔记献给你们的辛勤付出. 一:javascript语言核心 本章之后,我们将主要关注javascript的基础知识.第二章我们讲解javascript的注释,分号和unicode字符集:第三章会更有意思,主要讲解javascript的变量和赋值 这里有一些实例代码说明前两章的重点内容. 复制代码 代码如下: <script type="text/javascript"&

JavaScript核心语法总结(推荐)_基础知识

本文介绍了JavaScript的基本(常用)语法,供大家参考. Overview 先说一下Javascript该怎么写.两种形式,一种是直接把JavaScript写在HTML页面里,另一种是存在*.js文件里然后在页面内引用. 直接写时,即可以放在<head> </head>内,也可以放在<body> </body>内.一般函数是放在<head>区的,具体的执行代码是在<body>区里的.例如,在body里写: <body>

如何快速学习正则表达式_正则表达式

正则表达式概念 正则表达式,又称正规表示法.常规表示法(英语:Regular Expression,在代码中常简写为regex.regexp或RE),计算机科学的一个概念.正则表达式使用单个字符串来描述.匹配一系列符合某个句法规则的字符串.在很多文本编辑器里,正则表达式通常被用来检索.替换那些符合某个模式的文本. 在日常工作中,我们经常写正则表达式,比如在表单中经常用来验证用户输入的格式是否正确,我们就会用到正则表达式;可以把正则表达式看做是可以描述问题的语言,它就是专门为模式匹配而设计的 --