【问题标题】:Using global variables in Objective-C在 Objective-C 中使用全局变量
【发布时间】:2013-10-26 08:16:39
【问题描述】:

首先,我尝试了stackoverflow中给出的几乎所有解决方案,但我没有成功实现全局变量,我什至做了一步一步的教程,但我仍然遇到同样的错误。

问题来了:

我有一个带有多个视图的程序,我想在所有视图上使用变量, 所以我使用了全局变量,

我有:

GlobalVars.h

#import <UIKit/UIKit.h>
extern NSArray *truckBoxes;
extern NSArray *farmerlist;
extern NSString *farmerCardNumber;

extern NSString *fName;

@interface GlobalVars : NSObject
{
}

@end

GlobalVars.m

#import "GlobalVars.h"

NSArray *farmerlist;
NSArray *truckBoxes;
NSString *farmerCardNumber;
NSString *fName;
@implementation GlobalVars
{

}
@end

我在类中包含文件(连接到视图控制器): 在 .h 文件下我添加#import "GlobalVars.h

我可以从整个应用程序访问farmerlisttruckBoxes,但无法访问fNamefarmerCardNumber

我可以写信到farmerCardNumber 并从同一个视图读取,但如果我稍后尝试从另一个视图访问它,我会得到

2013-10-26 11:11:45.612 C3Cms[10427:70b] Branch : 11558
2013-10-26 11:11:59.459 C3Cms[10427:70b] -[__NSArrayM length]: unrecognized selector sent to instance 0x8b7fbc0
2013-10-26 11:11:59.463 C3Cms[10427:70b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArrayM length]: unrecognized selector sent to instance 0x8b7fbc0'
*** First throw call stack:
(
    0   CoreFoundation                      0x02a3b5e4 __exceptionPreprocess + 180
    1   libobjc.A.dylib                     0x014d58b6 objc_exception_throw + 44
    2   CoreFoundation                      0x02ad8903 -[NSObject(NSObject) doesNotRecognizeSelector:] + 275
    3   CoreFoundation                      0x02a2b90b ___forwarding___ + 1019
    4   CoreFoundation                      0x02a2b4ee _CF_forwarding_prep_0 + 14
    5   Foundation                          0x00f0db2d -[NSConcreteMutableAttributedString replaceCharactersInRange:withString:] + 39
    6   Foundation                          0x00f0e79a -[NSConcreteMutableAttributedString initWithString:attributes:] + 293
    7   UIKit                               0x001e8116 -[UILabel _setText:] + 97
    8   UIKit                               0x001e82d4 -[UILabel setText:] + 40
    9   C3Cms                               0x00001c1d -[printForm viewDidLoad] + 77
    10  UIKit                               0x0014e9a8 -[UIViewController loadViewIfRequired] + 696
    11  UIKit                               0x0014ec44 -[UIViewController view] + 35
    12  UIKit                               0x00168a72 -[UINavigationController _startCustomTransition:] + 778
    13  UIKit                               0x00175757 -[UINavigationController _startDeferredTransitionIfNeeded:] + 688
    14  UIKit                               0x00176349 -[UINavigationController __viewWillLayoutSubviews] + 57
    15  UIKit                               0x002af39d -[UILayoutContainerView layoutSubviews] + 213
    16  UIKit                               0x000a5dd7 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 355
    17  libobjc.A.dylib                     0x014e781f -[NSObject performSelector:withObject:] + 70
    18  QuartzCore                          0x030d772a -[CALayer layoutSublayers] + 148
    19  QuartzCore                          0x030cb514 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 380
    20  QuartzCore                          0x030cb380 _ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE + 26
    21  QuartzCore                          0x03033156 _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 294
    22  QuartzCore                          0x030344e1 _ZN2CA11Transaction6commitEv + 393
    23  QuartzCore                          0x03034bb4 _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv + 92
    24  CoreFoundation                      0x02a0353e __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 30
    25  CoreFoundation                      0x02a0348f __CFRunLoopDoObservers + 399
    26  CoreFoundation                      0x029e13b4 __CFRunLoopRun + 1076
    27  CoreFoundation                      0x029e0b33 CFRunLoopRunSpecific + 467
    28  CoreFoundation                      0x029e094b CFRunLoopRunInMode + 123
    29  GraphicsServices                    0x029979d7 GSEventRunModal + 192
    30  GraphicsServices                    0x029977fe GSEventRun + 104
    31  UIKit                               0x0003b94b UIApplicationMain + 1225
    32  C3Cms                               0x00002882 main + 130
    33  libdyld.dylib                       0x019bc70d start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException

【问题讨论】:

标签: ios objective-c unrecognized-selector


【解决方案1】:

实现全局变量、管理它们的生命周期(即初始化它们)甚至提供全局方法的一种方法是实现一个暴露这些变量/方法的类并使用单例模式:

GlobalVars.h:

#import <Foundation/Foundation.h>

@interface GlobalVars : NSObject
{
    NSMutableArray *_truckBoxes;
    NSMutableArray *_farmerlist;
    NSString *_farmerCardNumber;
    NSString *_fName;
}

+ (GlobalVars *)sharedInstance;

@property(strong, nonatomic, readwrite) NSMutableArray *truckBoxes;
@property(strong, nonatomic, readwrite) NSMutableArray *farmerList;
@property(strong, nonatomic, readwrite) NSString *farmerCardNumber;
@property(strong, nonatomic, readwrite) NSString *fName;

@end

GlobalVars.m:

#import "GlobalVars.h"

@implementation GlobalVars

@synthesize truckBoxes = _truckBoxes;
@synthesize farmerList = _farmerList;
@synthesize frameCardNumber = _frameCardNumber;
@synthesize fName = _fName;

+ (GlobalVars *)sharedInstance {
    static dispatch_once_t onceToken;
    static GlobalVars *instance = nil;
    dispatch_once(&onceToken, ^{
        instance = [[GlobalVars alloc] init];
    });
    return instance;
}

- (id)init {
    self = [super init];
    if (self) {
        _truckBoxes = [[NSMutableArray alloc] init];
        _farmerlist = [[NSMutableArray alloc] init];
        // Note these aren't allocated as [[NSString alloc] init] doesn't provide a useful object
        _farmerCardNumber = nil;
        _fName = nil;
    }
    return self;
}

@end

然后您可以像这样使用这些全局变量,例如:

GlobalVars *globals = [GlobalVars sharedInstance];
globals.fName = @"HelloWorld.txt";
[globals.farmerList addObject:@"Old Macdonald"];
[self processList:[globals farmerList]];

但是,请考虑:

  • 你不需要像这样使用全局变量;您应该能够创建一个根据需要创建的模型对象并将其引用传递给视图。这是 MVC。
  • 您还发布了一个无关问题的堆栈跟踪,该问题在 Objective-C 中非常常见;一旦你意识到它是什么,只有你可以修复这个错误。

【讨论】:

  • 感谢您的评论,我得到 Framework/Framework.h not found
  • 太棒了!有用!谢谢!供将来参考 - 请更改 @property(strong, nonatomic, readwrite) NSArray *farmerCardNumber; to @property(strong, nonatomic, readwrite) NSString *farmerCardNumber;
  • 一个后续问题,如果我想要 int 或 double 怎么办?如果我这样做 @property(strong, nonatomic, readwrite) double *farmerWeight;它说具有strong的属性必须是类型的对象。
  • 不,使用assign 代替strong 并放下指针(double 代替double *)。
  • 谢谢!你应该有更多的投票方式......!!
【解决方案2】:

错误与全局变量无关。错误信息

-[__NSArrayM length]: unrecognized selector sent to instance 0x8b7fbc0

表示您在代码中的某处将NSMutableArray 分配给farmerCardNumber 而不是NSString

例如,如果你做类似的事情

farmerCardNumber = [someDictionary objectForKey:@"someKey"];

[someDictionary objectForKey:@"someKey"]恰好是一个数组而不是一个字符串, 然后farmerCardNumber 指向该数组,即使它被声明为指向 一个字符串。

【讨论】:

  • 不可能,我只是在整个代码中搜索了farmerCardNumber,它只出现在:farmerCardNumber = txtFarmerCardNumber.text; if([firstBranchName isEqualToString: farmerCardNumber ]) 和 printFarmerCardNumber.text=farmerCardNumber;在另一个视图中
  • 在读取变量前不久插入NSLog(@"class=%@", [farmerCardNumber class]);,并检查输出...
  • 我刚刚添加了一个名为 testVar 的新 var,我得到了同样的错误。
  • 您的观察是正确的,它说“2013-10-26 11:46:32.764 C3Cms[10593:70b] class=__NSDictionaryM”,但是什么会改变它?我用一个在整个代码中只声明了 2 次的新 var 做了同样的事情,它说的是同样的事情。什么会覆盖它?
  • @izzy:这很奇怪。你如何分配给testVar?类在写入后立即正确吗?
【解决方案3】:

我在我的所有项目中都在使用并且工作正常。

GlobalResource.h

#import <Foundation/Foundation.h>

@class GlobalResource;

extern GlobalResource * R;

@interface GlobalResource : NSObject
{
    NSString *myVar;
}
+ (void) loadGlobalResources;

@property (strong, nonatomic, readwrite) NSString *myVar;

@end

GlobalResource.m

#import "GlobalResource.h"

GlobalResource *R;

@implementation GlobalResource

@synthesize myVar;

- (void) loadGlobalResources
{
    R = [[GlobalResource alloc] init];
}

- (id)init
{
    self = [super init];
    if (self) {
        myVar = @"My Value";
    }

    return self;
}

@end

如何使用

#import "GlobalResource.h"

//then access value as bellow

[GlobalResource loadGlobalResource];
NSLog(@"%@",R.myVar); //value will print here

【讨论】:

    【解决方案4】:

    你为什么不试试类似的东西:

    #import "GlobalVars.h"
    
    NSArray *farmerlist;
    NSArray *truckBoxes;
    NSString *farmerCardNumber = nil;
    NSString *fName = nil;
    @implementation GlobalVars
    {
    
    }
    @end
    

    #import "GlobalVars.h"
    
    NSArray *farmerlist;
    NSArray *truckBoxes;
    NSString *farmerCardNumber = @"";
    NSString *fName = @"";
    @implementation GlobalVars
    {
    
    }
    @end
    

    而且您似乎已将可变数组传递给您的字符串变量,这就是您收到该错误的原因。

    【讨论】:

      【解决方案5】:

      删除线

      #import "GlobalVars.h"
      

      来自 GlobalVars.m.

      【讨论】:

      • 如果我这样做,会出现很多错误,包括“在未指定基类的情况下定义了类 'globalvars'”
      • 一个实现文件应该总是导入它自己的接口。我认为这没有问题,也不明白不导入它如何解决上述问题。
      • 您的问题是 GlobalVars.m 既定义了您的全局变量,也将它们声明为外部变量。您的 GlobalVars.h 文件不能按原样包含在内。您可能还有其他问题,因为 GlobalVars.m 需要 GlobalVars.h 中的其他声明,但这是另一回事。
      • 如果一个变量同时声明为外部在同一个编译单元中定义是没有问题的,据我所知这是常见的做法。看看stackoverflow.com/a/1433387/1187415 中的第一个示例。
      【解决方案6】:

      您不能将外部变量放入 *.h 文件。

      所以在 GlobalVariables.m 中你有:

      extern NSArray *farmerlist;
      NSArray *farmerlist;
      

      还有:

      @interface GlobalVars : NSObject
      {
      }
      
      @end
      
      @implementation GlobalVars
      {
      
      }
      @end
      

      不需要

      [编辑]

      例如:

      其他.m

      #import "GlobalVars1.h"
      

      GlobalVars1.h

      extern NSArray *truckBoxes;
      extern NSArray *farmerlist;
      extern NSString *farmerCardNumber;
      
      extern NSString *fName;
      

      GlobalVars.h

      #import <UIKit/UIKit.h>
      
      @interface GlobalVars : NSObject
      {
      }
      
      @end
      

      GlobalVars.m

      #import "GlobalVars.h"
      
      NSArray *farmerlist;
      NSArray *truckBoxes;
      NSString *farmerCardNumber;
      NSString *fName;
      @implementation GlobalVars
      {
      
      }
      @end
      

      【讨论】:

      • 我应该把 NSArray 和 extern 放在哪里? (我的意思是,在 m 文件中..)
      • 抱歉,这是完全错误的。 extern 声明必须在 .h 文件中,以便包括该文件在内的其他编译单元知道它。
      • 从这个 m 中删除带有 (Philip's post) h 的行,并在其他 *.m 中用 h 写入 extern 或这一行
      • @izzy,你必须写两个文件 *.m 才能与 extern 一起使用
      • @skippy:问题中发布的 GlobalVars.h 和 GlobalVars.m 是正确的,没有问题(据我所知)。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-01-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-27
      相关资源
      最近更新 更多