zoukankan      html  css  js  c++  java
  • objective-c 中的关联介绍

    objective-c 中的关联介绍

    转载请注明CSDN博客上的出处:
    http://blog.csdn.net/daiyibo123/article/details/46471993


    如何设置关联

    我们可以使用下面的方法来关联属性:

    objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
    1. 被关联的对象,下面举的例子中关联到了UIAlertView
    2. 要关联的对象的键值,一般设置成静态的,用于获取关联对象的值
    3. 要关联的对象的值,从接口中可以看到接收的id类型,所以能关联任何对象
    4. 关联时采用的协议,有assign,retain,copy等协议,具体可以参考官方文档

    可以通过下面的方法来获取我们刚刚关联的object:

    objc_getAssociatedObject(id object, const void *key);
    1. 被关联的对象
    2. 要关联的对象的键值,一般设置成静态的,用于获取关联对象的值

    简单运用

    下面是简单地viewController类,黏贴直接可以运行:

    #import <UIKit/UIKit.h>
    @interface ViewController : UIViewController
    
    @end
    #import "ViewController.h"
    #import <objc/runtime.h>
    
    static char kUITableViewIndexKey;
    
    @interface ViewController ()
    @end
    
    @implementation ViewController
    - (void)viewDidLoad {
        [super viewDidLoad];
        UILabel *lable = [[UILabel alloc] initWithFrame:CGRectMake(0, 200, [UIScreen mainScreen].bounds.size.width, 50)];
        lable.backgroundColor = [UIColor lightGrayColor];
        lable.text = @"关联属性";
        lable.textColor = [UIColor blackColor];
    
    
        objc_setAssociatedObject(self, &kUITableViewIndexKey, lable, OBJC_ASSOCIATION_RETAIN_NONATOMIC);//设置一个关联
    
        [self.view addSubview:objc_getAssociatedObject(self, &kUITableViewIndexKey)];//获取刚刚关联的lable
    }
    @end

    注:在获取和设置关联的时候,调用的被关联对象(代码中用的是self)和关联键值(代码中用kUITableViewIndexKey)都必须是同一个对象。这样才可以保证能获取到关联对象。


    个人理解

    下面是键值的较好的运用:

    代码介绍:一个仿系统的TabBarController类(RDVTabBarController,这个是第三方库,下载地址:https://github.com/robbdimitrov/RDVTabBarController)

    在创建RDVTabBarController时,建立了两个UIViewController的扩展,扩展中建立关联,关联代码如下:

    @interface UIViewController (RDVTabBarControllerItemInternal)
    
    - (void)rdv_setTabBarController:(RDVTabBarController *)tabBarController;
    
    @end
    
    @interface UIViewController (RDVTabBarControllerItem)
    
    @property(nonatomic, readonly) RDVTabBarController *rdv_tabBarController;
    
    @end
    @implementation UIViewController (RDVTabBarControllerItemInternal)
    
    - (void)rdv_setTabBarController:(RDVTabBarController *)tabBarController {
        objc_setAssociatedObject(self, @selector(rdv_tabBarController), tabBarController, OBJC_ASSOCIATION_ASSIGN);
    }
    @end
    
    @implementation UIViewController 
    (RDVTabBarControllerItem)
    
    - (RDVTabBarController *)rdv_tabBarController{
        RDVTabBarController *tabBarController = objc_getAssociatedObject(self, @selector(rdv_tabBarController));
        //这里使用的递归算法
        if (!tabBarController && self.parentViewController) {
            tabBarController = [self.parentViewController rdv_tabBarController];
        }
    
        return tabBarController;
    }
    @end

    然后在RDVTabBarController创建中调用ViewController的扩展方法rdv_setTabBarController:(因为RDVTabBarController也是ViewController的子类,所以可以调用)。通过这个方法设置关联,将TabBarViewController中的childView都和TabBarViewController关联起来。

    下面是RDVTabBarController中调用扩展方法设置关联的代码:
    (这个简化了其他与关联无关的代码,需要了解其他的,自己从github上下载这个第三方库看源码。)

    - (void)setViewControllers:(NSArray *)viewControllers {        
    
    if (viewControllers && [viewControllers isKindOfClass:[NSArray class]]) {
           //向TabBarViewController中添加关联
            for (UIViewController *viewController in viewControllers) {
                [viewController rdv_setTabBarController:self];
            }
        } else {
            //没有向TabBarViewController中添加viewController,删除关联,删除TabBarViewCOntroller中的childViewController
            for (UIViewController *viewController in _viewControllers) {
                [viewController rdv_setTabBarController:nil];
            }
            _viewControllers = nil;
        }
    }

    完成了上面的设置之后,我们就在项目中,直接通过当前运行的viewController来获取tabBarViewController这个属性了。

    下面是示范代码:

    [self.rdv_tabBarController setTabBarHidden:!_viewController.rdv_tabBarController.tabBarHidden animated:YES];
    
    //通过点运算符,调用UIViewController中的扩展方法:`rdv_tabBarController`。然后在`rdv_tabBarController`扩展方法中,递归寻找和RDVTabBarViewController关联的属性。

    运行结果简介:

    简单运行一个demo,po打出相关RDVTabBarController中相关信息:

    • 放入TabBarController中的四个NavigationViewController
      存放结果

    • 第一个NavigationViewController,push推入下一个viewController;推入之后,运行上面的“直接通过当前运行的viewController来获取tabBarViewController”中的代码:

    编辑内容

    搜索关联

    在这里递归寻找关联值,第一个ViewController地址为:’0x7f9378e750a0‘没有进行关联,找不到。然后跳到父视图中,地址为:‘0x7f9378d39a70’有相关,找到,不需要在向下寻找。递归结束,找到关联值,返回结果。

    小结:

    这里,通过扩展和关联的结合使用,将RDVTabBarController这个实例属性,和当前的ViewController结合起来。这种思想,在以后自己编写第三方库函数的时候,值得借鉴!
    总体来说,associative的主要原理,就是把两个对象相互关联起来,使得其中的一个对象作为另外一个对象的一部分。


    参考:

    http://m.blog.csdn.net/blog/csz0102/19555673

  • 相关阅读:
    [HihoCoder1259]A Math Problem
    [POJ1205]Water Treatment Plants
    [HDU5492]Find a path
    [USACO08JAN]Cell Phone Network
    [CodeForces-543D]Road Improvement
    [HAOI2012]外星人
    [CodeForces-869C]The Intriguing Obsession
    [CodeChef-CAPTCITI]Snakes capturing the Mongoose Cities
    CF741D Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths
    Luogu P4095 [HEOI2013]Eden的新背包问题
  • 原文地址:https://www.cnblogs.com/AbeDay/p/5026907.html
Copyright © 2011-2022 走看看