iOS個人整理14-界面間傳值:屬性傳值---代理傳值---block傳值---單例傳值

一、屬性傳值

從前向後

假設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中聲明一個協議屬性,這裏要注意用assignweak修飾,

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的返回方法中

 //調用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進行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;
 
}





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章