《Effective Objective-C 2.0》—(第1-5条)—熟悉Objective-C

Objective-C通过一套全新的语法,在C语言基础上添加了面向对象特性。OC的语法中频繁使用中括号([  ]),而且不吝于写出极长的方法名,这通常令许多人觉得此语言较为冗长。这是这样写出来的代码非常易读,只是C++和Java程序员不太适应。

OC语言学起来很快,但有很多微妙细节需要注意,而且还有许多容易为人所忽略的特性。另一方面,有些开发者并未完全理解或是容易滥用某些特性,导致写出来的代码难以维护,难以调试。本章讲解基础知识,后续各章语言及其相关架构的各个特定话题。

第1条:了解OC语言的起源

OC与C++,Java等面向对象语言类似,不过很多方面有差别。若是用过另一种面向对象语言,那么就能理解OC所用的许多范式与模板了。然而语法上也许会显得陌生,因为OC使用消息结构(messaging structure)而非函数调用(function calling)。OC由SmallTalk演化而来,后者是消息型语言的鼻祖。消息与函数调用之间的区别看上去就像这样:

//Messaging (OC)
Object *obj = [Object new];
[obj perfromWith:parameter1 and:parameter2];

//Function calling(C++)
Object *obj = new object;
obj->perform(parameter1,parameter2);

关键区别在于:使用消息结构的语言,其运行时所应执行的代码由运行环境决定;而使用函数调用的语言,由编译器决定。如果范例代码中调用函数是多态的,那么在运行时就要按照“虚函数表”(virtual table)来查找到底应该执行哪个函数。而采用消息结构的语言,不论是否多态,总是在运行时才会去查找所要执行的方法。实际上,编译器甚至不关心接受消息的对象是何种类型。接受消息的对象问题也要在运行时处理,其过程叫做“动态绑定”(dynamic
binding)见第11条

OC的重要工作都由“运行期组件”(runtime component)而非编译器来完成。使用OC的面向对象特性所需的全部数据结构及函数都在运行期组件里面。举例来说,运行期组件中含有全部内存管理方法。运行期组件本质上就是一种与开发者所编代码相链接的“动态库”(dynamic library),其代码能把开发者编写的所有程序战粘和起来。这样,只需更新运行期组件,即可提升应用程序性能。

OC是C的超集,所以C语言中的所有功能在编写OC代码时依然适用。

OC只能在堆上声明变量,不能在栈上声明(CGRect可以声明在栈上,因为CGRect是C结构体),OC将堆内存管理抽象出来了。不需要malloc及free来分配或释放对象所占内存。OC运行期环境把这部分工作抽象为一套内存管理架构,名叫“引用计数”,见第29条

第2条:在类的头文件中尽量少引入其他头文件

与C和C++一样,OC使用头文件与“实现文件”来区隔代码。用OC语言编写任何类几乎都要引入Foundation.h。

尽量在头文件中使用类声明,防止循环头文件引用,过多的引用头文件也会增加编译时间。

第3条:多用字面量语法,少用与之等价的方法

举例:

NSNumber *someNumber = @1;
NSNumber *intNumber = @1;
NSNumber *floatNumber = @2.5f;
NSArray * animals = @[@"cat",@"dog",@"mouse",@"badger"];
NSString *dog = animals[1];
//----------------------
id object1 = /*......*/;
id object2 = /*......*/;
id object3 = /*......*/;
NSArray* arrayA = [NSArray ArrayWithObjects:object1,object2,object3,nil];
NSArray* arrayB = @[object1,object2,object3];
//如果object2 = nil那么arrayB抛出异常,array中只有object1和object2。
//----------------------
NSDictionary *personData = @{@"firstName":@"Matt",@"lastName":@"Galloway",@"age":@28};

第4条:多用类型常量,少用#define预处理指令

编写代码经常需要定义常量。例如:

#define ANIMATION_DURATION 0.3

#define会编译期简单替换文本,会造成很多不必要的麻烦。要像解决此问题,应该设法利用编译器的某些特性才行。比如:

static const NSTimeInterval kAnimationDuration = 0.3;

这种方式定义常量包含了类型信息,且最好将这个声明放到.m文件中。static const的声明不应该出现在头文件里。因为OC没有命名空间,所以那样就等于声明了一个全局变量。static修饰表示该变量仅定义在此.m文件中(一个编译单元),如果不加static,则编译器会为他创建一个“外部符号”(external symbol)。此时若另外一个.m文件也有了同名变量,就会造成符号重复(duplicate symbol)。

实际上,如果一个变量既声明为static,又声明为const,那么编译器根本不会创建符号,而是会像#define一样预处理指令一样,把所有遇到的变量都替换为常量。

有时候需要对外公开某个常量,例如:

//in the header file
extern NSString *const EOCStringConstant;
//in the implement file
NSString* const EOCStringConstant = @"VALUE";

EOCStringConstant是一个常量指针,编译器会看到头文件中的extern关键字,这个关键字是要告诉编译器,在全局符号表中将会有有一个名叫EOCStringConstant的符号。当链接成二进制文件之后,肯定能找到这个常量。因为符号要放在全局符号表里,所以命名常量时需谨慎。

本节要点:

● 不要用预处理指令定义常量。即使有人重新定义了常量值,编译器页不会产生警告信息,这将导致程序中常量不一致。

● 在实现文件中使用static const来定义“只在编译单元内可见的常量”(translation-unitspecific constant)。此类常量不在全局符号表中。

● 在头文件中使用extern来声明全局常量,并在实现文件中定义其值。

第5条:用枚举表示状态、选项、状态码

直接举例

typedef NS_ENUM(NSUInteger,EOCConnectionState){
    EOCConectionStateDisconnected,
    EOCConectionStateConnecting,
    EOCConectionStateConnected,
};

● 用NS_ENUM与NS_OPTIONS宏来定义枚举类型,并指明底层数据类型。这样做可以确保枚举是开发者所选的底层数据类型实现出来的,而不会采用编译器所选的类型。

其余章节点击这里

《Effective Objective-C 2.0》—(第1-5条)—熟悉Objective-C

时间: 2024-11-12 19:29:01

《Effective Objective-C 2.0》—(第1-5条)—熟悉Objective-C的相关文章

sudo: effective uid is not 0, is sudo installed setuid root

当普通用户需要临时使用root权限的时候需要执行sudo命令,但是在执行sudo命令的时候需要使用root的权限去执行/usr/bin/sudo二进制文件. 如果报错出现sudo: effective uid is not 0, is sudo installed setuid root 证明/usr/bin/sudo文件没有设置s权限(用户在执行文件的时候,临时拥有文件所有者的权限.) 解决方法: chmod u+s /usr/bin/sudo 加上权限之后再查看文件 ll  /usr/bin

iOS开发——技术精华Swift篇&Swift 2.0和Objective-C2.0混编之第三方框架的使用

Swift 2.0和Objective-C2.0混编之第三方框架的使用 swift 语言是苹果公司在2014年的WWDC大会上发布的全新的编程语言.Swift语言继承了C语言以及Objective-C的特性,且克服了C语言的兼容性问题.Swift语言采用安全编程模式,且引入了多种新功能,使得编程工作更加简便,灵活! 2015年6月9日苹果又一次给所有开发之者带来了一个惊喜,那就是今年年底swift讲开源,者队iOS开发着来说无疑是一个值得兴奋的消息,可是就在这短短的几个月里面swift吸引了越来

问题:sudo su: results -effective uid is not 0 is sudo installed setuid root

前段时间,新装的Centos运行sudo命令时出现的问题: sudo su: results -effective uid is not 0 is sudo installed setuid root 这是我在国外论坛上找到的解决办法 This another common problem for the new users for Linux. Anonymous change of permission of root or while experimenting we do run com

《Effective Objective-C 2.0》—(第6-10条)—对象、属性、equalToString、关联对象

用OC等面向对象语言编程时,"对象"(object)就是"基本构造单元"(building block),开发者可以通过对象来存储并传递数据.在对象之间传递数据并执行任务的过程就叫做"消息传递"(Messaing). 当应用程序运行起来以后,为其提供相关支持的代码叫做"Objective-C运行期环境"(Objevtive-C runtime),它提供了一些使得对象之间能够传递消息的重要函数,并且包含创建类实例所用的全部逻辑.

《Effective Objective-C 2.0》—(第11-14条)—运行时动态绑定、objc_msgSend、消息转发机制

第11条:理解objc_msgSend的作用 在对象上调用方法是OC中经常使用的功能.用OC术语来说这叫做:"传递消息"(pass a message).消息有"名称"(name)或者"选择子"(selector),可以接收参数,而且可能还有返回值. 由于OC是C的超集,所以最好理解C语言的函数调用方式.C语言使用"静态绑定",就是说在编译期就能决定运行时所应调用的函数.以下列代码为例: #import <stdio.h

《Effective Objective-C 2.0》—(第15-22条)—接口与API设计、深拷贝、浅拷贝

第15条:用前缀避免命名空间冲突 Objective-C没有其他语言内置的命名空间(namespace)机制.如果发生命名冲突程序连接时候,出现以下错误: duplicate symbol _OBJC_METACLASS_$_EOCTheClass in: build/something.o build/something_else.o duplicate symbol _OBJC_CLASS_$_EOCTheClass in: build/something.o build/something

《Effective Objective-C 2.0》—(第23-28条)—类别、协议,代理,匿名对象、delegate

第23条:通过委托与数据源协议进行对象间通信 对象之间经常需要相互通信,而通信方式有很多.OC开发者广泛使用一种名叫"委托模式"(Delegate Pattern)的编程设计模式来实现对象间的通信,该模式的主旨是:定义一套接口,某对象若想接收另一个对象的委托,则需遵从此接口,以便称为"委托对象"(delegate).而这"另一个对象"则可以给其委托对象回传一些信息,也可以在发生相关联时间时通知委托对象. 此模式可以将数据与业务逻辑解耦. 在Obj

android.support.design.widget.AppBarLayout 在android5.0+底部显示空白条问题

在最外层使用 RelativeLayout作为根节点,同时设置 android:fitsSystemWindows="true"问题解决. <?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://

实现0.5px的一条线

.box{ position: relative; } .box::after{ content: ''; position: absolute; width: 200%; height: 1px; bottom: 0; border-bottom: 1px solid red; transform-origin: 0 0; transform: scale(.5,.5); box-sizing: border-box } 注意:C3有兼容性问题,使用时需要加私有前缀