1. 属性传值
将属性在.h 文件里声明,另一个类导入这个头文件后即可给这个属性赋值,这个文件就可以得到传过来的变量。
#import <Foundation/Foundation.h>
@interface Person : NSObject<NSCopying,NSMutableCopying>
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) BOOL sex;
@property (nonatomic, copy) NSString *address;
@end
在另一个类里就可以通过如下代码赋值:
Person *person = [Person new];
person.name = @"Hardy";
person.sex = true;
person.address = @"SZ Nanshan Weinxin";
2. Block传值
首先在上述的Person类里声明一个block
@property (nonatomic, copy) void(^myBlock)(NSString *name);
然后在ViewController里调用
person.myBlock = ^(NSString *name){
NSLog(@"name=%@",name);
};
3. 代理(Delegate)传值
代理模式是一种相对block来说松耦合的传值模式。代理顾名思义就是委托另一个人去做一件事情。
在Person类@interface上面添加如下代码
@protocol PersonDelegate <NSObject>
- (void)updatePersonName:(NSString *)name;
@end
在@interface里面添加如下代码
@property (nonatomic, assign) id<PersonDelegate> delegate;
然后在实现Delegate的类(ViewController.m)里
@interface ViewController ()<PersonDelegate>
@end
这时候会提示Method ‘updatePersonName:’ in protocol ‘PersonDelegate’ not implemented这个警告,这是因为delegate里的方法是@required的,这是默认的,必须实现这个delegate里的方法;如果在方法上面声明为@optional,就可以不需要实现这个方法。
实现Delegate的类实现这个方法
- (void)updatePersonName:(NSString *)name{
}
4.常量文件(全局变量)传值
很多项目一般都会定义全局常量文件(通常为Contants.h)来定义一些全局常量,比如全局的颜色值、window的宽高以及全局的通知Key和多个文件都会用到的枚举等。这个大家应该都知道,就不贴代码了。
5. 单例传值
我们项目中一般都会定义一些单例类,利用单例类来进行全局传值。分享一个很不错的方便写单例模式的代码。定义一个Singleton.h的文件,然后把下面代码直接复制进去就好了。使用的时候只需在.h文件里@interface里声明SingletonH(当前类的名字),然后在.m文件里@implementation下面写上SingletonM(当前类的名字)就可以了。也可以不用当前类的名字,不过习惯上这样写可读性更好。
#ifndef Singleton_h
#define Singleton_h
// .h文件的实现
#define SingletonH(methodName) + (instancetype)shared##methodName;
// .m文件的实现
#define SingletonM(methodName) \
static id _instace = nil; \
+ (id)allocWithZone:(struct _NSZone *)zone \
{ \
if (_instace == nil) { \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
_instace = [super allocWithZone:zone]; \
}); \
} \
return _instace; \
} \
\
- (id)init \
{ \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
_instace = [super init]; \
}); \
return _instace; \
} \
\
+ (instancetype)shared##methodName \
{ \
return [[self alloc] init]; \
} \
+ (id)copyWithZone:(struct _NSZone *)zone \
{ \
return _instace; \
} \
\
+ (id)mutableCopyWithZone:(struct _NSZone *)zone \
{ \
return _instace; \
}
#endif
6. 通过NSNotificationCenter传值
相信这个大家应该也是很熟悉的,就是一个消息通知机制,相当于广播。一般用来不同层次之间的传值,当然同层次之间也可以用,但是个人不推荐使用,因为使用通知会导致逻辑不清晰,不能按照线性逻辑去理清框架。使用通知时需要接收通知的类需要先注册这个通知,不需要时要移除它。
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onTaskSuccess:) name:NOTICE_UI_SUCCESS object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:NOTICE_UI_SUCCESS object:nil];
发出通知的类直接发送通知
[[NSNotificationCenter defaultCenter] postNotificationName:DHY_NOTICE_UI_SUCCESS object:nil userInfo:userInfo];
关于通知,还有一点必须要注意的,就是接收消息的线程是取决于发送所在的线程的,即在哪个线程发送通知,就在哪个线程接收通知。所以如果接收到某个通知后需要直接更新UI,则一定要在主线程中发送通知,当然也可以接收到通知后再切换到主线程中去更新UI。
为了实现统一管理,把通知封装在一个单独的通知类中,然后所有的通知都通过这个类来发送,便于管理,然后在上层的基类中去注册这个通知,实现抽象方法,然后需要接收通知的子类去重写方法来实现具体功能。另外可以把通知封装成几个大的类别,再封装成小类,便于接收处理。
以上是个人对通知的理解和使用心得,大家觉得有什么不对的或有更好的方法欢迎大家留言一起讨论!
7. 数据持久化传值
数据持久化的方案主要有以下几种:
(1)NSUserDefaults
NSUserDefaults只能存储少量的数据,比如登录的用户名,密码以及是否开启声音和振动等数据,不能存储大量数据。以下代码简单描述了如何存储数据到NSUserDefaults和从NSUserDefaults取出数据。
//存储数据
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:@"hardy" forKey:@"EnglishName"];
[defaults synchronize];
//获取数据
NSString *englishName = [defaults objectForKey:@"EnglishName"];
(2)NSKeyedArchiver(归档)
归档实际上是把对象转为字节码,以文件的形式存储到磁盘上,需要时再解归档来还原这些对象。要实现归档需要遵守NSCoding协议,然后必须重写NSCoding协议两个方法。下面的代码给予上述的Person类说明如何使用。
Person.h
@interface Person : NSObject<NSCopying,NSMutableCopying,NSCoding>
Person.m
- (instancetype)initWithCoder:(NSCoder *)aDecoder{
if ([super init]) {
self.name = [aDecoder decodeObjectForKey:@"name"];
self.sex = [aDecoder decodeBoolForKey:@"sex"];
self.address = [aDecoder decodeObjectForKey:@"address"];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder{
[aCoder encodeObject:self.name forKey:@"name"];
[aCoder encodeBool:self.sex forKey:@"sex"];
[aCoder encodeObject:self.address forKey:@"address"];
}
(3)文件
<1> plist文件
创建plist文件,File——>New——>File,选择iOS–>Resource–>Property List
//写入Plist文件
NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = [path objectAtIndex:0];
NSString *plistPath = [documentsPath stringByAppendingPathComponent:@"person.plist"];
NSMutableDictionary *newsDict = [NSMutableDictionary dictionary];
[newsDict setObject:@"hardy" forKey:@"name"];
[newsDict writeToFile:plistPath atomically:YES];
//读取文件
NSMutableDictionary *data2 = [[NSMutableDictionary alloc] initWithContentsOfFile:plistPath];
//获取plist文件目录
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"person" ofType:@"plist"];
<2> 自定义格式文件
//存储数据到文件
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docuPath = [documentPaths objectAtIndex:0];
NSFileManager *fileManger =[NSFileManager defaultManager];
NSString *folderPath = [docuPath stringByAppendingPathComponent:@"abc.txt"];
if (![fileManger fileExistsAtPath:folderPath]) {
[fileManger createDirectoryAtPath:docuPath withIntermediateDirectories:folderPath attributes:nil error:nil];
}
NSString *filePath = [folderPath stringByAppendingPathComponent:fileName];
NSData *data = [@"need to write data" dataUsingEncoding:NSUTF8StringEncoding]; //需要写文件的数据
[data writeToFile:filePath atomically:YES];
//从文件中读取数据
NSString* content = [NSString stringWithContentsOfFile:folderPath encoding:NSUTF8StringEncoding error:nil];
(4)数据库
数据库可以使用CoreData和SQLite来存放进去数据库。因为CoreData和SQLite的使用比较麻烦,后面再详细的介绍。
(5)网络/服务器
将数据存储在服务器上,然后所有的客户端通过网络将本地数据上传到服务器或从服务器下载数据到本地。这其实应该算是多个客户端之间的通信。关于网络的使用也将在后面详细介绍。