2017 November 10 —— improvement

object-c 语法速看

OC:

核心:

变量与类型 字符串 函数 控制流

类 指针 继承 协议


编译型语言,声明-> 编译器的识别以及空间分配

1.oc 属于 c 的严格超集,在 C语言基础上加入 oo 特性

  1. 几种文件: .h .m .mm 文件类型
    .h interface 定义通常位于头文件
  2. 头文件的包含: include 与 import -> import 保证相同文件只会被包含一次,oc 推荐使用
  • 消息机制:

对象的传递

[car method :arg]

含义:发送 Method 消息给 car 对象接受,由 car 对象决定如果回应,若 car 对象没有定义 Method 则运行时抛出异常,但编译可通过 - 天生的动态绑定机制

No visible @interface for ‘NSDate’ declares the selector ‘timeIntervalSince1970foo’

No known class method for selector ‘timeIntervalSince1970’

消息的嵌套机制, 从内由外执行,可以减少代码行数,但会增加问题排错的复杂度;

alloc init 嵌套特殊实例:

alloc 获取对象的地址,进而通过 init 初始化对象;(init有点像构造函数,正如 java 对象创建,先在堆中开辟内存区间,进而构造对象,进一步执行构造函数完成对象初始化)

  • 字符串:

NS(NEXTSTEP 缩写)

  • NSString 字符串封装:

NSString 常量 = @”” 其他 NSString 操作

动态构建 NSString : [NSString stringWithFormat : @”format is %@.”,nsInfoObj]

常用方法: 获取长度 length   字符串比较 isEqualToString   其他参考Doc
  • %@ 与 description:

调用 NSLog 时,如果使用格式说明符号 %@,在处理时,程序将向指针变量所指向的对象发送 description 消息,改消息返回类实例的描述字符串;(类似 java 中的 toString()函数);默认情况下一字符串形式返回对象在内存中的地址;

-(NSString *)description
{
    return @"";
}
  • NSArray 数组 NSArray 无法动态添加或删除数组中的指针;且其指针有序排列,并可以通过索引来获取对应对象引用;

  • NSMutableArray 动态数组 可以动态增删元素; 构建方式:

类声明:

interface 定义声明
以 @interface 开始,以 @end 结束

implementation 实现

  • 函数:

NSLog(@”info: %@”, str)

[obj method] -> obj.method()

[obj method: arg] -> obj.method(arg)

特别注意多参数调用:

selectColor: (int) red Green: (int) green Blue: (int)blue{}

  • 类函数:

以 + 开头表示:

@interface MyClass +(void) saySomething; @end

@implementation MyClass +(void) saySomething{} @end

[MyClass saySomething];

而与之相对的普通函数则通常用 - 符号标注,在调用时则需要对于类对象传递调用消息

  • Selector 方法指针:

  • 指针

* value-at-address operator

\& address-of operator 取地址操作符

OC语言的函数参数传递机制是副本传递,也就是复制出实参的副本,然后往形参里面传递

注意数组的指针:

数组名就是数组元素的地址,数组是连续内存空间,arr 实际等同于 &arr[0] ;

  • 继承与协议:

  • 继承声明:

@interface MyClass : NSObject @end

  • 协议(Java interface)

@protocol Say (void) saySomething:(NSString) info; @optional (void) sayNothing:(NSString) info; @end

optional 可选函数

注: OC 中的函数 通常 没有 private 以及 public 之分

继承导入头文件时,导入子类头文件,则父类头文件被间接导入,无需重复 import;

继承中允许子类覆盖父类函数,在覆盖时只能改变方法实现,而不能改变其声明方式,即方法名,返回类型,以及实参类型都必须保持完全相同;

在向子类实例对象发送消息时,对象会层层寻找,沿着继承链向上,知道找到对应的函数,或者达到继承链的顶端;

super 关键字表示从父类开始搜寻,跳过对象 self 本身;

  • Category

为已存在的类添加方法,而不改动源码,看起来类似继承,但更加灵活,动态

  • 地址与指针

&i 数据内存地址

%p String 格式化时获取内存地址格式说明符

函数名就代表着函数的内存地址

printf(“%p”,main);

对于指针的使用需要注意: 地址以及内容,如果不能多重指针时,那就画出来,有助于理解;

指针定义时的注意点:

通常 * 符号应该紧跟变量名,而不应该紧跟声明的基本类型,如:

float* a,b,c; 只有 a 是指向 float 的地址值,而 b 以及 c 则是普通的 float 类型变量,容易引起误会;

  • 引用传递

变量引用传递, 操作地址;直接对于地址值存储内容进行操作可以直接改变地址值中储存内容,进而可以导致外部变量所指向地址中的内容变化; (稍不注意引起的问题很难发现)

对象只能通过指针来访问,对象的指针保存对象在堆空间中的内存地址,我们说 obj 是一个 Object 对象,事实上应该说”obj 是一个指针变量,保存了 Object 实例在内存中的地址”,而在 Java 中我们实际上是做出了语法上的精简,省略了指针符号;

  • 结构体:

typedef struct : typedef定义时在使用时无需使用 struct 关键字,简化

  • malloc堆:

  • self self 指针,指向运行当前方法的对象地址,某个对象方法向自己发送消息时则可以使用该关键字;

注意 self 与点语法陷阱: 需要注意的是点语法本质是方法调用,如果 set 函数中调用了 self 的 setter, 则造成无限递归:

-(void) setName:(NSString *)info{
    self.name = info; == self setName:info ;
}
  • 文件的编译链接

多库文件编译, Xcode在构建时会将每个.m 以及. h 文件编译成机器码,进而让其与库相连接,共同构建成可执行文件;

  • 类前缀 让类名独一无二,防止与其他类名冲突,如果有同名类名,将导致编译器无法区分类,进而出现编译错误;

  • 属性

@property 利用属性简化实例变量与 getter 以及 setter;编译器自动添加属性的 getter 以及 setter 函数,属性让头文件更加简洁,减少冗余代码;

苹果推荐利用这种方式去构建类,能用属性尽量使用属性;

属性特性:

原子性(atomic)与非原子性 (noatomic), 熟悉 Java 多线程知识的都比较熟悉这类了;

只读(readonly)以及可读写(readwrite)

对于属性的 getter 以及 setter ,可以使用 dot notation语法,看起来类似对象函数的调用,但本质依旧是消息的发送,这一点尤其需要注意;

也就是说:obj.name; 等价于[obj name];

属性可以是基本类型,也可以是指针,进而指向其他对象,通过指向其他对象可以描述对象之间的关系,如一对一关系以及一对多关系(Array)等等;

  • 对象所有权与 ARC

任何一个对象不会在其内部保存其他对象的实例,只有其他对象的指针,也就是对象地址;如果一个对象拥有另一个对象实例变量时,则称为对象拥有另一个指向对象;

ARC 当一个对象的拥有方个数为0时,则可以判定程序不再需要该对象,即可以释放该对象;ARC 从 Xcode4.2 引入,程序员无需自行管理所有权,手动控制释放与否;

NSObject dealloc 函数,类的实例被释放时,执行该函数;

-(void)dealloc
{
    NSLog(@"");
}

头文件中使用 @class 导入类,而无需 import 这样编译器可以不关注文件具体,因而处理速度更快;

组合实例变量与 属性欺骗其他类,如:

{
    NSMutableArray *_persons;
}
@property(nonatomic) NSArray *persons;

外部消息传递时,获取到的是不可变NSArray 对象,而内部的实现却是 NSMutableArray;

  • 类扩展

类扩展是一组私有声明,只有类以及其实例才能使用类扩展中声明的属性,实例变量以及方法;

在类实现文件 .m 文件, implementation 之上,创建类扩展;0

类扩展,事实上就是其他语言中的 private, 减少在阅读代码时的困难,其他人在使用时只需要阅读头文件即可知道如何使用该对象,而对于其内部封装并不关心;

使用类扩展可以简洁的实现私有特性,而无需使用实例变量与 property 双重覆盖,去欺骗关联对象;

值得注意的是类扩展这一私有特性,即使在继承关系中也是隐藏的,有 java 经验的很好理解:

No visible @interface declare the interface Method ...

  • 所生成实例变量

值得注意的是,头文件中声明的属性所 生成的实例变量,外部无法直接获取其变量,但可以借助其 gettter 以及 setter 函数访问;其子类可以通过 self 访问其 setter 以及 getter 函数,但不能直接访问其实例变量(除了自身,外部都不可以);

  • 内存泄漏

双向关系,强引用循环导致的内存泄漏问题,改强引用循环为弱引用,在双向关系中需要尤其注意这类问题,一旦父对象拥有子对象,则子对象就不能拥有父对象的强引用;

weak 属性,利用弱引用的自动;可以利用 __weak 显示申明指针变量为弱引用;弱引用指针变量所指向的对象当被回收之后,该指针变量为nil;

release 消息,用于显示销毁对象的存在;

OC 中内存管理方式需要重点理解

从局部角度考虑,以类为分界,考虑内存问题,不用考虑其他部分如何处理某个对象;从整个应用角度考虑会使问题复杂化;

  • 集合

NSSet

NSDictionary

不变对象的存在,如果需要添加等操作,就必须构建新的对象;

注意 Collection 集合类对象无法保存 nil ,如果要将使用空,则需要使用 NSNUll 类; [NSNull null]

  • 预处理

#inlude #import 以及 #define ,预处理读取并处理整个文件,并将处理结果交由编译器;

#define 告诉编译器,在看到该预声明变量时,用 define 的值替换;

const 常量,在程序运行的整个生命周期中,其指针值不变;

NSString const *NSLocalCurrentCountry = @"china";

通常情况下,在 define 以及 const 均可实现时, const 有其优势,一则效率更高,二者利于调试,调试器中可以直接查看全局变量值;

  • NSString
NSError *error;// error 指针变量 存储的 NSError 对象的内存地址值;
[info writeToFile:@"tmp/cool.txt" atomically:YES encoding:NSUTF8StringEncoding error:&error];//将方法内部构建的 error 对象地址值传出,  指针的指针
//error:(NSError **) error  方法签名

双星号,代表一个地址参数,存放了指向 NSError 实例的指针;

  • NSData

内存中的某块缓冲区,保存相应字节的数据;

  • 回调

事件驱动:将可执行逻辑代码块与特定事件绑定,事件发生时,逻辑执行;

回调的实现:

消息发送   通知中心中转   Block 对象

selector:

        __unused NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:logger selector:@selector(updateLastTime:) userInfo:nil repeats:YES];

delegate:

如 网络请求: 异步模式下的NSURLConnection delegate,delegate 实现相关函数,在对应web 事件发生时得到回调,如 得到数据,发生错误,获取数据完成…

delegate 究竟该实现哪些方法则需要对应 API 文档实现;

通知:

系统的一些设置发生变化时,程序中很多对象需要知道这一变化,这些对象都成为了通知中心的观察者,当发生对应的系统事件变化时则受到对应的通知回调;

三种方式其具体选择则需要根据具体事件来取舍: 一件事情的 selector, 复杂对象回调使用辅助对象,多个回调对象的触发则使用通知; (仔细体会跟 java 其实是相通的)

注意回调使用中的内存泄漏: 对象与回调对象之间的强引用循环问题,解决方案, 注重注意 dealloc 函数的使用,显示释放: 注意内存的管理考虑局部

  1. 通知中心不拥有观察者,释放观察者时,需要将观察者移除通知中心
  2. 对象不拥有委托对象或数据源对象,某个新建对象是另一个对象的委托对象,则该对象在 dealloc 中应该显示取消相应的对象间关联
  3. 对象不拥有 selector 的 target 目标,如果新建对象是另一个对象的目标,则改对象应该在其 dealloc 中将 target 目标指针赋值为 nil, 取消二者的关联;

以上引用自

  • Block

类似于函数指针的东西(JS 中的闭包)

Block 声明: void (^devewlizer)(id,NSUInteger,BOOL*);

匿名 Block 对象使用,简化代码类似 lambda…

注意 Block 中的 self 引用,如果 Block 中使用了对象实例变量,则 Block 中保存了对象的 self 引用,进一步导致强引用循环问题,因而不要在 Block 中使用实例变量,而应该通过弱引用,进一步使用弱引用对象的 getter 以及 setter 去获取变量; —> 理解编译器的思考过程非常重要

__block 声明变量可以在 Block 中被修改,否则 Block 中捕获的变量是常数,在内部修改时将报错;

  • 协议 protocol

事实上对应 Java 中的接口,指定了对象在系统中所扮演的角色

  • property list

plist 格式文件(XML 格式) writeToFile:@"/file.plist" 即可将对象数据保存为plist 文件;

Cocoa Touch

iOS 开发框架,OC 外的函数类库,有点像 Java 和 Swing 以及 Java 与 Android 的关系

CocoaPods

类库管理工具,类似 Android Maven 前端 NPM 这样的依赖管理工具;

CocoaPods安装和使用教程

First App

获取iOS App开发的初步印象

  • 添加 Empty Project 模版(新版 XCode 已删除该模版):

Finder > Applications > Right-Click on Xcode > Show Package Contents Contents > Developer > Library > Xcode > Templates > Base > Other


Quote:

[Objective-C 语法快速参考](http://blog.jobbole.com/66202/) [iOS开发60分钟入门](https://github.com/qinjx/30min_guides/blob/master/ios.md) [Add Empty Application Template](https://coderwall.com/p/wucjeq/add-empty-application-template-back) [iOS内存管理机制](http://ibloodline.com/articles/2016/01/15/memory.html)
上一篇
下一篇
Loading Disqus comments...
Table of Contents