教学视频推荐stanford ios7 应用开发这个课程,往后的版本就是swift语言的ios开发了
入门objective-c基础教程
进阶书记<
终极奥义 <<苹果官方文档>>(简直完美)
框架是一种把头文件。库。图片。声音等内容聚集在一个独立单元中的集合体
自动引用计数(automatic reference counting,ARC)只对可保留的对象指针有效 主要有以下三种
(1)代码块指针
(2)objective-c 对象指针
(3)通过_attribute_c((NSObject))类型定义的指针
如果想要在代码中使用ARC,必须满足以下三个条件
1能够确定哪些对象需要进行内存管理
2.能够表明如何去管理对象
3.有可行的办法传递对象的所有权
使用弱引用,保留计数器的值不会增加。可以用来防止内存泄漏
归零弱引用:在指向的对象释放之后 这些弱引用会被设置为零(nil),就可以向平常的指向nil值的指针一样被处理
枚举
-(NSEnumerator *)objectEnumerator;
可以使用这个方法:
NSEnumerator *enumerator=[array objectEnumerator];
如果想从后面往前浏览可以使用reverseObjectEnumerator方法可以使用
快速枚举
for(NSString *string in array)
{
NSLog (@“I found %@”,string);
}
异常
@try : 定义用来测试的代码块以决定是否要抛出异常
@catch() : 定义用来处理已抛出异常的代码块。接受一个参数,通常是NSException类型,但也可以是其他类型。
@finally : 定义无论是否抛出异常都会执行代码块,这段代码总会执行的。
@throw:抛出异常
与当前@catch异常处理代码相关的@finally代码块会在@throw引发下一个异常处理调用之前执行代码,因为@finally是在@throw发生之前调用的, (内存管理中) 这样会有一个问题 《如果再同一代码块中重复抛出异常》@finally会在异常重新抛出之前执行代码。 这样可能会导致@finally中内存管理代码早于@throw执行,@throw会变成僵尸异常 , 解决办法在pool外保留@finally就可以了
cocoa是那个关于对象及其保留计数器的规则:
1。如果使用new,alloc,或copy操作获得了一个对象,则对象的保留计数器值为1
2.。如果通过其他方法获得一个对象,则假设该对象的保留计数器的值为1,而且已经被设置了自动释放
3。如果保留的某对象,则必须保持retain方法和release方法的使用次数相等
996.操作符
<.>操作符其实是一个行为的调用,(例x.width=200)如果对<.>赋值的话那么就是调用setWidth这个行为 “只能用于属性getter和setter”(会被警告) 等号左边调用setter方法 等号右边调用getter方法
分配对象
向某个类发送alloc消息,就能为类分配一块最够大的内存,以存放该类的全部实例变量。同时alloc方法还顺便将这块内存区域全部初始化为0。 BOOL类型变量被初始化为NO。int类型变量被初始化为0,float被初始化为0.0.所有指针被初始化为nil。
类别:
任何NSString对象都能响应lengthAsNumber消息,包括字面量字符串,description方法返回的字符串,可变字符串,其他工具集某部分字符串,文件中加载的字符串,从因特网海量内容中提取的字符串 等等。正式这种兼容性使类别成为了一个强大的概念。通过它不需要创建NSString类的子类就可以获得一种新的行为
局限性
一 无法向类中添加新的实例变量
二 名称冲突 类别中的方法与现有的方法重名。当发生名称冲突时,类别具有更高的优先级。你的类别方法将完全取代出事方法,导致初始方法不再可用
类别的三个用途
1 将类的实现代码分散到多个不同的文件或框架中
2创建对私有方法的前向引用
3向对象添加非正式协议
属性
1.property中strong 只要不再有强指针指向它 内存就会释放
weak 弱指针 不仅仅是释放 指针会被置为nil(在堆中分配 需要strong或weak来修饰 原始类型例如BOOL int等不需要strong和weak来修饰 因为不在堆中 不需要内存管理)
2.nonatomic 非线程安全的:不能有两个线程同时设置该属性
因为不需要多线程设置同一个对象 ui对象在ui线程 模型对象在模型线程
@synthesize x=y ; 并不是说吧y赋给x ,而是说让@synthesize x 去使用名为y这个实例变量
方法
– (void) setNumerator: (int) n;
。⬆️ | ⬆️ | ⬆️ 。| 。 ⬆️ | ⬆️ | ⬆️
方法 | 返回| 方法 | 。方法 | 参数 | 参数
类型 | 类型| 名称 | 有参数 | 类型 | 名称
开头的 - 表明该方法是一个实例化方法, + 表示类方法,类方法本身是对类本身执行某些操作的方法,例如创建类的实例
1返回值
(1)声明新方法时需要告诉编译器该方法是否有返回值,如果有是哪种类型的值,将返回类型写在正负号后面的括号里
(2)不返回值可用void写在括号里
2方法的参数
(1)参数是通过参数名前面()指明类型的 例(int)(double)
(2)参数名称可以是任意的,它是用来引用参数的方法名称的
每个方法名的都以:结束,这告诉oc编译器该方法会有参数。接下来制定参数类型,并将起放入一对圆括号中,这与为方法自身指定返回类型的方式十分相似,最后使用象征性的名称来确定方法所指定的参数,整个声明以一个;结束。
不带参数名的方法
-(int) set:(int) n: (int) d;
注意第二个参数没有命名,这个方法名称为set:: ,两个冒号表明了这个方法有两个参数,虽然没有对所有的参数命名。
要调用set::方法,可以使用冒号作为参数分隔符
[aFraction set: 1 :3];
在编写新方法时,省略参数名不是一种好的编程风格,因为他使程序很难读懂并且不直观,特别是使用的方法参数特别重要时,更是如此
规定条款1 除了外面有init时 永远别调用alloc那些东西,不初始化就在堆中分配对象毫无意义 嵌套才行
反之除了里面有alloc外面也不要调用init,而且一定不要超过一次的调用init。 凡是初始化时init都会返回实例类型作为返回类型,将总是返回self self=[super init];
返回类型IBAction是typedef void ,为什么这么做,oc用来标记实现部分 而IBOutlet是无意义的 编译器会忽略它 只是用来在鼠标悬停是显示链接到什么
假设count是一个属性 self.count++;调用的是什么setter还是getter?
两者都调用先调用getter获取值 再调用setter设置值
@[xxx] 来创建数组
一个方法两个参数
-(void) setWord1:(NSString *) word1 setWord2:(NSString *) word2
(方法的数据返回类型) 方法名: (参数1数据类型) 参数1的变量名 参数2名称: (参数2数据类型) 参数2的变量名 ….
OC的函数的一个参数是由3个部分组成的,第一个参数的名称默认为方法名。
[obj setWord1: “参数1值”, setWord2: “参数2值” ]
[对象 方法名: 参数1值, 参数2的名称: 参数2值]
在Objective-C中,采用两个参数的方法的声明如下所示
-(void)someMethodWithFirstValue:(SomeType)value1 secondValue:(AnotherType)value2;
value1和value2是在实现中用于访问在调用方法时提供的值的名称,就好像它们是变量一样
方法调用中参数的顺序必须与方法声明匹配并且实际上,方法声明的是方法名称的一部分.
上面使用 的value1和value2值名称,不是方法声明的一部分,这意味着不必在声明中使用与实现中完全相同的值名称。唯一的要求是签名必须匹配,这意味着您必须使方法的名称以及参数和返回类型保持完全相同。
NSObject中的copy
copy:给一个可变对象发送copy消息 将返回一个不可变副本
mutablecopy返回可变副本
@[ ]用于array/mutablearray
@()用于NSNumber
@{key,value… }用于NSDicitonary
id是一个指针 指向未知类型或未指定类型,实际上o-c中所有指针都是id指针,当你将消息发送给一个对象时关于执行什么代码的决定,直到运行时才会决定,当发送一个消息时,一个函数会被调用,查阅消息发送时,对应于所指向的那一特定类所应执行的正确代码,这叫做动态或迟绑定,o-c中所有消息发送都是这样的
NSArray
对象的有序集合,是不可变的,一经创建其中的对象就会一直保持不变,无法添加 也无法删除任何对象,数组中所有对象在堆中都是强存储的,只要数组本身处在堆中,只要有强指针指向数组本身,数组中所有对象都会留在堆中
NSNumber
这个类被用于包含原始类型,例如 int,float,double,BOOL,enums,etc ,通常这些类型不能放入数组
NSDictionary
字典 它是键值对的不可变集合,类似hash表,所有键和值都是强存储的,如果他们在哪里作为键和值,那么他们就在堆中,只要字典在堆中他们就在,键和值显然都是对象
不可变NSDictionary的创建的一种语法是
@{key1:value1, key2:value2, key3:value3}
遍历字典
NSDictionary *myDictionary=…;
for(id key in myDictionary){
id value=[myDictionary objectForKey:key];
}
Property List
属性列表的意思是集合的集合。
那么什么是集合呢,NSArray,NSDictionary,NSNumber.NSString,NSDate,NSData
这些都是简单的集合,或者可以把他们看成集合的叶节点
任意对象图,只要其中"只有"NSArray,NSDictionary NSNumber NSString NSDate NSData这些,那么它就是属性列表了
NSUserDefaults
是一种共享字典,甚至在应用程序启动和退出时仍然持续存在
,就像一个永久的NSDictionary,NSUserDefaults数据库中存储的一切,都必须是一个属性列表,不过它并非一个完全的数据库,很小性能不是很好,只能将很小的东西存放到这里,不要存放大型图片这样的东西,将他们转化未NSData然后存储
NSRange
typedef struct{
NSUInteger location; //开始的位置
NSUInteger length; //长度
}NSRange;
比较重要的常数NSNotFound,NSNotFound是range中location值
没有被发现或者无效,例如在一个字符串中搜索子字符串结果找不到就会返回一个range,其位置将是NSNotFound
创建新的NSRange 的三种方式
NSRange range;
range.location=xx;
range.length=xx;
第二种
NSRange range={17,4};
第三种 cocoa提供的函数NSMakeRange();
NSRange range=NSMakeRange(17,4);
创建字符串
+(id)stringWithFormat:(NSString *)format,…;
可以按如下方式创建一个新的字符串
NSString *height;
height=[NSString stringWithFormat:@“You height is %d feet,%d inches”,5,11];
-(id)initWithFormat:(NSString *)format,…;
string=[[NSString alloc]inintWithFormat:@"%d or %d",25,624];
-(id)initWithContentsOfFile:(NSString *)path encoding:(NSStringEncoding)enc error:(NSError **)error
这个方法用来打开指定路径上的文本文件,读取文件内容,并使用文件内容初始化一个字符串
如果在生命和方法是添加了加号+,就是把这个方法定义为类方法。这个方法属于类对象,通常用于创建新的实例,称这种用于创建新对象的方法为工厂方法(factory method)
NSRangePointer
在IOS中我们不会将struct放到堆中,这个NSRangePointer用于引用调用range,有些方法会将NSRangePointer作为参数,这里说的是如果你讲一个指向range的指针传递给我,我将使用一些信息填充它,这里你几乎总是可以传递null,他不会填入任何信息,因为你没有指向一个range,但这是用于引用
View Controller lifecycle
视图控制器的生命周期就是一系列方法
大部分视图控制器都是在storyboard中创建的 ,视图控制器不会生成代码,你基本是直接编辑这些对象
每次我们向UINavigationController上压入新MVC时都是从新storyboard中新建一个在堆中新实例化一个,返回之后它就会消失
《effective objective-c 2.0 》笔记
采用消息结构的语言不论是否多态,总是在运行时才会去查找要执行的方法
OC中中指针是用来指示对象的想要声明一个变量,令其指代某个对象
NSString *someString=@“The string”;
他声明一个名为someString的变量,其类型是NSString * ,此变量是指向NSString的指针,所有OC语言的对象都必须这样声明,因为对象总是分配在“堆”中。不能在栈中分配OC对象
NSString stackString;
如果创建两个变量,令其指向同一地址,那么并不拷贝对象,指示这两个变量会同时指向此对象,两个变量都是XX类型,这说明当前“stack frame”里面分配了两块内存,每块内存大小都能容下一枚指针(32位4字节64位8字节),两块内存里面的值都一样,就是XX实例的内存地址
分配在堆中的内训必须直接管理,分配在栈上用于保存变量的内存则会在其栈帧弹出是自动清理。
OC将堆内存管理抽象出来了,不需要用malloc及free来分配或释放对象所占内存。OC运行期环境把这部分工作抽象为一套内存管理架构,名叫“引用计数”
消息与函数调用之间的区别看上去像这样
Object *obj=[Object new];
(c++)Object *obj=new Object;
[obj performWith:parameter1 and:parameter2];
(c++) obj->perform(parameter1,parameter2);
第二条要点
1 除非明确有必要,否则不要引入头文件。一般来说,应在某个类的头文件中使用前向声明来提及别的类,并在实现现文件中引入那些类的头文件。这样可以尽量降低类之间的耦合(coupling)
第三条
NSString,NSNumber,NSArray,NSDictionary
字符串字面量(string literal)
NSString *someString=@“Effective Objectibe-C 2.0”;
如果不实用这种语法,就要以常见的alloc init 方法来分配并初始化NSString对象,这种方法可以缩减代码长度,使其更为易读
extern 的用法与c++一致,都是告诉编译器这个变量其他地方一定会有定义
第五条枚举
要点
1应该用枚举来表示状态机的状态,传递给方法的选项以及状态码等值,给这些值起个易懂的名字
2如果把传递给某个方法的选项表示为枚举类型,而多个选项又可同时使用,那么就将各选项值定义为2的幂,以便通过按位或操作将其组合起来
3用NS_ENUM与NS_OPTIONS宏来定义枚举类型,并指明其底层数据类型。这样可以确保枚举是用开发者所选的底层数据类型实现出来的,而不会采用编译器所选出来的类型
4在处理枚举类型的switch语句中不要实现default分支。这样的化,加入新枚举之后,编译器就会提示开发者:switch语句并未处理所有的枚举。
第六条对象,消息,运行期
对象(object)是基本构造但愿,可以通过对象来存储并传递数据。在对象知见传递数据并执行任务的过程就叫做消息传递。
property是OC的一项特性,用于封装对象中的数据。OC对象通常会把其所需要的数据保存为各种实例变量。实例变量一般通过存取方法来访问,getter用于读取变量值,而setter方法用于写入变量值
如果使用了编译期计算出来的偏移量那么修改类定义之后必须重新编译,否则就会出错,OC的做法是,把实例变量当作一种存储偏移量所用的“特殊变量”,交由“类对象”保管,偏移量会在运行期查找,如果类的定义变了,那么存储的偏移量也就变了,这样无论何时访问实例变量,总能使用正确的偏移量。甚至可以在运行期间向类中新增实例变量,这就是稳固的‘应用程序二进制接口’(Application Binary Interface,ABI)
如不想令编译器自动合成存取方法,则可以自己实现。如果你只实现了其中一个方法,那么另外一个还是会由编译器来合成。
另一种方法:使用@dynamic关键字,它会告诉编译器:不要自动创建实现属性所用的实例变量,也不要为其创建存取方法,而且在编译访问属性代码时,即使编译器发现没有定义存取方法,也不会报错,它相信这些方法可以在运行期找到
例
@interface EOCPerson:NSManagedObject
@property NSString *firstName;
@property NSString *lastName;
@end
@implementation EOCPerson
@dynamic firstName,lastName;
@end
编译器不会为上面这个类自动合成存取方法和实例变量。如果用代码访问其中的属性,编译器也不会发出警示信息
第六条要点
1可以使用@peoperty 语法来定义对象中所封装的数据
2通过"特性"来指定存储数据所需要的正确语义
3在设置属性所对应的实例变量时,一定要遵从改属性所声明的语意
第七条:在对象内部尽量直接访问实例变量
本书作者强烈建议,除了集中特殊情况之外,在读取实例变量的时候采用直接访问的形式,而在设置实例变量的时候通过属性来做
在惰性初始化这种情况下,必须通过getter来访问属性,否则实例变量永远不会被初始化
-(EOCBrain *)brain{
if(!_brain){
_brain=[Brain new];
}
return _brain;
}
第七条要点
1在对象内部读取数据时,应该通过实例变量来读,而写入数据时则通过属性来写
2在初始化方法及dealloc方法中,总是应该通过实例变量来读写数据
3有时会使用惰性初始化技术配置某粉数据,这种情况需要通过属性来读取数据。
第八条:理解对象等同性概念
oc中==操作符比较的事两个指针本身,而不是其所指向对象。
首先直接判断两个指针是否相等,若想等则均指向统一对象,所以受测对象也必定相等。接下来比较两个对象所属的类。如不属同一个类,则两个对象不相等,不过我门也可能认为一个实例可与其子类实例相等,在继承体系中经常遇到此类问题。所以实现isEqual方法时要考虑到这种情况,最后检测每个属性是否相等。只要其中有不想等的属性就判定两个对象不想等。
计算hash值
-(NSUInteger)hash{
NSUInteger firstNameHash=[_firstName hash];
NSUInteger lastNameHash=[_lastName hash];
NSUInteger ageHash=_age;
return firstNameHash ^l astNameHash^ ageHash;
}
在自己编写判定方法时,应该一并覆写“isEqual”方法。后者的常见实现方式为:如果受测参数与接收消息的对象都属于同一个类,那么就调用自己编写的判定方法,否则交由超类来判断
第八条要点
1若想检测对象的等同性,请提供“isEqual”与"hash"方法
2相同的对象必须具有相同的哈希值,但是两个hash值相同的对象却未必相同
3不要盲目的逐个检查每条属性,而是应该依照具体需求来制定检测方案。
4hash算法 使用速度快,碰撞率低的算法
代码块 block:
(^blockname)(list of arguments)=^(arguments){dody};
编译器可以通过代码块的内容推导出返回类型,所以可以省略,如果代码块没有参数也可以省略。
void (^
theBlock)()=^{printf(“hello world\n”); };
这个幂符号^ 只有在定义时才需要使用它,调用时不需要。
除了包含可执行代码之外,块还具有从其封闭范围捕获状态的能力。
例如,如果从方法内部声明块文字,则可以捕获该方法范围内可访问的任何值,如果您在定义块的时间与调用块的时间之间更改了变量的外部值,该块捕获的值不受影,这也意味着该块无法更改原始变量的值,甚至无法更改捕获的值(将其捕获为const变量)
本地变量:
本地变量就是与代码块在同一范围内声明的变量。本地变量被代码块作为常量获取到,如果要修改它的值必须声明为可改变的
使用__block(例 __block int a=xx; 这个本地变量a就是可修改的了)
如果需要能够从一个块中更改捕获的变量的值,则可以__block在原始变量声明上使用存储类型修饰符。这意味着该变量存在于存储中,该存储在原始变量的词法范围与该范围内声明的任何块之间共享
块的强引用
块维护对任何捕获对象的强引用,包括self,这意味着,例如,如果对象维护copy捕获的块的属性,则很容易以强引用周期结束self
解决办法
通过捕获指向的弱指针self,该块将不会与XYZBlockKeeper对象保持牢固的关系。如果在调用该块之前释放了该对象,则weakSelf指针将简单地设置为nil
类族
统一的父类创建接口但不实现 各个子类实现,父类加所有子类是类族
1类族模式可以把 实现细节隐藏在一套简单的公共接口后面。
2系统框架中经常使用类族
3从类族的公共抽象基类中继承子类时要当心,请先查看开发文档
写一个简单计算器 思路是用两个NSMutablaArray 一个用来放操作数 另一个放符号
NSMutableArray存放的是指向对象的指针 不能直接相减
往数组中存放int double 这些基本类型不能直接存放,
[_Calculation.operand1 addObject:[NSNumber numberWithDouble:value]]; 要通过NSnumberWithxx这个方法存放 选择你想存放的对应类型的方法
写一个简单计算器 思路是用两个NSMutablaArray 一个用来放操作数 另一个放符号
声明全局变量时 用extern int x;这种格式来声明
外部变量可以访问
虽然是全局变量 但在其他文件使用时要告诉其他文件这个变量是哪个类的 所以要先声明一个其他类的对象 ,再用"其他类对象.其他类全局变量"这个变量语法来调用
方法调用的时候 建议传参
转载的
//NSMutableArray里面需要放的是一个类,但普通数据类型不是类,我们可以用NSNumber类来包装(即以对象形式实现)基本数据类型
NSMutableArray *array = [[NSMutableArray alloc] init];
BOOL isRight = NO;
int ABC = 10;
long longABC = 10;
double doubleABC = 10.123;
char cr = ‘a’;
[array addObject:[NSNumber numberWithBool:isRight]];
[array addObject:[NSNumber numberWithInt:ABC]];
[array addObject:[NSNumber numberWithDouble:doubleABC]];
[array addObject:[NSNumber numberWithLong:longABC]];
[array addObject:[NSNumber numberWithChar:cr]];
// 将基本类型数据封装到NSNumber中后,就可以通过下面的实例方法重新获取它
(char) charValue;
(int) intValue;
(float) floatValue;
(BOOL) boolValue;
(NSString *) stringValue;
// 例如
NSNumber *num = [NSNumber numberWithInt:88];
NSInteger integer = [num intValue];
静态变量
当希望将变量定义成全局变量,但不是外部变量,换句话说就是只在特定模块中是全局的,当除了特定类的方法之外,再没有其他方法需要访问这个特定的变量,可以将这个变量定义成static.
声明在任何方法之外,那么在该文件中所有位于这条语句之后的方法或函数都可以访问这个变量的的值,而其他文件中的方法和函数则不行.
由于这个变量不是实例变量,所以分配器方法可以直接访问它,类用户不知道这个变量,因为它是定义在实现文件中的静态变量,作用域只是文件内部,因此用户不能直接访问该变量,也就没有违背数据封装的概念,如果需要从类之外访问该变量,则可以编写一个方法来获取该变量
全局变量
int XXX= 0;(定义在任何方法或函数之外,前面不加extern)
定义在本模块中的全局变量而且也为外部变量
外部变量是可以被其他任何方法或函数访问和更改值的变量.在需要访问外部变量的模块中,变量声明和普通方式一样,只需要在声明前加上关键字extern,这就告知系统,要访问其他文件中定义的全局变量
例子
extern int XXX;
包含这个声明的模块可以访问和改变 XXX 的值,同样其他文件使用这个声明也可以访问XXX
外部变量
使用外部变量时,必须遵守:变量必须定义在源文件中的某个位置,即在所有的方法和函数之外声明变量,并且前面不加关键字extern
调度队列
1连续队列,每个连续队列都会根据指派的顺序执行任务,可以按自己的想法创建任意任务数量的队列,他们会并行操作。
2并发队列 ,每个并发队列都能并发的执行一个或多个任务。任务会根据指派到队列的顺序开始执行。无法创建连续队列,只能从系统提供的三个队列內选择一个来使用
3主队列,是应用程序中有效的主队列,执行的是应用程序的主线程任务
在实现计算器项目中遇到的问题
当存入‘+‘ ’-‘符号到NSMutableArray报错 后来在网上看了看,原因是NSMutableArray里面存的是对象 需要把基本的类型int double char先用NSNumber包装起来才可以存进去
NSNumebr *ns= [NSNumber numberWithChar:‘+’];
比较数组中的元素与@“+”出错
因为我包装的char 属于int类型 与NSString对象不能比较 所以采用 if([self.operator1[0] intValue] == ‘+’)
自己可以创建 串行队列, 也可以创建 并行队列。如下代码,它有两个参数,第一个参数是标识符,用于 DEBUG 的时候标识唯一的队列,可以为空,第二个参数用来表示创建的队列是串行的还是并行的,传入 DISPATCH_QUEUE_SERIAL 或 NULL 表示创建串行队列。传入 DISPATCH_QUEUE_CONCURRENT 表示创建并行队列。
//串行队列
dispatch_queue_t queue = dispatch_queue_create(“testQueue”, NULL);
dispatch_queue_t queue = dispatch_queue_create(“testQueue”, DISPATCH_QUEUE_SERIAL);
//并行队列
dispatch_queue_t queue = dispatch_queue_create(“testQueue”, DISPATCH_QUEUE_CONCURRENT);
在block应用中 避免循环存储(强指针指向对方,无法释放)采用若指针weakself避免
NSInvocation 类不能使用alloc init方法来创建对象应该使用
+invocationWithMethodSignature: 这个类方法来创建对象
加载.plist文件就是把plist文件中的字符与自己程序中的变量关联起来,再进行相应的流程
NSClassFromString方法是从一个名字获得一个类
协议
声明协议
@protocol NSCopying
//method
@end
protocol后面是协议名称,必须唯一,也可以继承父协议,与继承父类相似
@protocol childrenProtocol
//method
@end
所以需要实现子协议和父协议两个协议中所有需要实现的方法。
采用协议
可以在类的声明中列出该协议的名称,并用尖括号括起来
@interface ABC:NSObject
{
}
@end
方法中的协议
如果用一个尖括号括起来的协议名称跟随在id之后,则编译器将会知道我会接受任何类型的对象,但前提是遵守该协议
-(void) setObjectValue:(id<遵守的协议>)object;
该方法要求object对象遵守该协议
委托
李先生 张小姐两个类(别人处借鉴)
在OC中委托的效果也是通过协议实现的,大致流程是先定义某个协议,预留未实现的方法,先定义李先生,在李先生的大括号内包含协议,并调用协议申明的方法,定义张小姐类型,使张小姐遵循前面定义的协议,并在张小姐内部实现前面协议申明的方法,在张小姐内部实例化李先生(分配李先生一个对象)并在张小姐的类内部把张小姐指派给李先生内部的协议,然后返回到李先生调用“在张小姐内部实现协议的方法”的步骤
OOP真正的革命性在于它使用间接来调用代码,不是直接调用某个函数,而是间接调用。
什么是id类型 它表示的是标识符(identifier).id是一种泛型,可以用来应用任何类型的对象。
在objective-c中,通知对象执行某种操作称为发送消息(有人称为调用方法).代码[shape draw]表示向shape对象发送了draw消息。
消息(message)是对象可以执行的操作,用于通知对象去做什么。
继承 :通过继承可以把重复的代码都放到父类当中,简洁代码,减少bug。
父类中的空方法类似抽象基类的概念,虽然是空的,但我们仍然需要定义它,以便父类的所有子类都能通过空方法来实现各自的方法,在方法中不写任何内容或返回一个虚值都是可以通过编译的。
记住,每个方法调用都获得了一个名为self的隐藏参数,它是一个指向接收消息对象的指针。这些方法通过self参数来寻找他们需要用到的实例变量。
Super 既不是参数也不是实例变量,而是由Objective-c编译器提供的一种神奇的功能。当你向super发送消息时,实际上是在请求Objective-c向该类的超类发送消息。如果超类中没有定义该消息。objective-c 会和平常一样继续在继承链上一级中查找。
重写方法时,嗲欧哦那个超类方法总是一个明智之举,这样可以实现更多功能。调用继承来的方法可以确保获得方法实现的所有特性。
@interface Car : NSObject
{
Engine *engine;
Tire *tires[4];
}
每一个Car对象都会为指向engine和tires的指针分配内存,但是真正包含在Car中的并不是engine和tires变量,只是内存中存在的那些对象的引用指针。
if(self = [super init])
为了让父类(这里是NSObject)将所有需要的初始化工作一次性完成,你需要调用[super init]。init方法返回的值(id类型数据,即泛型对象指针)就是被初始化的对象。 将[super init]返回的结果赋给self是Objective-c的惯例。这么做是为了防止超类在初始化过程中返回的对象与一开始创建的不一致。
Get这个词在Cocoa中有特殊的含义。如果get出现在Cocoa的方法名称中,就意味着这个方法会将你传递的参数作为指针来返回数值。如果你在存取方法的名称中使用了get,那么有经验的Cocoa程序眼就会习惯性的将指针当做参数传入这个方法,当他们发现这不过是一个简单的存取方法时就会感到困惑。最好不要让其他人一头雾水。特别指出,对于返回属性值的存取方法,名称中不能使用get这个词
get 这个词在cocoa中有着特殊的含义,如果get出现在Cocoa的方法名称当中,就意味着歌着歌方法会将你传递的参数作为指针来返回数值.对于返回属性值的存取方法名称当中不能使用get这个词
getter方法engine返回实例变量engine的当前值,记住,在Objective-c中所有对象间的交互都是通过指针实现的,所以engine方法返回的是一个指针,指向Car中的发动机对象.
@class 创建了一个前向引用。这是告诉编译器:相信我以后你自然会知道这个类到底是什么,但是现在,你知道这些足矣。
如果有循环以来关系,@class也很有用。A类使用B类,B类也适用A类。如果试图通过#import语句让这两个类相互引用,那么就会出现变异错误。但是在A.h文件中使用@class B,在B.h中使
用@class A,那么这两个类就可以互相引用了。
用#pragma mark whatever,后面的whatever处可以填写任何文字,它会出现在功能菜单中。这种方法便于添加可读的标记,供程序员查看和使用。
NSRange
typedef struct _NSRange
{
unsigned int location;
unsigned int length;
} NSRange;
这个结构体用来表示相关事物的范围,通常是字符串里的字符范围或者数组里的元素范围。location字段存放该范围的起始位置,length字段则是该范围内所包含的元素个数.
NSString的stringWithFormat:方法就是通过格式字符串和参数来创建NSString的
如果在声明方法时添加了+号,就是把这个方法定义为类方法,这个方法属于类对象(而不是类的实例对象),通常用于创建心的实例。我们称这种用来创建新对象的类方法为工厂方法(factory method).
如果某个方法实现的事很通用的功能,比如创建一个实例对象。或者访问一些全局类数据,那么最好使用加号(+)作为前缀将它声明为类方法。
NSString的length方法,它放回字符串中的字符个数。
比较两个字符串是否相等时,应该使用isEqualToString;而不能仅仅比较字符串的指针值(指的是使用来比较两个字符串),这是因为运算符只判断thing1和thing2的指针数值,而不是他们所指的对象,所以用比较即使内容相同也会不同的,
因此如果你想检查两个对象是否为同一事物,就应该使用。如果想查看是否相等(即这两个字符串的内容相同),请使用isEqualRToString.
如果你想知道字符串内的某处是否包含其他字符串,请使用rangeOfString:
-(NSRange) rangeOfString:(NSStirng *) aString;
将rangeOfString:发送给一个NSString对象时,传递的参数就是要查找的字符串。他会返回一个NSRange结构体,告诉你与这个字符串相匹配的部分在哪里以及能够匹配上的字符个数。
如果没有找到,那么range.location则等于NSNotFound.
NSString是不可变的,这并不意味着我不能操作他们,不可变意识是NSString一旦被创建,便不能改变,我可以对它执行各种各样的操作,例如用它生成新的字符串,查找字符串或者将它与其他字符串进行比较,但是我不能以删除字符或者添加字符的方式来改变它。
在NSMutableString 可变字符串中,可以使用deleteCharacterInRange:方法删除字符串中的字符。
将字符串切分成数组和将数组元素合并成字符串这种操作。
使用-componentsSeparatedByString:将字符串切分成数组
NSString *string = @“oop:ack:bork:greeble:ponies”;
NSArray *chunks = [string componentsSeparatedByString:@":"];
使用componentsJoinedByString:来合并NSArray中的元素并穿件字符串
string = [chunks componentsJoinedByString:@":"];
生成@"oop:ack:bork:greeble:ponies"的字符串
NSEnumerator cocoa可以用它来表示集合中迭代出的对象,要想使用NSEnumerator需要通过使用objectEnumerator向数组请求枚举器
NSEnumerator *enumerator = [array objectEnumerator];
while (id thingie = [enumerator nextObject])
{
NSLog(@“i found %@”,thingie);
}
对可变数组进行枚举操作时,有一点需要注意:不能通过添加或删除对象着类方式来改变数组的容量。如果这么做了,枚举器就会出现混乱,我也会获得未定的结果。
快速枚举
for(NSString *string in array)
{
NSLog(@"%@",string);
}
为了支持代码块的功能,苹果公司添加了一个能在NSArray中通过代码块枚举对象的方法。
例[array enumerateObjectsUsingBlock:^(NSString *string,NSUInteger index,BOOL *stop){
NSLog(@“I found %@”,string);
}];
问题是“为什么我要使用它来代替快速枚举?”因为通过代码块可以让循环操作并发执行,而通过快速枚举,执行操作要一项项地线性完成。
NSDicitonary能在给定的关键字(通常是一个NSString字符串)下存储一个数值,(可以是任何类型的Objective-c对象),就可以用这个关键字来查找相应的数据。
字面量语法即使用类型@{key:value,…}的方法来定义,dictionaryWithObjectAndKeys:后面的参数是要存储的对象,然后才是关键字,而字面量的语法则是关键字在前,数值在后。关键字和数值之间以冒号分开,而每对键值之间用逗号分开。
使用objectForKey:方法并传递前面用来存储的关键字,就可以访问字典中的数值了
或者用dictionaryName[key]也能访问value
例 Tire *tire = tires[@“abc”];
向NSMutableDictionary类发送dictionary消息,可以创建新的NSMutableDictionary对象,可以使用setObject: forKey:方法为字典添加元素,也可以使用dictionaryWithCapacity:方法来创建新的可变字典,如果对字典中已有的关键字使用setObject: forKey:方法,那么这个方法会用新值替换掉原来的数值。如果想在可变字典中删除一些关键字,可以使用
removeObjectForKey:方法
请不要创建NSString,NSArray或NSDictionary的子类。在cocoa中许多类实际上是以类簇
(class clusters)的方式实现的,即它们是一群隐藏在通用接口之下的与实现相关的类。创建NSString 对象时,实际上获得的可能是NSLiteralString ,NSCFString,NSSimpleCString,NSBallOfString或其他未写入文档的与实现相关的对象
而使用NSArrat或NSString时不必在意系统内部到底用的是哪一个类,但给一个类簇创建子类则是非常痛苦的事,通常可以将NSString NSArray复合到你的某个类中或者使用类别来解决
编程中的问题
NSArray和NSDictionary只能存储对象,而不能直接存储任何基本类型的数据,如int float struct。不过可以用对象来封装基本数值,比如将int封装到一个对象当中,就可以将这个对象放入NSArray或NSDictionary中了。可以用NSInteger或NSUInteger类来处理基本类型
Cocoa提供了NSNumber类来封装基本数据类型.可以使用以下方法来创建新的NSNumber对象
通常将一个基本类型的数据封装称对象的过程被称为装箱(boxing)从对象中
提取基本类型的数据叫做开箱(unboxing)。
不要使用任何刚释放的内存,否则可能误用陈旧的数据,从而引发各种各样的错误,而且如果该内存已经加载了其他数据,将会破坏这些数据。
当使用alloc,new方法或者通过copy消息创建一个对象时,对象的保留计数器被设置为1,要增加对象的保留计数器的值,可以给对象发送一条retain消息。要减少的话可以给对象发送一条release消息.
当一个对象因其保留计数器归0而即将被销毁时,Objective-c会自动向对象发送一条dealloc,我可以在自己的对象中重写dealloc方法,这样就能释放掉已经分配的全部相关资源,一定不要直接调用dealloc方法,Objective-c会在需要销毁对象时自动调用它。
创建一个自动释放池
通过@autoreleasepool关键字
通过NSAutoreleasePool对象
在我门一直使用的Foundation库工具集中,创建销毁自动释放池已经由@autorelease关键字完成,当使用@autorelease{}时,所有花括号里的代码都会被放入这个池子里。
任何在花括号里面定义的变量在花括号外就无法使用了。这是C语言中的有效范围,比如说循环代码
第二种更名去的方法就是使用NSAutoreleasePool对象。如果使用了这个方法,创建和释放NSAutoreleasePool对象之间的代码就会使用这个新的池子。
cocoa内存管理规则
1当我使用new,alloc,copy方法创建一个对象时,该对象的保留计数器值为1,当不再使用该对象时,我应该向该对象发送一条 release或autorelease消息,这样该对象将在其使用寿命
结束时被销毁。
2当我通过其他方法获得一个对象时,假设该对象的保留计数器值为1,而且已经被设置为自动释放,那么我不需要执行任何操作来确保该对象的到清理。如果我打算在一段时间内拥有该对象,则需要保留它并确保在操作完成时释放它。
3如果你保留了某个对象,就需要释放或自动释放该对象,必须保持reatin方法和release方法使用次数相等
请记住,自动释放池被清理时间是完全确定的:要么是在代码中自己手动销毁,要么是使用AppKit时在时间循环结束时销毁。你不必担心程序会随机地销毁自动释放池,也不必保留每使用的
每一个对象,因为在调用函数的过程中自动释放池不会被销毁。
自动释放池以栈的形式实现:当我创建了一个新的自动释放池时,他就被添加到栈顶。接收autorelease小心的对象将被放入最顶端的自动释放池中。如果将一个对象放入一个自动释放池中,然后创建一个新的自动释放池,再销毁该新建的自动释放池,则这个自动释放池对象仍将存在,因为容纳该对象的自动释放池仍将存在
ARC(自动引用计数automatic reference counting,ARC)不是垃圾回收器。垃圾回收器在运行时工作,通过返回代码来顶起检查对象。与此相反,ARC是在编译时进行工作的。他在代码中插入合适的retain和release语句,就好像是我自己手动写好了所有的内存管理代码。不过是编译器替我完成了内存管理工作。
当指针指向某个对象时,我可以管理它的内存(通过retainu和release),也可以不管理.如果我管理了,就拥有这个对象的强引用(strong reference),如果我不管理,那么我拥有的就是这个对象的弱引用(weak reference)
在运行时系统中创建并处理异常的行为被称为抛出(throwing)异常
@try:定义用来测试的代码块以及决定是否要抛出异常
@catch():定义用来处理已抛出异常的代码块。接收一个参数,通常是NSException类型,但也可以是其他类型
@finally:定义无论是否抛出异常都会执行的代码块,这段代码块总是会执行的。
@throw:抛出异常
可以根据需要处理异常类型使用多个代码块。代码块应该从具体到抽象的顺序排列,并在最后使用一个通用代码块。
当程序检测到了异常,就必须向处理它的代码块报告这个异常。
程序会创建一个NSException实例来抛出异常,并会使用以下两种技术之一;
1使用"@throw异常名;"语句来抛出异常
2向某个NSException对象发送raise消息
例
NSException *theException = [NSException exceptionWithName:…];
@throw theException;
或[theException raise];
与当前@catch异常处理代码相关的@finally代码块会在@throw引发下一个异常处理调用之前执行代码,因为@finally是在@throw发生之前调用的。
当对象接收到一条autorelease消息时,其保留计数器的值不会发生改变。该对象只是被放入了NSAutoreleasePool当中。当自动释放池被销毁时,会向池中的所有对象发送release消息,所有被自动释放的对象都将其保留计数器的值减1。如果保留计数器的值归0了,则对象被销毁
对象初始化
分配对象
向某个类发送alloc消息,就能为类分配一块足够大的内存,以存放该类的实例变量。同时alloc方法还顺便将这块内存区域全部初始化为0,所有BOOL类型变量被初始化为NO,所有int类型变量被初始化为0,所有float类型变量被初始化为0.0,所有指针被初始化为nil。
请记住,self参数是通过固定距离寻找实例变量所在的内存为止的。如果init方法返回一个新对象,则需要更新self,以便其后的实例变量引用可以被影射到正确的内存位置。这也是需要使用self=[super init]这种形式进行赋值的原因,还要记住这个赋值操作只能影响该init方法中self的值,而不影响该方法范围以外的任何内容。
关键是要将[super init]返回值赋给self,我们建议一直使用if(self = [super init])这种技术,以确保安全并能捕获某些init方法“返回nil”的行为。
这个initWithContentsOfFile:encoding:error:方法用来打开指定路径上的文本文件,读取文件内容,并使用文件内容初始化一个字符串。读取文件/tmp/words.txt代码如下
NSError *error = nil;
NSString *string = [[NSString alloc] initWithContentsOfFile:@"/tmp/words.txt" encoding:NSUTF8StringEncoding error:&error];
初始化函数的一般规则是,假如对象必须使用某些信息进行初始化,那么你应该将这些信息作为init方法的一部分添加进来。
有的对象不是通过alloc ,copy ,new方法创建的,所以它的保留计数器值为1,而且我们可以认为它是自动释放的。因此自动释放池销毁时,该字符串对象也将被清理
我们在重载自己的dealloc方法时
当类中含有多个初始化方法时,类中的某个初始化方法被指派为指定初始化函数。该类的所有初始化都使用指定初始化函数中执行初始化操作,而子类使用其超类的指定初始化函数进行超类的初始化。通常接收参数最多的初始化方法是最终的指定初始化函数。
并不是一定要为自己的类创建初始化函数。如果不需要设置任何状态,或者alloc方法将内存清零的默认行为相当不错,则不必去在意init方法。
如果创建了一个置顶初始化函数,则一定要在自己的指定初始化函数中调用超类的指定初始化函数。
在Cocoa中,分配和初始化是两个分离的操作,来自NSObject类的方法alloc为对象分配一块内存区域并将其清零,实例方法init用于获得一个对象并使其运行。
@符号标志着“这是Objective-c语法”
@property预编译指令的作用是自动声明属性的setter和getter方法
@synthesize也是一种新的编译器功能,它表示“创建该属性的访问代码”。当遇到@synthesize rain;这行代码时,编译器将添加-setrain:和-rain:方法预编译代码。(在Xcode4.5以后的版本中,可以不必使用@synthesize了)
所有的属性都是基于变量的,所以在你合成(synthesize)getter和setter方法的时候,编译器会自动创建与属性名相同的实例变量
实例变量是声明在头文件还是实现文件?有什么区别呢
假设我有一个子类,并且想要从子类直接通过属性来访问变量。这种情况下,变量就必须放在头文件中,如果变量只属于当前类,则可以把它们放在.m文件里(并且要删除interface代码中的声明语句)
点表达式(.)如果点表达式出现在了=号的左边,该变量名称的setter方法将被调用,如果点表达式出现在了对象变量的右边,则该变量名称的getter方法将被调用。
点表达式只是调用相同访问方法的一种便捷方式。
点表达式通常出现在有属性的代码中,但是它只是调用对象的setter和getter方法的一种便捷方式。点表达式减少了需要键入的字符数量,而且也进一步方便了曾经使用其他语言的程序员
属性的名称始终与支持属性的实例变量名称相同。这种情况非常普遍,不过有时我可能会希望实例变量是一个名称,而公开的属性却是另一个名称。
@property (copy) NSString *name;
@property (retain) Engine *engine;
然后再修改@synthesuze指令:
@synthesize name = appellation;
编译器仍将创建-setName:和-name方法,但在其实现中用的却是appellation变量;
但如果我们不想要变量,getter和setter方法的话应该怎么做呢?
可以使用关键字@dynamic来告诉编译器不要生成任何代码或创建相应的实例变量。
@property属性只支持替代setter和getter方法,但是不支持那些需要额外接收参数的方法。
类别:
为已经存在的类添加行为时,通常采用创建子类的方法,类别是一种为现有的类添加新方法的方式
@interface NSString(NumberConvenience)
-(NSNumber *)lengthAsNumber;
@end
我们为NSString类添加了一个名为NumberConvenience的类别,只要保证类别名唯一,我可以像一个类中添加任意数量的类别。
与此相似,@implementation部分也爆亏类名,类别名以及新方法的实现。
@implementation NSString(NumberConvenience)
-(NSNumber *)lengthAsNumber
{
…;
}
@end
类别的缺陷:
1无法向类中添加新的实例变量,类别没有空间容纳新的实例变量
2名称冲突,也就是类别中的方法与现有方法重名,当冲突发生时,类别具有更高优先级,我的类别的方法将完全取代初始方法,导致初始方法不可用。
类别的优势:
1将实现代码分散到不同文件或框架中
2创建对私有方法的前向引用
3向对象添加非正式协议
4类别可以访问其继承的类的实例变量
对于为什么不想在类的@interface部分列出自己的全部方法,有许多充分的理由。这些方法可能只是纯粹的实现细节,我可能根据方法的名称来确定要使用哪个方法。
委托是一种对象,由另一个类执请求行某些操作。
selector:
什么是选择器(selector)?选择器只是一个方法的名称,但它以OC运行时使用的特殊方法编码,以快速执行查询。我可以使用@selector()编译指令圆括号中的方法名称来指定选择器。
NSObject提供了一个名为respondsToSelector:的方法,该方法询问对象以确定其是否能够响应某个特定消息。
Car *car = [[Car alloc] init];
if([car respondsToSelector:@selector(setEngine:)])
{
NSLog(@“123”);
}
选择器可以被传递,可以作为方法的参数使用,甚至可以作为实例变量被存储。这样可以生成非常强大和灵活的构造。
协议@protocol:
正式协议包含了方法和属性的有名称列表,正式协议要求显示地采用。采用协议的方法是在类的@interface声明中列出协议名称并用尖括号把协议名称括起来。采用以后,我的类就要遵守协议,承诺实现该协议的所有
方法,
例如:
@protocol NSCopying
@protocol后面是协议名称,协议名称必须唯一,也可以继承父协议,这点与继承父类类似。在
声明语句协议名称的后面的尖括号内可以置顶父协议的名称。
@protocol mySuperProtocol
@end
如果一个用尖括号括起来的协议名称跟随在id之后,则编译器会知道我接收任意类型的参数,但前提是遵守该协议。
委托/代理(delegate):
就是某个对象指定另一个对象处理某些特定任务的设计模式;
这里把代理设置为self所属的这个类,当Delegate属性调用协议中的方法时,就会调用被设置为代理并遵守协议的self这个类中实现的协议中的方法
[_pNetworkEX setDelegate:self];
代理由发起委托的类声鸣遵守协议的property,然后由self这个被委托的类来实现协议中的方法。 然后在发起委托的类中调用协议中的这个方法
car = [[[self class] allcoWithZone:zone]init];
这条语句是获得self参数所属的类,然后向self对象所属的类发送allocWithZone:消息,以分配内存并创建一个该类的新对象。最后发送init消息时期初始化。
GUI想用可以切换的界面可以使用Tab view部件
代码块:
代码块对象是对C语言中函数的扩展。除了函数中的代码,代码块还包含变量绑定。
一般用如下关系来表示
(^blockname)(list of arguments) = ^(arguments){ body;};
编译器可以通过代码块内容推导出返回类型,所以我可以省略它。如果代码块,没有参数也可以省略。
线程编程小例子
[self performSelectorInBackground:@selector(startCycleTest) withObject:nil];
这条语句创建一个线程用来执行选择器里的方法。
}
因为图形界面的更新动作必须在主线程里执行,所以我选用在主队列里执行更新界面的代码,
这样界面不会卡顿。
MD5/SHA1用法示例
//interface 部分
#import
#include
@interface AiChecksum : NSObject
{
}
/**
/**
//实现部分
#import “AiChecksum.h”
@implementation AiChecksum
//md5-hash
+(NSString *)md5HashOfPath:(NSString *)path
{
NSFileManager *fileManager = [NSFileManager defaultManager];
// Make sure the file exists
if( [fileManager fileExistsAtPath:path isDirectory:nil] )
{
NSData *data = [NSData dataWithContentsOfFile:path];
unsigned char digest[CC_MD5_DIGEST_LENGTH];
CC_MD5( data.bytes, (CC_LONG)data.length, digest );
NSMutableString *output = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
for( int i = 0; i < CC_MD5_DIGEST_LENGTH; i++ )
{
[output appendFormat:@"%02x", digest[i]];
}
return output;
}
else
{
return @"";
}
}
//sha1 hash
+(NSString *)shaHashOfPath:(NSString *)path
{
NSFileManager *fileManager = [NSFileManager defaultManager];
// Make sure the file exists
if( [fileManager fileExistsAtPath:path isDirectory:nil] )
{
NSData *data = [NSData dataWithContentsOfFile:path];
unsigned char digest[CC_SHA1_DIGEST_LENGTH];
CC_SHA1( data.bytes, (CC_LONG)data.length, digest );
NSMutableString *output = [NSMutableString stringWithCapacity:CC_SHA1_DIGEST_LENGTH * 2];
for( int i = 0; i < CC_SHA1_DIGEST_LENGTH; i++ )
{
[output appendFormat:@"%02x", digest[i]];
}
return output;
}
else
{
return @"";
}
}
//用法
#import “AiChecksum.h”
NSString *fullPath = @""; // do whatever you need to get the full path to your file
NSString *md5 = [AiChecksum md5HashOfPath:fullPath];
NSString *sha1 = [AiChecksum shaHashOfPath:fullPath];
NSLog( @“MD5: %@”, md5 );
NSLog( @“SHA1: %@”, sha1 );
//对NSString做sha1
(NSString *)sha1:(NSString *)str
{
NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding];
uint8_t digest[CC_SHA1_DIGEST_LENGTH];
CC_SHA1(data.bytes, (CC_LONG)data.length, digest);
NSMutableString *output = [NSMutableString stringWithCapacity:CC_SHA1_DIGEST_LENGTH * 2];
for (int i = 0; i < CC_SHA1_DIGEST_LENGTH; i++)
{
[output appendFormat:@"%02x", digest[i]];
}
return output;
}
plist文件里面直接输入\n换行字符是不行的,XCODE会自动加入\导致实际字符不是换行符,输入的方法应该是alt/option键+enter/return键(回车键)
Mac自带的软件Activity monitor这个软件可以看到在跑的后台
Type Alias
NSStringEncoding
The following constants are provided by NSString as possible string encodings.
These values represent the various character encodings supported by the NSString classes. This is an incomplete list. Additional encodings are defined in String Programming Guide for Core Foundation (see CFStringEncodingExt.h); these encodings can be used with NSString by first passing the Core Foundation encoding to the CFStringConvertEncodingToNSStringEncoding function.
Topics
Constants
NSASCIIStringEncoding
Strict 7-bit ASCII encoding within 8-bit chars; ASCII values 0…127 only.
NSNEXTSTEPStringEncoding
8-bit ASCII encoding with NEXTSTEP extensions.
NSJapaneseEUCStringEncoding
8-bit EUC encoding for Japanese text.
NSUTF8StringEncoding
An 8-bit representation of Unicode characters, suitable for transmission or storage by ASCII-based systems.
NSISOLatin1StringEncoding
8-bit ISO Latin 1 encoding.
NSSymbolStringEncoding
8-bit Adobe Symbol encoding vector.
NSNonLossyASCIIStringEncoding
7-bit verbose ASCII to represent all Unicode characters.
NSShiftJISStringEncoding
8-bit Shift-JIS encoding for Japanese text.
NSISOLatin2StringEncoding
8-bit ISO Latin 2 encoding.
NSUnicodeStringEncoding
The canonical Unicode encoding for string objects.
NSWindowsCP1251StringEncoding
Microsoft Windows codepage 1251, encoding Cyrillic characters; equivalent to AdobeStandardCyrillic font encoding.
NSWindowsCP1252StringEncoding
Microsoft Windows codepage 1252; equivalent to WinLatin1.
NSWindowsCP1253StringEncoding
Microsoft Windows codepage 1253, encoding Greek characters.
NSWindowsCP1254StringEncoding
Microsoft Windows codepage 1254, encoding Turkish characters.
NSWindowsCP1250StringEncoding
Microsoft Windows codepage 1250; equivalent to WinLatin2.
NSISO2022JPStringEncoding
ISO 2022 Japanese encoding for email.
NSMacOSRomanStringEncoding
Classic Macintosh Roman encoding.
NSUTF16StringEncoding
NSUTF16BigEndianStringEncoding
NSUTF16StringEncoding encoding with explicit endianness specified.
NSUTF16LittleEndianStringEncoding
NSUTF16StringEncoding encoding with explicit endianness specified.
NSUTF32StringEncoding
32-bit UTF encoding.
NSUTF32BigEndianStringEncoding
NSUTF32StringEncoding encoding with explicit endianness specified.
NSUTF32LittleEndianStringEncoding
NSUTF32StringEncoding encoding with explicit endianness specified.
NSProprietaryStringEncoding
Installation-specific encoding.
@interface
NSMutableDictionary * _axes;
NSMutableDictionary * _inputs;
NSMutableDictionary * _outputs;
}
@property (readonly) BOOL IsStop;
@property (readonly) BOOL IsOpen;
@property NSTimeInterval updateInterval;
//和上面的不一致因为在声明不是一个对象 经过@synthesize axes = _axes;这条语句后 setaAxes和axes方法中用的是_axes(NSMUtableDictionary) 这样类外部不能修改axes这些属性而类内部可以修改
@property (readonly) NSDictionary* axes;
@property (readonly) NSDictionary* inputs;
@property (readonly) NSDictionary* outputs;
@implementation
@synthesize IsStop, IsOpen, updateInterval;
@synthesize axes = _axes;
@synthesize inputs = _inputs;
@synthesize outputs = _outputs;
-(id)init
{
_axes = [[NSMutableDictionary alloc] init];
}