一 类
1.类和对象的定义
成员变量的声明
NSString * _变量名
成员变量的Setter和Getter方法
一个类可以有多个构造方法
构造方法(作用是初始化一个类)
无参构造方法
- (id/类名 */) init {};
有参构造方法
- (id/类名 */) initWith…. {};
类方法
类方法不可访问成员变量
不可以调用对象方法
作用
创建对象
+ (id)defualtClass{
Dog *dog =[ [Dog alloc] init];
….
[dog release];
}
通过类方法可以对外暴露一个功能模块的接口
[Dog start];
+ (id) start{
Dog *dog =[ [Dog alloc] init];
….
[dog release];
}
创建单例对象
+ (Dog *) defaultDog{
static Dog * dog = nil;
if (dog ==nil){
dog = [[Dog alloc] init] ;
}
return dog;
}
+ (Dog *)defaltDog {
//声明一个Dog类的静态指针,存储在数据段,默认为空
static Dog * dog;
if (!dog) {
//如果dog为空时,才创建dog对象
dog = [[Dog alloc] init];
}
//这个方法只有在第一次调用时,才开辟空间,创建对象
//以后调用,得到的都是第一次调用时创建的对象,是同一个对象,所有指针指向同一个地址
//这个方法会创建出单例对象
return dog;
}
类别
1.类别可以添加对象方法和类方法
2.类别不可以添加成员变量
3.用类别添加到某个类方法,就如同添加到原类中一样
4.类别添加的方法可以访问成员变量
5.父类中用类别添加的方法,子类也可以用
二 字符串操作
不可变字符串
字符串创建
NSString * str = @"ada";
NSString * str1 = [[NSString alloc] initWithString:@"fsf"];
Format可以实现字符串拼接
NSString * str2 = [[NSString alloc] initWithFormat:@"dfsf,%f",3.0];
将C字符串转化为OC字符串
NSString * str3 = [[NSString alloc] initWithUTF8String:"vsfsg"];
每个alloc+init方法,否有对应的方法
NSString * str1 = [[NSString StringWithString:@"fsf"];
NSString * str2 = [[NSString StringWithFormat:@"dfsf,%f",3.0];
NSString * str3 = [[NSString StringWithUTF8String:"vsfsg"];
OC字符串与基础数据类型的转换
floatValue
intValue
integerValue
boolValue
获取字符串长度
[str length]
获取字符串制定位置的字符
[str characterAtIndex:i]
字符串常用操作
比是否相等
[a isEqualToString:b] (返回值是Bool)
比大小
[a compare:b] (0,相等;1,a>b;-1,a<b)
提取子串
[father subStringFromIndex:5] from 闭区间
[father subStringToIndex:3] to 开区间
[father subStringWithRange:NSMakeRange(4,5)] 第一个数定位,第二个数表示取得长度
改变大小写
uppercaseString
lowercaseString
判断某个字符串是否是以另一个字符串开头或者是结尾
hasPrefix 开头
hasSuffix 结尾
可变字符串
重置字符串
[str setString:]
追加
[str appendString:]
插入
[str insertString:]
删除
[str deleteCharacterInRange:NSMakeRange(location.length)]
修改
[str replaceCharacterInRange:NSMakeRange(location,length) withString:]
字符串分割
[str componentsSeparatedByString:](以单个字符分割)
[str componentsSparatedByCharactersInSet:[NSCharacterSet characterSetWithCharatersInString:]](以多个字符分割)
数组元素拼接
[arr componentsJoinedByString:]
三 数组
数组的常用方法
获取数组下标
[arr objectAtIndex:]
取数组尾元素
[arr lastObject]
获取数组元素个数
[arr count]
获得某个下标的元素
[arr objectAtIndex:]
重置数组
[arr setArray:]
追加
[arr addObject:]
插入
[arr insertObject: atIndex:]
按照下标删除
[arr removeObjectAtIndex:]
[arr removeObject:]
删除所有元素
[arr removeAllObjects]
删除最后一个
[removeLastObjct]
替换
[arr replacrObjectAtIndex: withObject:]
交换位置
[arr exchangeObjectAtInde: withObjectAtIndex:]
增加元素
[arr addObject:]
[arr addObjectsFromArray:]
四 字典
传入键,取值
[dic objectForKey:]
获取键值对数
[dic count]
得到所有的键
[dic allKeys]
得到所有的值
[dic allValues]
重置字典
[dic setDictionary]
增加
[dic setObject: forKkey:]
删除
[dic removeObjectForKeys:]
删除所有键值对
[dic removeAllObjects]
比较字符串大小
[str compare:str2]
[str isEqualToString:str1]
五 选择器
SEL sel = @selector(run);
这个方法用于编译时就能确定调用的方法
SEL sel = NSSelectorFromString(@"run");
这个方法用于运行时确定调用的方法
选择器定义
@selector把参数中的消息(crash),转化为选择器常量,存储到了SEL变量
SEL sel = @selector(crash);
选择器实现
[对象 performSelector: ]
[对象 performSelector: withObject:]
performSelector方法最多只支持2个参数
如果有两个以上的参数,可以自己封装一个数据存储类,信息存储类里面有多个成员变量,传参的时候穿一个对象就可以了
可以传一个数组或者字典,如果传的是个字典的话,字典的键就得事先约定好
SEL sel2 = @selector(invesAPerson:);
NSDictionary * dic = @{@"name":@"博雅·汉库克", @"sex":@"女", @"motto":@"我要嫁给路飞"};
消息实现:
– (void)invesAPerson:(NSDictionary *)infoDic {
NSString * name = infoDic[@"name"];
NSString * sex = infoDic[@"sex"];
NSString * motto = infoDic[@"motto"];
NSLog(@"姓名: %@, 性别: %@, 座右铭: %@", name, sex, motto);
}
选择器用法
实现比较
– (BOOL)isLongerThanAnotherLavra:(Lavra *)newLavra {
return [self length] > [newLavra length];
}
SEL sel = @selector(isLongerThanAnotherLavra:);
[array sortArrayWithSelector:sel];//自己定义方法
[array sortUsingSelector : sel] //NSMutableArray自带的一个排序方法
- (void)sortArrayWithSelector:(SEL)selector {
//冒泡排序
for (int i = 0; i < [self count] - 1; i++) {
for (int j = 0; j < [self count] - i - 1; j++) {
//这个if是想判断 self[j] 和 self[j + 1]
//判断结果,是由参数selector决定的
//[虫子的对象 发一个消息(selector里面装的消息)(传了参数是另一个虫子)]
if ([self[j] performSelector:selector withObject:self[j + 1]]) {
[self exchangeObjectAtIndex:j withObjectAtIndex:j + 1];
}
}
}
}
选择器常用的方法
判断对象能否响应某个消息
respondsToSelector: 是OC常用的方法
作用
可以使用一个方法实现不同的功能,提高代码复用度
选择器支持iOS开打中的控件的响应机制
可以用于方法的回调
Class class是一种变量类型,装类的类型(相当于int)
六 点语法
setter方法用于给成员变量赋值
getter方法用于返回成员变量的值
OC里面点语法,不是直接访问成员变量,而是调用setter和getter方法
七 继承
(oc的继承是动态继承,编译的时候不能确定父类是谁,在运行的时候才可以确定)
子类没有声明的成员变量,属性,方法,但可以直接用父类的,这就是继承
子类可以继承父类的成员变量,属性,方法
但是父类没有声明在头文件里的成员变量,属性,方法,子类是继承不到的
重写:1.完全重写 2,在父类的基础上重写
重写也是多态的体现,再重写的方法中可以用super可以直接调用父类的方法
派生:子类可以派生出父类没有的方法属性,父类不能访问
重载:一簇方法功能是一样的,区别在于参数的个数,这就叫重载
八 多态
有,重写,重载,虚函数,其实就是同一个接口的不同实现
【虚函数】父类的指针可以指向子类对象
不看指针看对象的方法,称为虚函数
- (void)beatWorm:(Worm *)worm;
形参是父类的对象,地址可以传子类的地址
九 工厂模式
工厂模式,其实是多个类共同组成的,对外他们使用同一个类名
@implementation LNBString
+ (LNBString *)string1 {
TaggedString * str = [[TaggedString alloc] init];
return str;
}
+ (LNBString *)string2 {
CFString * str = [[CFString alloc] init];
return str;
}
-(void)print;
@end
@implementation TaggedString
-(void)print {
NSLog(@"CFString");
}
@end
@implementation CFString
- (void)print {
NSLog(@"CFString");
}
@end
LNBString * str1 = [LNBString string1];
LNBString * str2 = [LNBString string2];
[str1 print];
[str2 print];
NSLog(@"%@, %@", [str1 class], [str2 class]);
十 内存管理
1.内存管理常见的问题
只申请不释放【内存泄露】
释放内存后,依旧访问这段内存【内存提前释放】
多次释放同一段内存【内存重复释放】
【内存管理的方法】引用计数内存管理
2,setter和getter方法分析
setter方法
NSArray * arr = [[NSArray alloc] init]; //a = 1
Dog * dog3 = [[Dog alloc] init]; //d = 1
[dog3 setArray:arr]; //a = 2
[arr release]; //数组被释放 a = 1
arr = nil;
NSArray * newArr = [[NSArray alloc] init]; //new == 1
[dog3 setArray:newArr]; //new == 2
[newArr release]; //new == 1
[dog3 setArray:newArr];
- (void)setArray:(NSArray *)array {
if(_array != array) {
[_array release];
_array = [array retain];
}
}
getter方法
Dog * dog4 = [[Dog alloc] init];
NSArray * arr4 = [[NSArray alloc] init]; //arr4 == 1
[dog4 setArray:arr4]; //arr4 == 2
[arr4 release]; //arr4 == 1
NSArray * arr5 = [dog4 array]; //arr4 == 1
[dog4 release]; //arr4被释放
- (NSArray *)array {
return [[_array retain] autorelease];
}
拷贝消息
字符串本身已经实现了拷贝协议,所以一般来讲,拷贝操作只用于字符串
【归档】方法实现自己封装类的对象拷贝
retain并不产生新的对象,两个指针指向同一个对象。
copy会复制源对象,产生新的对象,产生的新对象,不可修改。
mutableCopy也复制对象,复制产生的新对象可以修改。
实际工作中,只有字符串,使用copy或mutableCopy,其他都用retain
【单例不需要内存管理】
内存管理法则
a.凡是用alloc, retain, new(或使用new开头的方法), copy(或使用copy开头的方法), mutableCopy(或使用mutableCopy开头的方法)操作的对象,都必须使用release或autorelease方法进行释放。
b.谁创建,谁释放。(谁+1,谁-1)
十一 协议与代理
【数据下下载,怎么把字符串转化成统一资源定位符】
NSData * data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:[url stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]];
NSString * str = [url stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL * newURL = [NSURL URLWithString:str];
NSData * data = [[NSData alloc] initWithContentsOfURL:newURL];
协议
协议里面规定的方法缺省属性是必须实现的
协议里面可以声明可选实现方法
@protocol HttpRequestDelegate <NSObject>
//@required标识符下面的方法为必须实现的协议方法
@required
- (void)downloadFinished:(NSData *)data;
//@optional标识符下面的方法为可选实现的协议方法
@optional
- (void)sleep;
@end
@interface HttpRequest : NSObject
代理指针
@property (assign) id<HttpRequestDelegate> delegate;
下载数据
- (void)downloadDataWithURL:(NSString *)url;
@end
委托方
@implementation HttpRequest
下载数据
– (void)downloadDataWithURL:(NSString *)url {
//同步下载
//NSData就是一堆二进制数据,纯粹为了存储数据
//字符串转化为统一资源定位符,不支持中文汉字
//用UTF8编码格式将字符串重新编码
NSString * urlStr = [url stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
代理方
@interface DataManager : NSObject <HttpRequestDelegate>
通过一个统一资源定位符获取数据
– (void)loadDataWithURL:(NSString *)url;
@end
@implementation DataManager {
//把数据下载类生命成自己的成员变量,以便调用下载方法
HttpRequest * _request;
}
- (instancetype)init {
if (self = [super init]) {
_request = [[HttpRequest alloc] init];
//设置代理指向,代理就是当前对象
//把自己成员变量的代理设为自己
_request.delegate = self;
}
return self;
}
- (void)dealloc {
[_request release];
_request = nil;
[super dealloc];
}
- (void)loadDataWithURL:(NSString *)url {
//希望开始加载数据,但是下载数据的任务不属于数据管理类
//在这里调用数据下载类的方法,进行数据下载
[_request downloadDataWithURL:url];
}
#pragma mark - 实现协议里面的方法
- (void)downloadFinished:(NSData *)data {
//把data转化为字符串,打印
NSString * str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"%@", str);
[str release];
}
@end
十二 Block
【委托方】
对外暴露下载方法
@interface HttpRequest : NSObject
@property (copy) void (^finished)(NSData *);
- (void)downloadWithURL:(NSString *)url;
@end
对外暴露下载方法
@implementation HttpRequest
- (void)downloadWithURL:(NSString *)url {
//开辟子线程的方式下载
//Target:表示这个消息的接受者,第二个参数为消息,第三个参数为传的参
NSThread * thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadFunc:) object:url];
//子线程开始运行
[thread start];
//子线程的release会在执行完任务之后生效
[thread release];
}
- (void)threadFunc:(NSString *)url {
//模拟一下下载耗时
sleep(5);
//下载数据
NSData * data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:[url stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]];
//把下载好的数据回传给调用者
_finished(data);
[data release];
}
- (void)dealloc {
self.finished = nil;
[super dealloc];
}
@end
【代理方】
数据管理类开始加载数据
@interface DataManager : NSObject
- (void)loadData:(NSString *)url;
@end
@implementation DataManager {
//把数据下载类,声明成数据管理类的成员变量
HttpRequest * _request;
int _a;
}
- (instancetype)init {
if (self = [super init]) {
//创建成员变量对象
_request = [[HttpRequest alloc] init];
}
return self;
}
- (void)dealloc {
[_request release];
_request = nil;
[super dealloc];
}
- (void)bark {
}
数据管理类开始加载数据
- (void)loadData:(NSString *)url {
//调用数据下载类的方法,开始下载数据
_request.finished = ^(NSData * data) {
//Block真正实现的地方
NSString * str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"%@", str);
[str release];
};
[_request downloadWithURL:url];
}
@end
另一种实现
【委托方】
@interface Worker : NSObject
@property (copy) void (^finished)(NSUInteger);
//买电脑的方法
//添加一个Block回调的参数
- (void)buyMacWithNumber:(NSUInteger)num withFinished:(void (^)(NSUInteger))finished;
void (^)(NSUInteger)
@end
@implementation Worker
- (void)dealloc {
self.finished = nil;
[super dealloc];
}
- (void)buyMacWithNumber:(NSUInteger)num withFinished:(void (^)(NSUInteger))finished {
NSLog(@"工人买回了电脑.");
//信息通过Block回传
finished(num);
}
【代理方】
@interface Boss : NSObject
//发起买电脑的方法
- (void)wantToBuyMacWithNum:(NSUInteger)num;
@end
@implementation Boss {
Worker * _worker;
}
- (void)dealloc {
[_worker release];
_worker = nil;
[super dealloc];
}
//发起买电脑的方法
- (void)wantToBuyMacWithNum:(NSUInteger)num {
//自己不会买电脑,需要调用Worker的买电脑方法
if (_worker == nil) {
//创建成员变量对象
_worker = [[Worker alloc] init];
}
[_worker buyMacWithNumber:num withFinished:^(NSUInteger num) {
//买回来电脑之后执行的代码
NSLog(@"老板收到了%lu台MAC.", num);
}];
}
@end
十三 文件操作
1.获取NSFileManager对象
NSFileManager * manager = [NSFileManager defaultManager];
2.文件浅遍历
NSError * error = nil;
NSArray * arr = [manager contentsOfDirectoryAtPath:PATH error:&error];
if (error != nil) {
NSLog(@"%@", error);
}
NSLog(@"%@", arr);
3.文件路径的深遍历
NSArray * arr1 = [manager subpathsOfDirectoryAtPath:PATH error:nil];
NSLog(@"%@", arr1);
4.判断文件/路径是否存在
BOOL result = [manager fileExistsAtPath:PATH];
NSLog(@"%d", result);
BOOL isDir;
BOOL result1 = [manager fileExistsAtPath:PATH isDirectory:&isDir];
if (isDir == YES) {
NSLog(@"是路径");
}else {
NSLog(@"不是路径");
}
5.创建一个文件路径
NSError * error1 = nil;
创建文件路径的时候,一定要把路径名写全
path1 = @"/Users/naibin/Desktop/FileManager/MIDDLE/ACE"
NSString * path1 = [PATH stringByAppendingPathComponent:@"MIDDLE/ACE"];
NSString * path2 = [PATH stringByAppendingFormat:@"/ACE%d", 9];
NSDictionary * dic = [manager attributesOfItemAtPath:PATH error:nil];
[manager createDirectoryAtPath:path1 withIntermediateDirectories:YES attributes:nil error:&error1];
if (error1 != nil) {
NSLog(@"%@", error1);
}
创建一个文件,文件里有内容
NSString * str = @"我是一个字符串";
NSData * data = [str dataUsingEncoding:NSUTF8StringEncoding];
[manager createFileAtPath:[PATH stringByAppendingPathComponent:@"abc.txt"] contents:data attributes:nil];
6.拷贝一个文件/路径
通过FileManager创建、拷贝、移动一个文件或者路径,如果存在同名文件或者路径的话,就返回操作失败
[manager copyItemAtPath:[PATH stringByAppendingPathComponent:@"c"] toPath:[PATH stringByAppendingPathComponent:@"OTHERS/c"] error:nil];
7.删除文件或者路径
[manager removeItemAtPath:[PATH stringByAppendingPathComponent:@"OTHERS/c"] error:nil];
8.移动某个文件或者路径
【注】拷贝、移动操作,拷贝、移动的结果目录一定要写全
[manager moveItemAtPath:[PATH stringByAppendingPathComponent:@"OTHERS/cc"] toPath:[PATH stringByAppendingPathComponent:@"cc"] error:nil];
十四 归档
字符串归档
归档就是把任何对象转化为NSData数据的过程
NSString * str = @"我是将要被归档的字符串";
NSData * data = [str dataUsingEncoding:NSUTF8StringEncoding];
把转化得来的二进制数据持久化
[data writeToFile:PATH atomically:YES];
解析字符串
NSData * data = [[NSData alloc] initWithContentsOfFile:PATH];
字符串解归档
把二进制文件转化成对应对象格式
NSString * str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"%@", str);
[str release];
[data release];
归档
归档前,先要建文件夹
LNBClass * class = [[LNBClass alloc] init];
BOOL isDir;
NSFileManager * fileManager = [NSFileManager defaultManager];
[fileManager fileExistsAtPath:[PATH stringByAppendingPathComponent:@"USER"] isDirectory:&isDir];
if (isDir == NO) {
//不存在,创建文件夹
fileManager createDirectoryAtPath:[PATH stringByAppendingPathComponent:@"USER"] withIntermediateDirectories:YES attributes:nil error:nil];
}
1.需要遵从NSCoding协议的对象,都要实现协议里的方法
2.开始归档
(1)可变的空NSData对象
NSMutableData * data = [[NSMutableData alloc] init];
(2)归档工具
NSKeyedArchiver * archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
(3)归档
[archiver encodeObject:class forKey:@"class"];
(4)关闭归档工具
[archiver finishEncoding];
(5)把Data对象持久化
[data writeToFile:PATH atomically:YES];
(6)释放对象
[data release];
[archiver release];
[class release];
解归档
(1)把要解归档的文件读成NSData
NSData * data = [[NSData alloc] initWithContentsOfFile:PATH];
(2)解归档工具
NSKeyedUnarchiver * unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
(3)解归档
LNBClass * class = [[unarchiver decodeObjectForKey:@"class"] retain];
【此处要retain】
(4)关闭解归档工具
[unarchiver finishDecoding];
(5)释放对象
[data release];
[unarchiver release];
[class showAllStudents];
[class release];
十五,JSON解析
获取二进制数据
解析之前,必须了解数据格式
NSData * data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:@"http://10.0.8.8/sns/my/user_list.php?number=20&page=2"]];
进行JSON格式解析
NSError * error = nil;
NSDictionary * dic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
if (error != nil) {
NSLog(@"%@", error);
}
【JSON解析一定要知道,你解析的数据里面存的是啥】
十六,文件句柄
读文件
//获取到文件的读句柄,就可以通过读句柄,读取该文件的内容
NSFileHandle * handle = [NSFileHandle fileHandleForReadingAtPath:PATH];
常用方法
readDataToEndOfFile
readDataOfLength
定位到某个字节
seekToFileOffset
readDataOfLength
写句柄
获取到文件的写句柄,就可以对该文件进行写操作
NSFileHandle * hanle = [NSFileHandlefileHandleForWritingAtPath:PATH];
NSString * str = @"写入我吧";
[hanle seekToEndOfFile];
[hanle writeData:data];NSData * data = [str dataUsingEncoding:NSUTF8StringEncoding];
清空文件至剩余参数个字节
truncateFileAtOffset
十七,XML解析
获取待解析数据
NSData * data = [[NSData alloc] initWithContentsOfFile:PATH];
获取节点树
NSError * error = nil;
GDataXMLDocument * doc = [[GDataXMLDocument alloc] initWithData:data options:0 error:&error];
if (error != nil) {
NSLog(@"%@",error)
获取根节点
GDataXMLElement * rootElement = doc.rootElement;
获取books节点
GDataXMLElement * booksElement = [rootElement elementsForName:@"books"][0];
获取book节点
GDataXMLElement * bookElemtnt = [booksElement elementsForName:@"book"][0];
NSArray * bookArray = [doc nodesForXPath:@"//books/book[@language = 'en' ]" error:nil][0];
Xpath语法,能够快速定位一个节点
“//”表示忽略前面的节点名,直接取节点名为book的节点
Xpath可以进行数据按照属性进行筛选
GDataXMLElement * bookElement = [doc nodesForXPath:@"//books/book[@language = 'ch']" error:nil][0];
获取属性的值
GDataXMLNode * languageNode = [bookElement attributeForName:@"language"];
NSString * language =languageNode.stringValue;
NSLog(@"%@",language);
获取auther
GDataXMLElement * authorElement = [bookElement elementsForName:@"auther"][0];
获取name节点
GDataXMLElement * nameElement = [authorElement elementsForName:@"name"][0];
NSString * authorName = [nameElement stringValue];
NSLog(@"%@",authorName);
[doc release];
[data release];