Objective-C零碎知识点
OC总结
[TOC]
零碎百科
1.类的命名应当使用匈牙利标识(Hungarian Notation),每个字母开头大写。
2.方法的命名应当使用驼峰标识(Camel Notation),首个单词小写,后面的单词首字母大写其他小写,在oc初始化方法中如果不使用驼峰标识可能报错,默认是不是初始化方法。
3.C语言字符串(字符数组)在OC中的赋值不能使用= 要使用字符串拷贝函数(在oc中使用char用strcpy)
4.减少代码中的硬代码(hord code),硬代码很难维护,并且减少硬代码程序可读性更强,静态常量使用:static const 类型 全大写用下滑线连接下一个单词,计算公式之类的可以使用宏定义。
5.API - Application Programming Interface (应用程序编程接口)
6.自动释放池(在自动释放池中创建的对象由自动释放池托管 离开自动释放池自动释放),如果一个对象没有指针指向它就成了垃圾对象会被系统自动清理,程序员只管分配内存不管释放内存(ARC - 自动引用计数).
7.for-in循环需要对每个元素进行遍历(除非用break终止循环),只读循环,在循环过程中不能够修改数组中的元素.
8.不要在头文件中包含自定义类的头文件 因为可能导致循环包含头文件的问题,如果类的声明部分使用了其他自定义类型 可以做一个向前引用声明.
9.方法声明前面如果是- 说明该方法是对象方法 需要创建对象来调用.
10.方法声明前面如果是+ 说明该方法是类方法 用类名直接调用.
11.三目运算符,猫王运算符:?
12.oc中的*即使指针也是引用。
13.求a,b,c三条边三角形的面积,使用海伦公式
duoble p = (a + b + c) / 2;
duobel area = sqrt(p * (p - a) * (p - b) * (p - c));
14.当不知道起什么名字的时候: foo - fuck up bar - beyond all recognization
15.RTTI 运行时类型识别 RunTime Type Identification)
16.神语录: 在计算机的世界里时间和空间是不可调和的矛盾,如果想赢得时间就要牺牲空间,如果想节省空间就会浪费时间
- ASCII 1字节 - 字母、数字、符号、控制字符
Unicode 2-4字节不等 万国码
GB2312 - 国标码
GBK - 国标扩
GB18030
18.为什么复制了还要返回当前对象的指针? 级联编程(开火车式编程)
19.plist文件,是XML(eXtensible Markup Language 可扩展标记语言)格式存储数据
20.NSDate对象的timeIntervalSinceDate:可以计算出两个日期之间相差多少秒
21.内存管理原则:能不用MRC就不用
谁创建谁释放 +1 操作和 -1 操作必须成对出现
如果使用手动内存管理(MRC)需要了解四个方法
1.retain 对象引用计数+ 1
2.release 对象引用计数 - 1
3.retainCount 查看对象引用计数值
4.autorelease 当使用了自动释放池可以由自动释放池自动释放内存而不用再调用release方法
22.// @synthesize a = _a;
// 属性合成:产生和属性对应的成员变量、修改器和访问器,系统默认会对属性进行自动合成
协议(Protocol)
- 协议委托和Block的使用
协议表能力,表约定,表角色
@protocol 协议名 <NSObject>
// 只有声明没有实现
// 相关方法的集合
@end
Objective-C的响应机制 不看指针只看对象
- Objective-C采用了动态继承编译机制。动态编译机制就是说在编译时不能确定类之间的继承关系。只有在运行时才确立类之间的继承关系。正因如此,也不能在编译时确定类的大小,自然也就不能将类的对象创建在栈中。
类、对象、消息
- 类:类是对一组具有共同属性和行为的对象的抽象,它是对象的蓝图和模板
定义一个类要做两件事情:
数据抽象 --- 属性(名词)
行为抽象 --- 方法(动词)
- 类和类之间的关系简单的说有三种:
IS-A 继承
HAS-A 关联
USE-A 依赖
属性修饰符
-
多线程特性:nonatomic和atomic
-
读写特性:readwrite和readonly
-
内存管理器:strong(普通对象指针,retain的代替平)、weak(插座变量,不需要管理生命周期的对象,可能导致循环引用的指针,代理对象的指针)、copy(NSString和block)、assign(基本数据类型)、retain、unsafe_unretain
-
修改器和访问器:setter 和getter
-
对象:对象是独一无二的,都有属性和行为,对象属于某个类,是一个具体的接受消息的单元
比方说我们建一个学生类(抽象),那么具体某个学生就是对象(具体)
- 消息:对象与对象之间的联系通过消息来传递,程序中的一切操作就是依靠给对象发送消息来实现,对象接收到消息就会调用有关对象的行为来完成相应的操作。
面向对象的三大支柱
1.封装:我们定义一个类相当于封装了数据结构和操作数据的过程,让它们形成一个逻辑上的整体。
2.继承:从一个已经有的类创建新类的过程就叫做继承。提供继承信息的类成为父类(超类、基类);得到继承信息的类成为子类(派生类、衍生类)。通过继承我们可以让子类复用父类的代码(不在需要每个子类书写和父类相同的重复代码),与此同时我们可以创建子类对系统的功能提供了增强(子类是对父类的扩展和增强)
3.多态:子类继承父类的方法后,可以给父类的方法给出新的实现版本,这一过程称为方法的重写(也称为方法覆盖或方法置换)。由于不同的子类对父类的方法进行重写是可以给出各自的实现版本,同样的对象指针,接收到同样的消息,但是做了不同的事情,这就是多态。
如何实现多态(polymorphism)
- 方法重写: 在继承的过程中子类重写(override)父类方法 不同的子类给出不同的实现版本
- 对象造型: 用父类型的指针指向子类对象
访问对象属性及修饰符
- @private:私有的,对外界来说是不可见的
- @protected:受保护的,对子类相当于公开,对其他类相当于私有。(默认)
- @public:公开,对外界来说是可见的
常用的基础类
字符串
NSString
1.length:字符串长度。
2.characterAtIndex:截取哪个位置的单个字符串,%C连接。
3.stringWithFormat:连接字符串。
4.substringFromIdex:截取从哪个位置开始的一个子串。
5.isEqualToString:比较两个字符串是否相同
6.stringWithString:返回相同的字符串(把不可变的字符串编程可变的字符串)
NSString是不变的字符串任何对字符的修改操作都会创建新的字符串对象,而不是在原来的字符串对象上修改。
跑马灯示例
// 下面的代码实现了跑马灯效果
NSString *str = @"欢迎来到vistaWorld学习.....";
//
while (1) {
// 字符串的stringWithFormat:方法可以通过指定的格式串来创建并初始化一个字符串对象
// 字符串的substringFromIndex:方法是从指定位置取子串
// 字符串的characterAtIndex:方法是取指定位置的字符
str = [NSString stringWithFormat:@"%@%C", [str substringFromIndex:1], [str characterAtIndex:0]];
// NSLog(@"1%@1",[str substringFromIndex:1]);
// NSLog(@"0%C0",[str characterAtIndex:2]);
// 字符串的UTF8String方法将Objective-C的字符串(NSString *)变成C的字符串(char *)
printf("%s\n", [str UTF8String]);
usleep(100000);
}
NSMutableString
- NNString的子类,兼容它的所有方法
数组
- OC的数组是对象 在内存中的堆(heap)上
- 数组和字典都是对象的持有者,可以用来存储其他对象的地址,数组是按相邻关系的组织数据的,而字典是通过键值对映射来组织数据的。
NSArray
- 创建的时候直接赋值分配了内存
- NSArray和C数组的区别:NSArray中只能存放对象的指针,不能存放基本数据的元素值。可以用NSNumber包装基本数据类型或使用C语言的数组来存放基本数据类型的元素。(通知方向传一个基本数据的时候)
1.firstObject:第一个元素指针
2.lastObeject:最后一个元素对象的指针
3.objectAtIndes:去指定索引的对象
4.arrayByAddingObject:/arrayByAddingObjectsFromArray:将元素或数组添加到数组中并返回新的数组
5.count:数组的个数
6.componentsSeparatedByString:用指定的字符拆开字符串返回一个数组
NSString *str10 = @"You go your way, I will go mine!";
// 下面的方法用指定的字符集对字符串进行拆分得到一个数组
// 应用场景: 将句子拆分成单词
NSArray *words = [str10 componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@", !"]];
for (NSString *tempStr in words) {
NSLog(@"%@", tempStr);
}
// 处理字符串最重要的工具是正则表达式
NSArray *unharmoniousContents = @[@"操", @"Fuck", @"fuck", @"FUCK"];
NSString *str11 = @"操你大爷。Fuck you!";
for (NSString *tempStr in unharmoniousContents) {
// 将字符串中指定内容替换成另外的内容
// 应用场景: 构建和谐社会屏蔽不良内容
str11 = [str11 stringByReplacingOccurrencesOfString:tempStr withString:@"*"];
}
NSMutableArray
- 需要alloc来分配内存
- NSArray的子类,兼容它
1.addObject:添加对象
2.insertObject atIndex/ insertObjects atIndexes:在那个对象的位置插入对象
3.removeObject:/removeAllObjects/removeLastObject/removeObjectAtIndex:/removeObjectsIn Range:移除对象
4.arrayWithArray:?
5.replaceObjectAtIndex:withObject:/setObject:atIndexedSubscript:/setArray: 替换数组中的元素
5.直接copy转换成不可变数组
NSRange
1.rangOfString:方法在字符串中查找有没有某个子串
2.NSRange是一个结构体 它包括了location(位置)和length(长度)两个成员
3.如果location的值是NSNotFound就表示没有找到指定的子串
4.应用场景: 搜索和替换
5.substringWithRange:方法截取字符串指定范围的子串
NSDictionary
1.字典是存放键值对组合的容器 也就是说字典容器中的每个条目都是由一个键和一个字构成的 键在前值在后中间是冒号 条目之间用逗号分隔
2.setObeject forKey:添加元素
3.allkeys:所有的键
4.removeObejectForKey:从字典中删除元素
文件的操作
数据持久化
数据的持久化就是将数据从内存中转移到持久存储介质(通常是硬盘)中,使用文件系统存储数据是最常见的持久化方案
在Objective-C开发中,我们将对数据结构转换成NSData类对象的过程成为归档,也成为数据的序列化;相反的过程称之为解归档,也称为数据的反序列化。如果一个类的对象需要归档和解归档,那么该类必须要遵循NSCoding协议,我们使用的NSString,NSArray,NSDuctionary遵循这个协议,因此可以进行归档和解归档。
如果对象中关联了其他对象 如果在归档时要对关联的对象进行归档, 那么关联的对象也必须遵循NSCoding协议才能进行归档,否则程序会崩溃
NSCoding协议有两个方法:
1.一个用于对象属性的编码:- (void)encodeWithCoder:(NSCoder *)aCoder
- (void) encodeWithCoder:(NSCoder *)aCoder {
if (aCoder) {
[aCoder encodeObject:_name forKey:@"name"];
}
}
2.一个用于对象属性的解码:- (id)initWithCoder:(NSCoder *)aDecoder;
所以只有遵循了该协议的对象才能进行归档和解归档 - (instancetype) initWithCoder:(NSCoder *)aDecoder {
if (self = [super init]) {
if (aDecoder) {
_name = [aDecoder decodeObjectForKey:
@"name"];
}
}
return self;
}
归档器(NSKeyedArchiver)和解归档器(NSKeyedUnarchiver)
示例:
#if 0
CDStudent *stu1 = [[CDStudent alloc] init];
stu1.name = @"王大锤";
stu1.age = 24;
stu1.car = [[CDVehicle alloc] initWithBrand:@"BMW" autoTransmission:YES maxSpeed:320];
CDStudent *stu2 = [[CDStudent alloc] init];
stu2.name = @"张大成";
stu2.age = 19;
stu2.car = [[CDVehicle alloc] initWithBrand:@"三蹦子" autoTransmission:NO maxSpeed:15];
NSArray *array = @[stu1, stu2];
// 将学生对象的状态写入存储设备的过程叫归档
// 从存储设备中将学生对象的状态读取出来的过程叫解归档
// 归档和解归档在有的地方称为序列化和反序列化
// NSMutableData对象相当于一个数据中转站
NSMutableData *mData = [NSMutableData data];
// 创建归档器
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:mData];
// 将学生对象进行归档编码并指定对应的键
[archiver encodeObject:array forKey:@"array"];
// 结束归档编码(学生对象的数据已经编码到mData对象中)
[archiver finishEncoding];
// 将归档数据写入文件中完成持久化
[mData writeToFile:@"/Users/Hao/Desktop/data" atomically:YES];
#endif
#if 1
// 将归档文件的数据加载到内存中
NSData *data = [NSData dataWithContentsOfFile:@"/Users/Hao/Desktop/data"];
// 创建解归档器
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
// 通过指定的键将对象解归档出来
NSArray *array = [unarchiver decodeObjectForKey:@"array"];
for (CDStudent *stu in array) {
NSLog(@"姓名: %@", stu.name);
NSLog(@"年龄: %ld", stu.age);
[stu study];
[stu drive];
}
#endif
}
return 0;
}
NSFileManager
- 文件的操作
/ 获得默认的文件管理器对象
NSFileManager *manager = [NSFileManager defaultManager];
// 删除文件
NSLog(@"%@", [manager removeItemAtPath:@"/Users/Hao/Desktop/abc.txt" error:nil]? @"删除成功": @"删除失败");
// NSData代表一组二进制数据的对象
// 提示: 下面的代码是联网获得数据如果网络不给力可能得到nil后者代码会在此处卡一段时间
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://10.0.8.8/sns/attachment/201505/12/123669_1431421013Nw4a.jpg"]];
// 用指定的二进制数据创建文件对象
// 如果第二个参数是nil则创建一个空文件
NSLog(@"%@", [manager createFileAtPath:@"/Users/Hao/Desktop/你好" contents:data attributes:nil]? @"创建成功":@"创建失败");
// 创建文件夹
// 如果第二个参数是YES则会在上级文件夹不存在时依次创建出上级文件夹再创建当前指定的文件夹
NSLog(@"%@", [manager createDirectoryAtPath:@"/Users/Hao/Desktop/abc/def/小狗屎" withIntermediateDirectories:YES attributes:nil error:nil]? @"创建文件夹成功": @"创建文件夹失败");
// 移动(剪切)文件夹
[manager moveItemAtPath:@"/Users/Hao/Desktop/abc/def/小狗屎" toPath:@"/Users/Hao/Desktop/x/shit" error:nil];
// 删除文件夹
[manager removeItemAtPath:@"/Users/Hao/Desktop/b" error:nil];
}
return 0;
NSFileHandle:句柄
- 文件内容的操作
- NSFileHandle:句柄(指针)fileHandleForUpdatingAtPath更新文件
NSArray *myarray = @[@"hello", @"good", @"simple", @"shit"];
myarray = [myarray sortedArrayUsingSelector:@selector(compare:)];
NSLog(@"%@", myarray);
// handle - 句柄(指针)
NSFileHandle *handler = [NSFileHandle fileHandleForUpdatingAtPath:@"/Users/Hao/Desktop/hello.txt"];
// NSLog(@"文件有: %ld字节", handler.availableData.length);
// 读取6个字节
// NSData *data = [handler readDataOfLength:6];
// NSLog(@"%@", data);
// NSLog(@"文件有: %ld字节", handler.availableData.length);
// NSLog(@"%@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
NSMutableData *mData = [NSMutableData data];
[mData appendData:[@"面朝电脑\n" dataUsingEncoding:NSUTF8StringEncoding]];
[mData appendData:handler.availableData];
// 将文件指针移到文件开头的位置
[handler seekToFileOffset:0];
[handler writeData:mData];
#if 0
NSString *str = @"good good girls";
NSData *newData = [str dataUsingEncoding:NSUTF8StringEncoding];
[handler writeData:newData];
// 将文件指针移到文件的末尾
[handler seekToEndOfFile];
// fopen/fclose/fseek/fread/fwrite/ftell
NSData *zhData = [@"我爱你们" dataUsingEncoding:NSUTF8StringEncoding];
// 将数据写入文件
[handler writeData:zhData];
#endif
}
return 0;
}
JSON及其数据解析
JSON全称JavaScript Object Notation(JavaScript对象表达式),是目前最多的存储和交换文本信息的语法,比XML更小更快更易解析,是一种轻量级的文本数据交换格式
JSON的语法规则
- 数据在名/值对中
- 数据由逗号分隔
- 花括号保存对象
- 方括号保存数组
- JSONObjectWithData:option:error:
- NSDictionary / NSArray
KVC
- setValue:forKey:
setValuesForKeysWithDictionary:
通常需要重写setValue:forUndefinedKey:方法
.h实体类(模型类 - 数据模型 只有属性没有业务逻辑方法
@property (nonatomic, assign) NSUInteger wid;
.m- (void) setValue:(id)value forKey:(NSString *)key {
// 对于属性和JSON数据类型不匹配的情况需要手动转换
if ([key isEqualToString:@"wid"]) {
self.wid = [value integerValue];
}
else {
// 对于不需要类型转换的键值对组合直接使用KVC赋值
[super setValue:value forKey:key];
// 不能写下面的代码否则会因为递归调用不收敛导致栈溢出
// [self setValue:value forKey:key];
}
// 提示: 使用KVC大招时一定重写此方法
-(void)setValue:(id)value forUndefinedKey:(NSString *)key {
// 在使用KVC时通常都需要重写此方法来处理不能识别的key
// 如果JSON数据中的键和类的属性名不匹配可以通过下面的字典进行转换
NSDictionary *keyPropDict = @{@"wpic_large": @"largePicUrl", @"update_time": @"updateTime"};
// 如果JSON中的键在类中有与之对应的属性才使用KVC给该属性赋值
// 如果没有对应的属性就什么都不要做
if (keyPropDict[key]) {
[self setValue:value forKey:keyPropDict[key]];
}
}
匿名类别
- 定义:// 匿名类别(Anonymous Category) - 类扩展
@interface 类名()
// 此处可以放置类私有的东西
@end
Block
-
Block的用法跟C语言中指向函数的指针用法几乎一致
-
定义方法一:
定义Block类型的属性(用来保存一段回调代码) 属性修饰符必须写copy因为要从栈将Block拷贝到堆上 typedef (返回参数,可为空)(^block名)(数据类型); block名 参数
面向对象的编程原则
-
单一职责原则(SRP): 设计一个类应该只围绕一个主题或中心思想服务;设计一个方法应该只做好一件事情。
-
开闭原则(OCP): 好的软件实体只接受扩展不接受修改。抽象是关键,用继承结构封装可变性(隔离程序中不同的可变因素)。
-
依赖倒转原则(DIP): 要面向抽象编程不要面向实现编程。声明指针变量的类型、方法的参数类型、方法的返回类型时尽可能使用父类型指针或协议指针(id<协议>),不要使用具体类型(子类型)指针。
爱人,待周爱人而后为爱人--- 《墨子·取周》
蛋 *x = nil;
- (void) foo:(蛋 *) egg;
- (蛋 *) bar;
- 里氏替换原则(LSP): 任何时候用子类对象替换父类型对象都是可以的,但是反过来通常是不成立的。子类能力比父类能力更多,用能力多的替换能力少的当然可以,反之未必成立。
白马 马也 乘白马 乘马也
黑马 马也 乘黑马 乘马也
娣 美人也 爱娣 非爱美人
盗 人也 恶盗 非恶人也 ---《墨子·小取》
-
接口隔离原则(ISP): 协议小而专,不能大而全。不能够将不相关的方法组织到一个协议中,这样会模糊协议所表示的角色。
-
合成聚合复用原则(CARP) : 优先考虑用强关联关系复用代码而不是使用继承。
IS-A --- 继承
HAS-A --- 关联 ---> 聚合 ---> 合成
USE-A --- 依赖
- 迪米特法则(LoD): 不要和陌生人讲话。除非是必须发生联系的对象,否则不要让对象之间发生联系。
邱越 - 庄 - Mr.Song - Mr.Lee - DG - Xi Jinping - 奥巴马
小国寡民,鸡犬相闻,民至老死,不相往来
XML
XML全称eXtensible Markup Language(可扩展标记语言),设计用来传输和存储数据。是异构系统之间交换数据的事实标准,是一种具有自我描述能力的传输数据的语言。
XML文档形成的是一种树形结构,它必须包含根元素,该元素是所有其他元素的父元素,这棵树从根部开始,并扩展到树的最低端。
XML的语法规则
- 所有的XML芫荽都必须有一个关闭标签
- XML标签对于大小写敏感
- XML文档必须有根元素
- XML属性值必须加引号
- XML中的特殊字符要使用实体引用
- XML中的注释是
解析XML数据文件主要有两种方式:
- SAX --- 顺序解析 事件驱动(遇到标签、属性、内容都会引发相应的事件执行事件回调来处理XML文件中的数据)
- DOM (Document Object Model) --- 支持XPath查找,可以动态的增加删除修改节点,占用内存较多
HTTP协议入门
- 超文本传输协议,基于TCP协议的应用层协议
- HTML (Hyper-Text Markup Language) 标签语言
- HTTP请求和响应
- 请求格式:请求行 请求头 消息体
- 响应格式:响应行 响应头 消息体
回调方法(callBack)
- SEL理解是给能够响应的对象绑定一个方法,返回值为空。
- 如果知道做什么但是不知道什么时候发生都应该用回调方法,简洁代码,发生响应。
- oc—>selector/Block/指向函数的指针/协议委托
匿名类别(类扩展)
- 通过匿名类别来声明私有化的成员变量(也可以声明在实现部分),前置声明私有化的成员方法(现在私有化的成员方法可以不前置声明),声明私有化的属性(比较常用)。
类别(category)
1.当我们使用苹果第三方库感觉这个类再有一个方法就好了,这个时候我们就可以选择给类打一个补丁。
2.source->Objective-C File->Category->选择要打的类别
拼接和拆分URL示例
#import <Foundation/Foundation.h>
@interface NSString (FormatURL)
// 拼接URL参数
+ (NSString *)formatURL:(NSString *) url params:(NSDictionary *) params;
// 拆分URL参数
+ (NSDictionary *)splitURL:(NSString *) url;
@end
#import "NSString+FormatURL.h"
@implementation NSString (FormatURL)
// http://chaosky.me -> http://chaosky.me?xx=xxx&xxx=xx
// http://chaosky.me?xxx=xxx -> http://chaosky.me?xxx=xxx&xxx=xx&xx=x
+ (NSString *)formatURL:(NSString *)url params:(NSDictionary *)params
{
NSMutableArray * paramArray = [NSMutableArray array];
// 遍历字典
for (NSString * key in params.allKeys) {
NSString * paramString = [NSString stringWithFormat:@"%@=%@", key, params[key]];
[paramArray addObject:paramString];
}
NSString * paramsStr = [paramArray componentsJoinedByString:@"&"];
// 定义拼接好的URL地址
NSMutableString * formatURL = [NSMutableString stringWithString:url];
// 判断当前URL地址是否已存在参数列表
NSRange range = [url rangeOfString:@"?"];
if (range.location != NSNotFound) {
[formatURL appendFormat:@"&%@", paramsStr];
}
else {
[formatURL appendFormat:@"?%@", paramsStr];
}
return formatURL;
}
+ (NSDictionary *)splitURL:(NSString *)url
{
// 找到?位置
NSRange paramRange = [url rangeOfString:@"?"];
if (paramRange.location != NSNotFound) {
// 获取参数列表
NSString * paramStr = [url substringFromIndex:paramRange.location + 1];
// 按字符拆分数组
NSArray * paramArray = [paramStr componentsSeparatedByString:@"&"];
// 将数组中字符串拆分
NSMutableDictionary * paramDict = [NSMutableDictionary dictionary];
for (NSString * param in paramArray) {
// 将字符串拆分为数组
NSArray * keyValue = [param componentsSeparatedByString:@"="];
paramDict[keyValue[0]] = keyValue[1];
// paramDict setValue:<#(nullable id)#> forKey:<#(nonnull NSString *)#>
}
return [paramDict copy];
}
else {
return nil;
}
}
@end
那些觉得好玩的案例
加密解密
#import <Foundation/Foundation.h>
static const int KEY = 100; // 加密和解密使用的密钥
int main(int argc, const char * argv[]) {
@autoreleasepool {
// NSString *str = @"扵牕伄"; // 加密后的字符串
// NSString *mStr = @"";
// for (int i = 0; i < [str length]; i++) {
// unichar ch = [str characterAtIndex:i];
// ch = ch ^ KEY;
// mStr = [mStr stringByAppendingFormat:@"%C", ch];
// }
// NSLog(@"%@", mStr);
NSString *str = @"不再见";
NSString *mStr = @"";
for (int i = 0; i < [str length]; i++) {
unichar ch = [str characterAtIndex:i];
ch = ch ^ KEY;
mStr = [mStr stringByAppendingFormat:@"%C",ch];
NSLog(@"%@",mStr);
}
NSLog(@"%@", mStr);
}
return 0;
}