objective c和c++语言,objective-c和c语言
本文讨论了Objective-C语言的核心语法,这部分开始阐述一些具体的语法。如您所料,其中涉及到定义和类。
阶级不特殊。
在Smalltalk中,类是具有某些特征的对象。Objective-C也是如此,类是对象,对象响应消息。Objective-C和C都将对象分配和初始化分开。
在C #中,对象是通过new操作来分配的。在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消息时,它会返回一个初始化的对象。这可能是你发信息的对象,但不一定是那个。这与其他初始化过程一致。有可能public类的一些特殊子类在不同的数据上更有效。
实现这个特性的一般方法叫做isa-swizzling。正如我前面提到的,Objective-C对象是C结构,这些结构的第一个元素是指向一个类的指针。这个元素是可访问的,就像其他实例变量一样;您可以通过在运行时分配新值来更改对象的类。当然,如果你对内存中对象的类设置有不同的布局,这些设置可能会严重错误。
但是,您可以通过父类定义布局,通过子集集定义行为。例如,这种技术用于标准化的字符串类(NSString ),它有各种不同的文本字符集、静态内容和其他内容的实例。
因为类是对象,所以您可以像操作对象一样操作它们。例如,您可以将它们放在一个集合中。当我有一些输入事件需要通过类的不同实例来处理时,我使用这种格式。您需要创建一个名为类的目录映射事件,然后为每个输入事件实例化一个对象。如果您在库中这样做,它允许代码用户轻松地注册他们自己的句柄。
和类型指针。
Objective-C不公开允许在堆栈上定义对象。但这不是真的——在堆栈上定义对象是可能的,但这有点困难,因为它破坏了一个关于内存管理的假设。因此,每个Objective-C对象都是一个指针。有些类型是由Objective-C定义的;这些类型在头文件中被定义为C类型。
Objective-C中最常见的三种类型是id、Class和SEL。Id是Objective-C对象的指针,相当于C语言中的void*。您可以映射任何对象指针类型以指向它,并将其映射到其他对象指针类型。
您可以向id发送任何消息,但是如果不支持,它将返回运行时异常。
类是指向Objective-C类的指针。是一个类对象,所以也可以接收消息。类名是一种类型,不可变。标识符NSObject是NSObject实例的一种类型,但它也可以用作消息接收者。您可以按如下方式获得一个类:
[NSObject类];
向NSObject类发送一个类消息,然后返回一个指向表示该类的类结构的指针。这对于我们的回顾非常有用[FS:PAGE],正如我们在本系列的第二部分中看到的。
第三种类型,SEL,代表一个选择器——代表一个方法名的抽象。可以在编译时通过@selector()直接创建,也可以在运行时通过C string调用运行时库函数,或者使用OpenStep NSSelectorFromString()函数,该函数为Objective-C字符串赋予了一个选择器。这种技术允许您通过名称调用方法。您可以在C中使用类似的dlsym(),但它在C中有很大的不同。在Objective-C中,您可以执行以下操作:
1.[对象性能选择器:@选择器(do something)];
这相当于以下内容:
1.[对象做某事];
显然,第二种格式稍微快一些,因为第一种格式传输两种消息。稍后,我们将通过选择器看到处理的一些细节。
c与id没有相同的类型。因为对象总是可以被类型化的。在Objective-C中,您可以选择类型系统。以下两种情况都有效:
1.id object=@ "一个字符串";
2.
3.NSString *string=@ "一个字符串";
常数实际上是NSConstantString类的实例,NSConstantString类是NSString的子类。它引用NSString*在编译时检查消息类型并存储公共实例变量(这在Objective-C中从未使用过)。请注意,您可以通过以下方式更改此设置:
1.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中的接口只定义了位,并且需要显式地公开。出于实现的原因,这在大多数实现中包括私有实例变量,因为除非你知道一个类有多大,否则你不能继承它。最近的一些实现,如苹果的64位运行时,没有这种限制。
Objective-C对象的接口如下:
1.@interface AnObject : NSObject
2.
3.{
4.
5.@私人
6.
7.国际间
8.
9.@public
10.
11.id另一个对象;
12.
13.}
14.
15.(id)aClassMethod;
16.
17.-(id)an instance method:(ns string *)string with:(id)a object
18.
19.@end
第一行包含三个部分。对象的标识符是新类的名称。冒号后的名称是NSObject。(这是可选的,但是每个Objective-C对象都应该扩展NSObject)。括号里的名字是协议——类似于Java里的接口,——是通过类实现的。
正如C实例变量(C中的域)可以访问修饰符,与C不同,这些修饰符以@为前缀,以避免与C标识符冲突。
Objective-C不支持多重继承,所以只有一个父类。因此,对象第一部分的布局总是与父类实例的布局一致。这曾经被定义为动态的,意味着改变一个类中的实例变量需要重新编译它的所有子类。在较新的运行时中不需要这种限制,并且访问实例变量的开销稍大。这个决定的另一个影响是Objective-C的其他特性之一。
1.结构对象
2.
3.{
4.
5.@ defs(an object);
6.
7.};
@def表示这个结构被插入到一个特定对象的所有字段中,所以struct_AnObject和AnObject类的实例具有相同的内存结构。例如,您可以通过此规则直接访问实例变量。一种常见的用法是允许C函数直接操作Objective-C对象,这是基于性能原因。
正如我前面暗示的,与这个特性相关的另一件事是对象可以在堆栈上创建。因为结构和对象在[FS:PAGE]内存布局中具有相同的结构,所以您可以简单地创建一个结构,将其指针设置为正确的类,然后将指针映射到对象指针。然后你就可以把它当作一个对象来使用,尽管你必须小心不要让指针越界。我从未在现实世界中使用过这种方法。这只是理论上的可能。)
与C不同,Objective-C没有私有或受保护的方法。Objective-C对象上的任何方法都可以被其他对象调用。如果你不在接口中声明一个方法,它就是非正式的和私有的。您将得到一个运行时警告:对象没有响应这个消息,但是您仍然可以调用它。
它非常类似于接口c中的头声明。但它仍然需要一个实现,这并不奇怪。您可以使用@implementation来定义它。
1.@实现对象
2.
3.(id) aClassMethod
4.
5.{
6.
7.
8.
9.}
10.
11.-(id)an instance method:(ns string *)string with:(id)a object
12.
13.{
14.
15.
16.
17.}
18.
19.@end
请注意,参数类型是特定的,并且在括号中。这是为了重用C中的映射语法,以显示值被映射到类型;他们可能不是这种类型。准确地说,映射时也适用同样的规则。这意味着映射将在不兼容的对象指针类型之间导致警告(而不是错误)。
内存管理
传统上,Objective-C不提供任何内存管理。在早期版本中,object类实现了一个新的方法调用malloc()来创建一个新对象。当你使用完这个对象后,发送一条免费消息。任何对象都从NSObject继承并响应-retain和-release消息。当你使用完这个对象时,你发送了一个免费的消息。打开添加参考计算。
从NSObject继承的每个对象都响应-retain和-release消息。当你想保留一个指向对象的指针时,你可以发送一个-retain消息。当您使用完它时,您可以发送一条发布消息。
这个设计有点小问题。通常你不需要保持一个指向对象的指针,但是你也不想释放它。一个典型的例子是,当返回一个对象时,调用者需要保持指向该对象的指针,但你不想这样做。
这个问题的解决方案是NSAutoreleasePool类。通过添加-retain和-release,NSObject还可以响应-autorelease消息。当您发送其中一个时,将它注册到现有的自动发布池。注销该池对象时,它会向每个对象发送一条-release消息,该对象会在此之前收到一条-autorelease消息。在OpenStep应用程序中,NSAutoreleasePool实例在循环开始时创建,在循环结束时销毁。您也可以创建自己的实例来自动释放对象。
这个机制减少了c需要的一些副本,其实不值得这么做。在Objective-C中,挥发性是对象的属性,而不是引用。在c语言中,有常量指针和非常量指针。不允许在常量对象上调用非常量方法。这不能保证对象不会被改变。——只是因为你不想改变。
在Objective-C中,正常模式定义了一个不变类和一个可变子类。NSString就是一个典型的例子;它有一个变量子类NSMutableString。如果你得到了NSString并想保存它,你可以发送一个-retain消息,保存指针而不用复制。相反,可以向NSString发送stringWithString:消息。不管这个参数是否可变,都将检查并返回原始指针。
当Apple和GNU运行时,Objective-C支持存储垃圾收集,这将避免需要-retain和-release。现有框架中的语言附件并不总是得到很好的支持,在使用时应该格外小心。
现在我们已经浏览了Objective-C语言的核心,我们将在这一部分的总结中看到更高级的主题。
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。