一、屬性傳值
從前向后
假設A為第一個視圖控制器,B為第二個視圖控制器
在A中導入B的.h文件
場景:A向B傳值
第一步:在B的.h中定義一個content屬性
@interface SecondViewController : UIViewController
@property(nonatomic,copy)NSString *contents;
@end
第二步:在點擊A中的按鈕的方法里面給B的content屬性賦值
-(void)buttonAction:(UIButton *)button
{
NSLog(@"進入第二頁");
SecondViewController *secondVC =
[[SecondViewController alloc] init];
secondVC.contents = self.label.text;
[self.navigationController pushViewController:secondVC animated:YES];
[secondVC release];
}
第三步:在B中使用content的屬性給相應的控件賦值
@implementation SecondViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
self.navigationItem.title = self.contents;
}
二、代理傳值
代理傳值使用在兩個界面傳值的時候,從后向前傳值。
假設A為第一個視圖控制器,B為第二個視圖控制器
場景:B向A傳值
第一步:首先在B的.h文件中聲明協議和協議方法
第二步:在B的.h中聲明一個協議屬性,這里要注意用assign或weak修飾,
weak和assign是一種“非擁有關系”的指針,通過這兩種修飾符修飾的指針變量,都不會改變被引用對象的引用計數。但是在一個對象被釋放后,weak會自動將指針指向nil,而assign則不會。所以,似乎用weak更安全些。
@property (nonatomic,assign)id <協議名>delegate;
#pragma mark 這里是B的.h
#import <UIKit/UIKit.h>
@protocol CustomTabBarDelegate <NSObject>
//把btn的tag傳出去的方法
-(void)selectedIndexWithTag:(NSInteger)tag;
@end
@interface CustomTabBarView : UIView
//聲明一個協議屬性delegate
@property (nonatomic,assign)id <CustomTabBarDelegate>delegate;
@end
第三步:在B即將POP回前一個界面的時候,在pop方法的上一行使用協議方法傳遞數據
[self.delegate 協議方法名稱:(參數,也就是要傳回的數據)
#pragma mark 這里是B的.m
// 判斷在指定的代理類中是否實現了該協議方法
// 確保執行時無此方法時不崩潰
if([self.delegate respondsToSelector:@selector(selectedIndexWithTag:)])
{
//執行代理方法
[self.delegate selectedIndexWithTag:(sender.tag - 1000)];
}
else
{
NSLog(@"selectIndexWithTag該方法沒有實現");
}
第四步:在A的.m中,在push到B界面的push方法之前,B對象的初始化之后,指定A對象為B對象的代理
(B對象).delegate = self;
此時會有黃色警告,沒有遵守協議
#pragma mark A的.m中
//指定代理,B就是customView
customView.delegate = self;
第五步:在A的延展或者A的.h文件中導入協議<協議名稱>
#pragma mark A的.m的延展里 , A就是RootTabBarController
//導入協議
@interface RootTabBarController ()<CustomTabBarDelegate>
@end
第六步:在A的.m中實現協議方法,取得參數中的值,呈現在當前界面上
#pragma mark A的.m
//實現代理方法,這里就可以使用從B傳來的值了
- (void)selectedIndexWithTag:(NSInteger)tag
{
self.selectedIndex = tag;
}
三、block傳值
這里就不具體講block是怎么回事了,這是OC的基礎內容。
block就是一塊代碼片段,類似于函數但是block可以作為參數進行傳遞
第一步:
在B的.h中重定義一個block,用這個重定義的block類型聲明一個類的屬性
這里要注意用copy修飾block屬性
#pragma mark B的.h
#import <UIKit/UIKit.h>
//block傳值
//重命名一個有參無返回值的block類型
typedef void(^passValue)(NSInteger tag);
@interface CustomTabBarView : UIView
//用這個block類型定義一個屬性
@property (nonatomic,copy)passValue passValueTag;
@end
第二步:
在B的.m的返回方法中調用block的方法
#pragma mark B的.m的返回方法中
nbsp;//調用block方法
self.passValueTag(sender.tag - 1000);
第三步:
在A的.m中創建B的實例的地方,為B的block屬性賦值,也就是說,寫好這個block中的內容,類似于給B的某一個屬性賦初值
//設置block內容
customView.passValueTag = ^(NSInteger tag)
{
self.selectedIndex = tag;
};
這里只有三步,比代理的方法簡單了不少
下面是實現效果
第一頁有個Label,在第二頁的輸入框輸入文字,就可以顯示在第一頁的label上,實現了從后向前的傳值
沒有引用局部變量的block內存存儲在全局區
沒有引用局部變量的block內存存儲在全局區
引用了局部變量的block內存存儲在棧區
當對block進行copy操作的時候blcok的內存在堆區
block的循環引用問題
當block是self的一個屬性的時候
self.circleBlock = ^() { my_self.navigationItem.title = @"asd"; };
會導致self的引用計數+1,最終導致循環引用
在arc下使用__weak修飾變量防止循環引用
在非arc下使用__block修飾變量防止循環引用
四、單例傳值
單例傳值基本思路是創建一個SingleTon類,里面定義一個要傳的值的屬性,再聲明一個share類方法,在類方法中用static定義類的實例變量,讓它只初始化一次。
這樣凡是導入這個SingleTon類的文件都可以通過share方法聲明一個實例變量,從變量中拿到它的屬性,這個屬性是地址唯一的,也就是說,大家拿到的都一樣,一處變化,任何位置拿到的這個值都變化。
創建SingleTon類
SingleTon.h
#import <Foundation/Foundation.h>
@interface SingleTon : NSObject
//傳值的具體屬性
@property (nonatomic,retain)NSString *passValue;
//一般單例是類方法來創建
+(SingleTon*)sharedSingleTon;
@end
SingleTon.m
#import "SingleTon.h"
@implementation SingleTon
+(SingleTon *)sharedSingleTon
{
//static 只賦值一次
static SingleTon *singleTon = nil;
//線程鎖,保證同時只有一個線程訪問
@synchronized(self) {
if (!singleTon) {
singleTon = [[SingleTon alloc]init];
}
}
return singleTon;
}
@end
//GCD方法創建單例
+(XMPPTools *)sharedXMPPTool
{
static XMPPTools *xmppTools = nil;
//GCD方式創建單例
static dispatch_once_t onceToker;
_dispatch_once(&onceToker, ^{
xmppTools = [[XMPPTools alloc]init];
});
return xmppTools;
}
這次把代碼貼全點
AppDelegate.h
#import "AppDelegate.h"
#import "RootViewController.h"
#import "SecondViewController.h"
@interface AppDelegate ()
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
RootViewController *rootVC = [[RootViewController alloc]init];
//創建導航控制器
UINavigationController *naviagtionC = [[UINavigationController alloc]initWithRootViewController:rootVC];
self.window.rootViewController = naviagtionC;
return YES;
}
用的時候在兩個ViewController文件中導入SingleTon.h
RootViewController.m
#import "RootViewController.h"
#import "SingleTon.h"
#import "SecondViewController.h"
@interface RootViewController ()<UITableViewDelegate,UITableViewDataSource>
@property (nonatomic,retain)UITextField* myTextField;
@end
@implementation RootViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.title = @"第一頁";
//添加UItextField
_myTextField = [[UITextField alloc]initWithFrame:CGRectMake((414-200)/2, 200, 200, 40)];
_myTextField.borderStyle = UITextBorderStyleLine;
_myTextField.placeholder = @"input";
//添加按鈕
UIButton *myBtn = [UIButton buttonWithType:UIButtonTypeSystem];
myBtn.frame = CGRectMake((414-100)/2, 300, 100, 100);
[myBtn setTitle:@"確定" forState:UIControlStateNormal];
myBtn.layer.cornerRadius = 50;
myBtn.layer.masksToBounds = YES;
myBtn.backgroundColor = [UIColor colorWithRed:200/255.0 green:233/255.0 blue:160/255.0 alpha:1];
//添加按鈕方法
[myBtn addTarget:self action:@selector(jumpToSecondVC:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:myBtn];
[self.view addSubview:_myTextField];
}
//重復調用的方法,再返回時用單例的值給標題
-(void)viewWillAppear:(BOOL)animated
{
SingleTon *singleTon = [SingleTon sharedSingleTon];
if (singleTon.passValue.length) {
self.navigationItem.title = singleTon.passValue;
}
}
-(void)jumpToSecondVC:(UIButton*)sender
{
NSLog(@"tap btn");
SingleTon *mySingleTon = [SingleTon sharedSingleTon];
//把輸入框的值給單例的屬性
mySingleTon.passValue = _myTextField.text;
SecondViewController *secondVC = [[SecondViewController alloc]init];
[self.navigationController pushViewController:secondVC animated:YES];
}
SecondViewController.m
#import "SecondViewController.h"
#import "SingleTon.h"
@interface SecondViewController ()
@property (nonatomic,retain)UITextView *myTextView;//
@property (nonatomic,retain)UITextField *testTextField;
@end
@implementation SecondViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.title = @"第二頁";
SingleTon *mySingleTon = [SingleTon sharedSingleTon];
self.navigationItem.title = mySingleTon.passValue;
_testTextField = [[UITextField alloc]initWithFrame:CGRectMake((414-200)/2, 300, 200, 40)];
[self.view addSubview:_testTextField];
_testTextField.placeholder = @"input";
mySingleTon.passValue = _testTextField.text;
}
//view即將消失時,也就是返回前,賦值給單例
-(void)viewWillDisappear:(BOOL)animated
{
SingleTon *mySingleTon = [SingleTon sharedSingleTon];
mySingleTon.passValue = _myTextField.text;
}