【问题标题】:Don't understand global variables不懂全局变量
【发布时间】:2014-05-28 11:12:27
【问题描述】:

我正在为 iPad 开发一个应用程序,该应用程序经常需要共享变量。对我来说,似乎最简单的解决方案是创建一个具有全局变量的类,而不是专注于来回传递——因为我也遇到了一些问题。

使用带有情节提要的 Xcode 5 在 iPad IOS7 的 Objective-C 中创建和使用全局变量的最简单方法是什么?

(我知道有重复但我不能让它工作)

【问题讨论】:

  • 了解单例模式并使用它们..
  • 使用全局变量几乎从来都不是一个好主意。 als Salman 说,如果您需要它们,请理解并使用单例模式。
  • 我认为您想为整个程序创建一个全局类。这是一种封装、保护数据的好方法,也是一种有组织的方式来做你想做的事。
  • 仅仅因为 2 或 3 个类需要访问一个变量并不意味着 200-300 个类需要访问该变量。如果你给出一些更具体的例子来说明何时/何地/如何共享变量,这个问题会更好一些,因为几乎总有比全局变量更好的方法。
  • 我很失望,事实上前三个 cmets 都立即推荐单例而不是催促更多信息。用户似乎最有可能只需要在几个视图控制器之间传递数据,而且这不太可能是真正合法地保证任何类型的全局变量的情况......

标签: ios objective-c ipad global-variables global


【解决方案1】:

编辑:关注@nhgrif 和其他 cmets,我正在稍微改变我的答案

传递变量或使用全局变量的方式实际上取决于您尝试做什么。

这里有几种方法:

将一个值从一个视图传递到另一个视图可以简单地在将其添加到堆栈之前完成,如下所示:

ViewController *viewController = [[ViewController alloc] init];
viewController.yourIntegerValue =  42;   
[self presentViewController:viewController animated:YES completion:nil];

NSUserDefaults 非常适合您喜欢传递或保存以备后用的通用小块数据。参见 AlwaysWannaLearn 的示例,我通常为所有通用值(带键)构建和存储 NSDictionary。 (另见我同意的@nhgrif 的评论)

AppDelegate 解决方案是@Martin Koles 建议的另一种方法。也许对于一组值来说没问题,如果只是为了将我所有的全局变量放在一个地方,我会避免它。

单例解决方案(原始答案)。 它简单、可扩展、优雅、高效。我通常将其中一个添加到我创建的任何项目中。

这里是如何快速做到这一点:

创建一个新文件:MyManager.h

#import <foundation/Foundation.h>

@interface MyManager : NSObject {
    NSString *someProperty;
}

@property (nonatomic, retain) NSString *someProperty;

+ (id)sharedManager;

@end

创建一个新文件:MyManager.m

#import "MyManager.h"

@implementation MyManager

@synthesize someProperty;

#pragma mark Singleton Methods

+ (id)sharedManager {
    static MyManager *sharedMyManager = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedMyManager = [[self alloc] init];
    });
    return sharedMyManager;
}

- (id)init {
  if (self = [super init]) {
      someProperty = [[NSString alloc] initWithString:@"Default Property Value"];
  }
  return self;
}

- (void)dealloc {
  // Should never be called, but just here for clarity really.
}

@end

就是这样 - 这个类将保存你的全局函数和值

要使用这个巧妙的技巧,请将以下行粘贴到项目中的任何其他位置

MyManager *sharedManager = [MyManager sharedManager];
//int getValuefromSingleton = sharedManager.MyFunctionOrValue;

【讨论】:

    【解决方案2】:

    实现和使用单例模式的最简单和最简单的方法:

    创建一个NSObject继承类,你的头文件(.h)应该是这样的:

    @interface MySingletonClass : NSObject 
    
    //this method will be used to get singleton instance
    + (MySingletonClass *)sharedInstance;
    
    //some variables getters and setters
    - (void)setName:(NSString *)name;
    - (NSString *)name;
    
    - (void)setAge:(int)age;
    - (int)age;
    
    @end
    

    这将是您的实现 (.m) 类:

    @interface MySingletonClass() {
    
    }
    
    //your global variables
    @property (nonatomic, strong) NSString *name;
    @property (nonatomic) int age;
    
    @end
    
    @implementation MySingletonClass
    
    static MySingletonClass *sharedInstance = nil;
    
    //this method will be used to get singleton instance
    + (MySingletonClass *)sharedInstance {
        if(sharedInstance == nil){
            sharedInstance = [[MySingletonClass alloc] init];
        }
    
        return sharedInstance;
    }
    
    -(id)init {
        if(self = [super init]) {
            _name = @"";
            _age = 0;
        }
    
        return self;
    }
    
    //some variables getters and setters
    - (void)setName:(NSString *)name {
        _name = name;
    }
    
    - (NSString *)name {
        return name;
    }
    
    - (void)setAge:(int)age {
        _age = age;
    }
    
    - (int)age {
        return age;
    }
    
    @end
    

    你也可以在头文件中定义你的变量。

    您可以像这样在整个应用程序中使用设置/获取变量:

    [[MySingletonClass sharedInstance] setName:@"Test"];
    NSString *name = [[MySingletonClass sharedInstance] name];
    

    【讨论】:

      【解决方案3】:

      您应该使用存储键值对的NSUserDefaultsKeychain,而不是使用全局变量,您可以在任何地方和应用程序的任何控制器中使用它们。由于安全性较低,全局变量通常不是首选。它们的值可以很容易地改变。与全局变量相比,KeychainNSUserDefaults 更安全,您可以在一个位置存储多个值。使用NSUserDefaults 的示例如下,其中存储值并在应用程序的任何位置使用。

      用于存储键值对:

       NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
       [prefs setObject:[finalDetails valueForKey:@"Std_Id"] forKey:@"Std_Id"];
      

      用于在其他控制器中获取该值。

      NSString *stdId = [[NSUserDefaults standardUserDefaults] valueForKey:@"Std_Id"];
      

      【讨论】:

      • 我已经在我的应用程序中使用了很多 NSUserDefaults,但我认为它是一种奇怪的方式 - 一直在保存一些东西。你确定这是个好方法吗?它会一直保存和阅读。苹果会批准吗?
      • 我想不出任何理由拒绝使用NSUserDefaults。它是存储常用信息的一种不错的方式。我也用过,还不错。是的,如果您想要更高的安全性,您可以选择使用Keychain。就NSUserDefaults而言,您可以放心使用。 :)
      • 钥匙串应该用于登录信息等等,但不能用于在视图控制器之间传递信息。每个用户都会愤怒地看到他们的钥匙串上到处都是应用程序的一些无用信息。 NSUserDefaults 用于永久存储小值,例如首选项,也不应该用于此目的。
      【解决方案4】:

      我尝试仅将NSUserDefaults 用于需要在应用程序执行之间保持的相对简单的值 - 对于更复杂的数据,Core Data 可能更合适。

      对于瞬态数据,我更喜欢使用数据模型类。

      数据模型类将具有所需的属性,有时还有一些类或实例方法来操作数据。一旦您将数据放入模型类中,通常非常简单地在您的视图控制器之间传递引用并避免对“全局变量”的需要。如果您确实需要“全局变量”,那么您可以使用 singleton pattern - 例如,[UIApplication sharedApplication] 是一个单例。

      您可以使用以下结构创建单例

      MyData.h

      @interface MyData : NSObject {
          NSString *someProperty;
      }
      
      @property (nonatomic, retain) NSString *someProperty;
      
      + (id)sharedMyData
      
      @end 
      

      我的数据.m

      #import "MyData.h"
      
      @implementation MyData
      
      
      #pragma mark Singleton Methods
      
      + (id)sharedMyData {
          static MyData *sharedMyData = nil;
          static dispatch_once_t onceToken;
          dispatch_once(&onceToken, ^{
              sharedMyData = [[self alloc] init];
          });
          return sharedMyData;
      }
      
      - (id)init {
        if (self = [super init]) {
            someProperty = [[NSString alloc] initWithString:@"Default Property Value"];
        }
        return self;
      }
      

      然后,无论您需要在何处访问您的数据,都可以使用 [MyData sharedMyData]; 获取对它的引用

      【讨论】:

        【解决方案5】:

        拥有不保留状态的全局范围变量的最简单方法是在 AppDelegate(在您的应用中是单例)上拥有一个属性:

        在 AppDelegate.h 文件中:

        @property (strong, nonatomic) NSString *globalString;
        

        以及您需要访问的任何地方:

        #import "AppDelegate.h"
        
        AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
        // use appDelegate.globalString ...
        

        如果你需要在你的类中多次使用 AppDelegate,那么将其定义为属性并懒惰地启动:

        @property (nonatomic, strong) AppDelegate *appDelegate;
        
        - (AppDelegate *)appDelegate
        {
            if (!_appDelegate) {
                _appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
            }
            return _appDelegate;
        }
        

        但是,您应该始终尽量避免这种情况,因为它违反了 OOP 规则。我建议你阅读 iOS 设计模式,尤其是 MVC、Facade 和 Singleton:iOS Design Patterns

        Singleton NSUserDefaults 也可以使用,但这是为了在应用终止后保留状态。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-03-05
          • 2022-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-09-28
          • 2015-06-12
          • 2019-07-24
          • 2017-11-08
          相关资源
          最近更新 更多