一、自定義構造函數和屬性傳值
1、首先在需要值的類中自定義構造函數並在.h文件中聲明
//自定義構造函數傳值
//.m文件中
- (instancetype)initWithList:(NSArray *)list{
if (self = [super init]) {
myList = list;
}
return self;
}
//.h文件
- (instancetype)initWithList:(NSArray *)list;
//在哪個類裏面 需要 數據 就可以使用屬性 **向上一個頁面** 要值
//正向傳值
//使用一個對象 裏面的屬性、方法...的時候 必須有這個對象存在
@property (nonatomic, copy) NSString *titleName;
//屬性傳值
1>在聲明文件中聲明一個屬性
2>在實現文件中將屬性賦值作爲標題
//.m文件
self.title = self.titleName;
2、在傳值的類中初始化被傳值的對象,在初始化時將值賦給被傳值初始化對象。
//Next_ViewController需要一個值 從ViewController傳到 Next_ViewController
//只要alloc init 就會初始化 一個新的對象
//這個對象 就跟 之前的對象 不是同一個對象 (之前存在的舊對象裏面的數據 就會被清空 (它裏面 沒有被賦值))
1>當不同類型(或者類)響應同一個方法時,可以通過 isKindOfClass 判斷這個對象 屬於哪種類型(哪個類)
//判斷手勢
if([sender isKindOfClass:[UITapGestureRecognizer class]] == YES){}
2>初始化一個數組,並將需要傳得值放在初始化的數組
NSArray *list = @[@"自定義", @"構造函數", @“傳值"];
Next_ViewController *next = [[Next_ViewController alloc] initWithList:list];
//屬性傳值
next.titleName = @"傳值";
3> 手勢裏面有一個 狀態屬性 可以通過 手勢觸發的狀態 判斷 手勢觸發的時間段
if (sender.state == UIGestureRecognizerStateBegan) {
Next_ViewController *next = [[Next_ViewController alloc] initWithList:@[@"屬性傳值", @"屬性"]];
next.titleName = @"正向傳值";
}
二、KVC與KVO傳值
1、KVC(鍵值編碼)傳值
1>KVC主要通過”key”來進行傳值。通過找到屬性或者全局變量的值
2>“key”是屬性或者全局變量的名字
2、KVO(鍵值觀察者)傳值
1>KVO主要通過觀察“屬性”的狀態的變化做出相應地操作。比如從後臺數據庫獲取數據,界面首次初始化時,只有數據發生變化界面纔會發生改變。
2>KVO首先要註冊一個監視中心
//[Model sharManger]創建一個單例
[[Model sharManger] addObserver:self forKeyPath:@"title" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil];
//模擬從後臺數據庫獲取數據
[NSTimer scheduledTimerWithTimeInterval:3 target:self selector:@selector(updateTitle) userInfo:nil repeats:YES];
//獲取數據
- (void)updateTitle{
NSArray *list = @[@"K", @"V", @"O"];
[Model sharManger].title = list[arc4random()%list.count];
}
3>觀察數據是否發生變化
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
if ([keyPath isEqualToString:@"title"]) {
//記錄 所有發生的改變
[all addObject:change[@"old"]];
label.text = change[@"new"]
for (NSString *s in all) {
NSLog(@"%@", s);
}
}
4>移除觀察者
[[Model sharManger] removeObserver:self forKeyPath:@"title"];
三、單例傳值
1>新建一個類繼承NSObject
#import "Model.h"
static Model *model = nil;
@implementation Model
+(instancetype)sharManger{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
model = [[Model alloc] init];
});
return model;
}
@end
}
2>聲明兩個屬性
//標題
@property (nonatomic, copy) NSString *title;
//圖片
@property (nonatomic, retain) UIImage *image;
3>在ViewController.m中導入單例類並給屬性賦初值
[Model sharManger].title = @"風景";
[Model sharManger].image = [UIImage imageNamed:@“begin"];
4>在Next_ViewController類中
UIImageView *imageView = [[UIImageView alloc]initWithFrame:self.view.frame];
imageView.image = [Model sharManger].image;
[self.view addSubview:imageView];
[Model sharManger].image = [UIImage imageNamed:@"bg"];
5>因爲單例只初始化一次,所以在第一次圖片傳過去之後,之後圖片將會一直是@“bg"
四、通知傳值
1、通知是一對多的傳值,通知傳值首先要有觀察者。
2、首先註冊一個消息中心(在這裏模擬請求服務器獲取用戶賬號信息)
1>建一個繼承NSObject的HTTPResquestManager類
//在實現中實現以下方法
+ (void)getRequest{
NSDictionary *dic = @{@"username":@"通知傳值", @"password":@"123456"};
sleep(5);
[[NSNotificationCenter defaultCenter] postNotificationName:@"didResponse" object:nil userInfo:dic];
}
2>在觀察者對象中接收通知
(1)- (instancetype)init
{
self = [super init];
if (self) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reloadDataMeassage:) name:@"didResponse" object:nil];
}
return self;
}
(2)在reloadDataMeassage方法中實現
- (void)reloadDataMeassage:(NSNotification *)not {
label.text = [NSString stringWithFormat:@"%@\n%@", not.userInfo[@"userName"], not.userInfo[@"password"]];
}
3>移除觀察者
[[NSNotificationCenter defaultCenter] removeObserver:self forKeyPath:@"didResponse"];
五、Block(閉包)傳值(block目的:用於反向傳值)
1、局部變量
1>參數聲明
返回值類型(^閉包的名字)(參數列表)
2>實現
閉包的名字 = ^(參數列表){code}
3>調用
閉包的名字();
示例:
聲明
void (^block)(int age, NSString *name);
實現
//如果想修改block外部的變量值 需要添加__block修飾
//__block int age;
block = ^(int age, NSString *name){
//代碼實現
//age = 10;
NSLog(@"%d %@", age, name);
}
調用
block(20, @“小明”);
2、全局變量
1>在延展或.h中聲明一個block全局變量
void (^imageNameBlock)(NSString *imageName);
2>在需要實現Block的方法中實現
***** 由於Block定義全局變量會循環引用 所以需要將該類設置成弱變量
__weak ViewController *vc = self;
__block UIImage *image = nil;
imageNameBlock = ^(NSString *imageName){
image = [UIImage imageNamed:imageName];
vc.view.backgroundColor = [UIColor colorWithPatternImage:image];
};
3>調用
imageNameBlock(@"logo");
4>爲了避免重複初始化控件,需要將控件寫在Block實現的外面
3、屬性傳值
1>在Next_ViewController.h文件中聲明一個屬性
@property (nonatomic, copy) void (^block)(NSString *title);
2>在Next_ViewController.m文件中,在返回上一個頁面時,同時通過Block把這個頁面的值傳到上一個頁面
self.block(@“Block屬性傳值”);
3>在初始化Next_ViewController的地方
next.block = ^(NSString *title){
NSLog(@“%@”, title);
}
4、方法傳值
1>在Next_ViewController.h文件中聲明一個方法
- (void)passValue:(void^(NSString *))block;
2>在Next_ViewController.m文件中實現方法
- (void)passValue:(void^(NSString *))block{
block(@“方法傳值”);
}
3>在初始化Next_ViewController的地方調用此方法
[next passValue:^(NSString * title){
NSLog(@“Block方法傳值”);
}];
六、代理傳值
代理:又叫委託 自己不能去辦的事 委託給別人去辦
1、聲明代理方法(不要在@interface裏面 聲明代理方法)
//協議名字一般是類名+delegate
2、聲明代理的屬性 (可以通過這個屬性找到 代理方法)
@property (nonatomic, assign) id<NextDelegate> delegate;
//聲明代理的屬性 用assign 分配棧裏面
//id<NextDelegate> 代理的類型 尖括號裏面是代理的名字
3、什麼時候需要觸發這個代理方法
// respondsToSelector 判斷一個方法 是否可以響應 返回值是一個BOOL值
4、通過協議的屬性 調用代理的方法 (委託)
5、導入協議
@interface ViewController ()<NextDelegate>
6、在初始化有代理方法的對象地方 掛上代理
7、寫上代理方法 等待被執行