iOS知识点四五六

1.  init()方法是在NSObject类中声明的,而NSObject类是Atom类的父类(超类)。NSObject类的init()方法用于将内存分配给新对象后,立刻初始化该对象。因此,如果要执行自定义的初始化功能(如设置实例变量的值),就应该在实现文件中处理。

-(id)init{
 if(self = [super init]){}

return self;

}

2.  在许多程序设计语言中,获取对象内部状态的方法(通常称为getter/setter方法)必须手动编写。Objective-C提供了简化和自动化该任务的自动声明属性。属性和实例变量的区别是,属性无法直接访问对象的内部状态,但提供了访问这些数据的方便机制(即读取和设置方法),因而可以含有其他逻辑。通过Objective-C的自动声明属性,编译器能够根据你提供的规范自动生成这些方法。这就减少了编写和维护代码的工作量,并能够增加程序的一致性和可靠性。

3.  @property (特性) 属性的类型  属性的名称

    

属性的访问器方法可以在运行时被委托或者动态创建,使用@dynamic属性指令可以阻止编译器通过这种方式自动生成访问器方法。这样,如果无法找到应用了@dynamic属性指令的属性访问器方法的实现代码,编译器就不会发出警告了。但是,开发人员必须通过下列方式创建这些访问器方法实现代码:直接手动编写这些代码,通过其他途径(如动态代码加载或者动态方法决议)获得这些代码,以及能够动态生成这些方法的软件库(如苹果公司的Core Data框架)。

4. 使用协议声明的方法和属性可以由任何类实现。类接口直接与特定的类关联,因此也会直接与类的层次结构关联。相对而言,协议不与特定的类关联,因此使用它可以捕捉无继承关系的类之间的相似之处。协议使Objective-C支持多继承的概念(方法声明)。协议还可以用于定义对象能够发送哪些消息(通过设置遵守协议的属性)。

5. 使用分类可以在不进行子类化的情况下,为已经存在的类增加功能。分类中的方法会成为类的组成部分(在程序中),并且会被其子类继承。这意味着可以向这个类(或它的子类)发送消息,调用在分类中定义的方法。分类通常用于:1. 扩展其他人定义的类(即使你无法访问它们的源代码) 2.代替子类 3.将新类的实现代码分发给多个源文件(通过多人分工,简化了大型类的开发工作)

6. 可以将扩展视为一种匿名(即未命名的分类)。在扩展中声明的方法必须在相应类的主@implementation快中实现(它们无法在分类中实现)。

  扩展与分类的区别是它能够声明实例变量和属性。编译器会检查在扩展中声明的方法(和属性)能否被实现。类扩展通常应该存储在类实现文件中,并用于组织和声明在类中独立使用的其他私有方法(例如,不是公共API的一部分)。

7.  alloc方法为对象分配了内存,并将它的实例变量初始化为0,但是alloc方法既没有将该对象的实例变量初始化为适当的值,也没有为该对象准备其他必须的对象和资源。因此,你编写的类应该实现完成该初始化的过程。NSObject类实现了init方法,该方法为对象的初始化提供了基础,你编写的类至少要包含这个方法的内容,才能提供自定义的初始化行为。

  self = [super init]。通过调用init方法获得的结果被赋给了Objective-C的特殊参数self。所有的方法都拥有一个隐含参数self(它不存在于方法定义中),它是一个指向接收消息对象的指针。实际上,如果成功初始化了父类(即表达式[super init]返回了合法的对象),就说明实现了对对象的自定义初始化;否则,init方法会返回nil。

8. 转发选项

      Objective-C 提供了两种消息转发选项:

        1* 快速转发: NSObject类的子类可以通过重写NSObject类的forwardingTargetForSelector:方法,将该方法转发给其他对象,从而实现快速转发。该技巧就像是将对象的实现代码与转发对象合并到了一起。这类似于实现的多重继承行为。如果你有一个定义了对象能够消化哪些消息的目标类,这个技巧可以取得很好的效果。

       2*标准转发:NSObject类的子类可以通过重写NSObject类的forwardInvocation:方法,实现标准转发。该技巧使对象能够使用消息的全部内容(目标、方法名和参数)。

9.  Objective-C可执行程序是由(可执行)代码、初始化和未初始化的程序数据、链接信息、重定位信息、局部数据和动态数据构成的。程序数据包括以静态方式声明的变量和程序常量(即在程序编译时在代码中设置的常数)。

        可执行代码、程序数据、链接与重定位信息会以静态方式被分配内存,并在程序的生命周期中一直存在。

        局部(自动)数据在语句块中声明并且仅在该语句快中有效,当该语句快执行后局部数据不会继续存在。

       自动数据被存储在程序栈中,程序栈通常是在执行程序/线程前就被设定尺寸的内存段。栈用于存储局部变量和调用方法/函数的上下文数据。这些上下文数据包括方法的输入参数、返回值,以及调用完方法后继续执行程序的代码地址。操作系统会自动管理这些内存;这些数据会获得栈中的内存,而分配给这些数据的内存会在它们失效后被释放。

       在运行时,Objective-C会将创建的对象(通过NSObject类的alloc方法)存储在动态分配的内存即堆内存中。以动态方式创建的对象就意味着需要进行内存管理,因为在堆内存中创建的内向永远不会超出其作用范围。

 10.  自动引用计数(ARC)是一种功能强大的内存管理工具,它可以使这类任务自动化,从而减轻程序员的负担。ARC使用的引用计数模式与MRR使用的相同,但由编译器管理回收对象的工作。具体来说,在编译程序时,编译器会分析源代码,确定以动态方式创建的对象的回收需求,然后在已编译代码的必要位置自动插入retain和release消息。ARC还具有其他优点,如可以(潜在地)提升应用的性能和消除内存管理错误(如错误释放仍旧在使用的对象、保留不再使用的对象)。此外,与垃圾回收机制相比,ARC更可靠(保留和释放语句是在编译时插入的),并且不会为实现垃圾回收机制而在程序执行过程中引入暂停操作。

      注意:ARC无法自动处理循环引用。Objective-C提供了弱引用功能,在必要时通过该功能你可以手动解消循环引用。

   弱引用是一种非所有权引用,被弱引用的对象不属于引用它的对象,从而可以消除循环引用。苹果公司的Objective-C约定为,父对象强引用其所有的子对象,子对象弱引用其父对象(在必要的情况下)。

11. 预处理器

        Objective-C编程语言中含有一个预处理器,用于在编译前处理源文件。其中有些处理操作上自动执行的,另外一些处理操作是根据源文件中包含的预处理器语言元素执行的。

        Objective-C编译器编译源代码的一般流程是:接收源文件,然后将它转换为能够在目标平台上执行的文件。可将该过程分为几个阶段,如下图所示:

    

        如上图所示,这些阶段包括词法分析、语法分析、生成代码与优化、汇编与链接,最终生成可执行的二进制代码。在词法分析阶段,源代码被拆分为多个记号。每个记号 (token)都说一个独立的语言元素,如关键字、操作符、标识符和在其本身语法环境中的符号名。

        语法分析阶段会检查正确的记号,并检查它们所构成的表达式的合法性。这项任务的目的是通过记号创建抽象语法树(AST)或层次分析树。

       在生成代码和优化阶段,AST用于生成输出语言代码,输出语言代码可能是机器语言,也可能是中间语言表示(IR)。优化后,代码的功能不会改变,但是性能更好,体积更小。

      汇编阶段会接收上一处理阶段生成的代码,并将它们转换为在目标平台上可执行的机器代码。

      最后,在链接阶段,汇编程序输出的一段或多段代码会被合并为一个独立的可执行程序。

        预处理器语言是一门不同于Objective-C的独立编程语言。预处理语言对源文件进行的转换主要包括源文件的内容、条件编译和宏展开。预处理器语言会在程序编译之前处理源文件,但预处理器不能识别Objective-C代码。

       预处理器语言定义了预处理器指令和宏展开。预处理器指令是指由预处理器(而不是编译器)执行的命令。宏指令是指具有名称的一段代码。当该名称在源代码使用时,就会被替换为它代表的那段代码。

       Objective-C源文件中的预处理器指令会使用独特的语法,使它们由处理器(而不是编译器)处理。处理器执行具有下列形式:

        #指令名  指令参数   

       预处理器指令以井号(#)开头,后面紧跟指令名,之后是相应的参数,例如 #import "Elements.h" 就是一条预处理器指令。预处理器指令会将换行符用作结束符号。要使预处理器指令扩展为多行,可使用反斜杠(\)连接两行代码,例如

     #define DegressToRadians(x) \

        ((x)*3.14159/180.0)

       是一条使用反斜杠扩展为两行的的预处理器指令。

      下面列出成套的预处理器指令及其作用

      1. 头文件包含(#include、#import)

       2. 条件编译(#if、#elif、#else、#endif 、#ifdef、#ifndef)

      3.诊断(#error、#warning和#line)

      4.#pargma指令

    1. 头文件包含

     #import与#include指令的区别是,它可以确保头文件仅在源文件中包含一次,因而能够防止递归包含。

    在没有使用import指令的情况中,必须在头文件中包含警卫,以防止出现递归包含。包含警卫就是一系列用于防止重复包含头文件的预处理器语句。它们通常由含有#ifndef指令的条件编译表达式和#define指令构成。

    3. 诊断

       在编译程序的过程中,可使用多条预处理器指令诊断问题。

      使用#error指令可以使预处理器生成一条错误信息并终止编译过程。

       #error "错误信息"

       应使用双引号封装错误信息。这条指令通常用于处理条件编译错误,例如,如果程序还未定义宏INPUT_ARGS,代码段

       #ifndef INPUT_ARGS

       #error "No input arguments provided"

      #endif

    会使编译过程中止并生成一条错误信息(No input arguments provided)。

    使用#warning指令可以生成编译警告信息,但允许编译器继续进行编译。

    #warning "警告信息"

     使用#line指令可以在编译器消息中添加行号。当编译器出错误时,编译器会显示含有出错文件名称和相应行号的错误信息,从而使定位错误代码变得容易。下面是#line指令的语法:

    #line 行号 ''文件名"

   该行号被赋予下一行代码。而后续的代码行都会拥有每行+1的行号。封装在双引号中的文件名是可选项,使用它可以重新定义在编译器消息中显示的文件名。下面的#line指令的例子:

   #line to "Elements.m"

    这段代码会生成一条错误信息,表明文件Elements.m的第11行代码中有错误。

   4. #pragma指令

      使用pragma指令可以设置超出Objective-C语言范畴的、额外的编译器选项。这些选项专门用于特定的平台和编译器。下面是#pragma指令的语法:

       #pragma pragma选项

     pragma选项是对应于特定编译器指令(即参数,如果存在)的一系列字符,这些字符可以实现预定义操作。如果编译器不支持#pragma指令中的特定参数,它就会忽略该指令,而不生成错误消息。

    Xcode支持多条#pragma mark指令。

    使用下面的指令可以在跳转栏弹出窗口创建分隔线:

    #pragma mark-

    使用下面的指令可以创建用于区分方法类别的标签:  

    #pragma mark 标签名称

   标签名称会在弹出窗口中显示为方法的标签。

5. 宏是有名称的代码段。可以使用#define定义宏,使用 #undef指令移除宏。

   #define SQUARE(x) ((x)*(x))

   在被替换进宏体之前,所有的参数都会进行彻底的宏展开。进行参数替换后,为了进行宏展开,预处理器会再次扫描全部内容,包括参数。预处理器无法识别Objective-C语句,它仅仅是将宏名替换为相应的值和代码。还应注意,宏不会受到Objective-C作用范围规则的影响。被定义之后,宏会一直存在并能够在整个文件中起作用,直到被#undef指令解除定义为止。

   应使用花括号封装用于执行计算而非返回值的多行函数型宏。例如:#define SWAP(a,b){a ^=b;b^=a;a^=b }

  函数型宏定义在替换字符串时接受两种特殊操作符:#和##。使用字符串化操作符(#)可以将宏的输入参数替换为相应的字符串(由双引号封装)。使用连接操作符(##)可以将两个记号(token)连接起来,使他们之间不含空格。

   警告:不要过度使用宏。因为以不正确的方式使用宏会导致嵌套错误、运算优先规则和重复性副作用等问题。此外,对复杂宏依赖程度较大的代码会使维护变得困难,因为宏使用的语法通常不同于Objective-C的语法。

12. ARC禁止以手动的方式向对象发送release、autorelease、dealloc或其他相关的消息。当你编写的代码执行以下操作时,会释放对象的所有权: 1)重新分配变量; 2)将nil赋予变量;3)释放对象的所有者。

 将ARC与苹果公司提供的框架和服务一同使用

   苹果公司提供了非常多的软件库(框架和服务),它们可以为OS X和iOS平台上运行的软件提供接口。如下图所示,给出了应用开发中最常用的一些软件库。

       这些软件库中中有些软件库的应用程序编程接口(API)是使用Objective-C编写的,因而能够在你的Objective-C中直接使用,而大多数软件库的API是使用ANSIC编写的,因而也可以在你的Objective-C程序中直接使用。

       ARC能够自动管理Objective-C对象和块对象的内存。苹果公司提供的基于C语言的API软件库没有与ARC整合。因此,当通过动态方式为这些基于C语言的API分配内存时,你必须手动管理内存。实际上,ARC不允许Objective-C对象的指针和其他数据类型的指针(苹果公司提供的基于C语言的API中的)之间进行直接转换。为了方便开发人员在Objective-C程序中使用基于C语言的API,苹果公司提供了多种机制,如直接桥接和ARC桥接转换。

与我之前写的博客里的关于这部分的描述相比较看一下:

再来看看xcode里的这部分的方法的标记

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值