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

简介:   本文将Objective-C讨论了语言的核心语法。这部分开始详述一些具体的语法。正如你期待的一样,涉及到了定义和类。  类并不是特殊的  在Smalltalk中,类是具有一些特性的对象。在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中,你可以做的如下:

 
 
1 . [ object perfomSelector:@selector(doSomething)];

这等价于如下:

 
 
1 . [ object doSomething];

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

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

 
 
1 . id object = @”a string ”;
2上海闵行企业网站制作/span>.
3. NSString *string = @”a string”;

  常量字符串实际上是NSConstantString类的一个实例,NSConstantString类是NSSt上海企业网站设计与制作ring的子类。将它引用到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中的接口仅定义位并且明确的需要公开。对于实现的原因,这包括私有实例变量在大部分的实现中,因为你无法继承一个类除非你知道它多大。最近的一些实现,象Apple的64位运行时则没有这种限制。

  Objective-C对象的接口如下:

 
 
1 . @interface AnObject : NSObject
2 .
3 . {
4 .
5 . @private
6 .
7 . int integerivar
上海闵行企业网站设计与制作>8 .
9 . @public
10 .
11 . id anotherObject;
12 .
13 . }
14 .
15 . + (id) aClassMethod;
16 .
17 . - (id) anInstanceMethod:(NSString * )aString with:(id)anObject
18 .
19 . @end

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

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

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

 
 
1 . struct_AnObject
2 .
3 . {
4 .
5 . @defs(AnObject);
6 .
7 . };

  @def表示着对特定对象所有域都插入这种结构,所以struct_AnObject 和AnObject类的实例有着相同的内存结构。举个例子来说,你可以通过这种规则可以直接存取实例变量。一个通常的用法就是允许C函数直接操作Objective-C对象,是基于性能原因。
  正如我前面暗示的,与这个特性相关的另一件事就是可以在堆栈上创建对象。因为结构和对象在[FS:PAGE]内存布局中有着相同的结构,你可以简单的创建结构,设置他的指针指向正确的类,然后映射一个指针指向一个对象指针。然后你可以当做对象来使用,虽然你不得不小心没有什么可以保持指针不越界。(现实世界中我从没有使用这种方法,仅仅理论上可能。)

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

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

 
 
1 . @implementation AnObject
2 .
3 . + (id) aClassMethod
4 .
5 . {
6 .
7 . ...
8 .
9 . }
10 .
11 . - (id) anInstanceMethod:(NSString * )aString with:(id)anObject
12上海徐汇企业网站设计与制作an style="color: #000000;">.
13 . {
14 .
15 . ...
16 .
17 . }
18 .
19 . @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语言的核心,在这部分的总结我们将会看到更多的一些高级话题。

目录
相关文章
|
4月前
|
SQL 开发框架 数据库
".NET开发者的超能力:AgileEAS.NET ORM带你穿越数据库的迷宫,让数据操作变得轻松又神奇!"
【8月更文挑战第16天】AgileEAS.NET是面向.NET平台的企业应用开发框架,核心功能包括数据关系映射(ORM),允许以面向对象方式操作数据库,无需编写复杂SQL。通过继承`AgileEAS.Data.Entity`创建实体类对应数据库表,利用ORM简化数据访问层编码。支持基本的CRUD操作及复杂查询如条件筛选、排序和分页,并可通过导航属性实现多表关联。此外,提供了事务管理功能确保数据一致性。AgileEAS.NET的ORM简化了数据库操作,提升了开发效率和代码可维护性。
56 5
|
1月前
|
自然语言处理 物联网 图形学
.NET 技术凭借其独特的优势和特性,为开发者们提供了一种高效、可靠且富有创造力的开发体验
本文深入探讨了.NET技术的独特优势及其在多个领域的应用,包括企业级应用、Web应用、桌面应用、移动应用和游戏开发。通过强大的工具集、高效的代码管理、跨平台支持及稳定的性能,.NET为开发者提供了高效、可靠的开发体验,并面对技术更新和竞争压力,不断创新发展。
49 7
|
1月前
|
IDE 测试技术 开发工具
.NET开发者福音:JetBrains官方宣布 Rider 非商用免费开放!
.NET开发者福音:JetBrains官方宣布 Rider 非商用免费开放!
|
4月前
|
机器学习/深度学习 人工智能 算法
【悬念揭秘】ML.NET:那片未被探索的机器学习宝藏,如何让普通开发者一夜变身AI高手?——从零开始,揭秘构建智能应用的神秘旅程!
【8月更文挑战第28天】ML.NET 是微软推出的一款开源机器学习框架,专为希望在本地应用中嵌入智能功能的 .NET 开发者设计。无需深厚的数据科学背景,即可实现预测分析、推荐系统和图像识别等功能。它支持多种数据源,提供丰富的预处理工具和多样化的机器学习算法,简化了数据处理和模型训练流程。
70 1
|
4月前
|
数据库 C# 开发者
WPF开发者必读:揭秘ADO.NET与Entity Framework数据库交互秘籍,轻松实现企业级应用!
【8月更文挑战第31天】在现代软件开发中,WPF 与数据库的交互对于构建企业级应用至关重要。本文介绍了如何利用 ADO.NET 和 Entity Framework 在 WPF 应用中访问和操作数据库。ADO.NET 是 .NET Framework 中用于访问各类数据库(如 SQL Server、MySQL 等)的类库;Entity Framework 则是一种 ORM 框架,支持面向对象的数据操作。文章通过示例展示了如何在 WPF 应用中集成这两种技术,提高开发效率。
69 0
|
4月前
|
开发者
在.NET 中进行并发编程,究竟隐藏着哪些让开发者头疼不已的挑战?又该如何破解?
【8月更文挑战第28天】在现代软件开发中,并发编程的重要性日益凸显,但.NET开发者们却常常遇到资源竞争与死锁等挑战。例如,多线程对共享资源的访问可能导致数据不一致。以上提供了一个因缺乏同步机制而导致计数器结果出错的例子,并通过使用锁解决了该问题。此外,还介绍了一个产生死锁的代码片段,展示两个线程因互相等待对方持有的锁而陷入僵局。通过对这些挑战的理解和应对,可以提高软件的稳定性和效率。
31 0
|
4月前
|
开发框架 监控 .NET
开发者的革新利器:ASP.NET Core实战指南,构建未来Web应用的高效之道
【8月更文挑战第28天】本文探讨了如何利用ASP.NET Core构建高效、可扩展的Web应用。ASP.NET Core是一个开源、跨平台的框架,具有依赖注入、配置管理等特性。文章详细介绍了项目结构规划、依赖注入配置、中间件使用及性能优化方法,并讨论了安全性、可扩展性以及容器化的重要性。通过这些技术要点,开发者能够快速构建出符合现代Web应用需求的应用程序。
70 0
|
4月前
|
C# Android开发 开发者
当跨平台开发成为热点,.NET MAUI 如何触动开发者的心弦,引领未来?
【8月更文挑战第28天】在数字化浪潮中,跨平台应用开发需求激增,.NET MAUI 如新星般闪耀,为开发者指明了方向。它提供统一的 C# 和 XAML 开发体验,支持 Android、iOS、Windows 多平台应用构建,大幅提高效率,降低成本。使用 .NET MAUI,一个团队即可打造多平台流畅应用,简化工作流程。其简洁代码示例展示了强大功能与易用性,同时在性能优化方面表现出色,确保各平台上的流畅体验。加之活跃社区支持,.NET MAUI 必将推动跨平台开发迈向新高峰。
60 0
|
6月前
|
网络协议 Java 程序员
TCP/IP协议栈是网络通信基础,Java的`java.net`包提供工具,使开发者能利用TCP/IP创建网络应用
【6月更文挑战第23天】 **TCP/IP协议栈是网络通信基础,它包含应用层(HTTP, FTP等)、传输层(TCP, UDP)、网络层(IP)、数据链路层(帧, MAC地址)和物理层(硬件信号)。Java的`java.net`包提供工具,使开发者能利用TCP/IP创建网络应用,如Socket和ServerSocket用于客户端和服务器通信。**
57 3