使用全局变量的四种方式:extern、AppDelegate、定义单例对象、NSUserDefaults 和单例工厂的使用方法

知识点一、 众所周知,在很多地方都要用到全局变量,因为在一个地方声明赋值的过的对象成员或变量经常在别的地方被使用。例如在一个表示登录页控制器中的登录信息要在别的地方使用到,最常见的做法是别的控制器中也定义一个此变量属性,在跳转之前 对此变量属性进行赋值,这样做只能一对一的进行传递而且麻烦费事有很多弊端。最好的方法是定义一个全局变量——在一个地方赋值,在同一程序的任意地方都能获取到。经过总结发现,在IOS中定义全局变量的方法也无非就以下几种:

(一)直接利用extern

(二)在AppDelegate.h中声明属性变量

(三)直接创建单例对象

(四)使用NSuserDefaults类进行存储

注意:全局变量的特点就是一方赋值,多方使用

详细介绍如下所示:

第一种:直接利用extern—— 这种方式的使用原理是 在文件1的.m文件中@implementation和@end之间 成员方法之外声明一个全局变量  “全局变量类型 全局变量名”,然后把文件1的头文件导入到使用全局变量的控制器中(或直接导入到pch文件中) 这样被导入的控制器(工程中的所有文件)中在同样的位置加上 “extern 全局变量类型 全局变量名” 就可以直接使用此全局变量了。 

使用此种方法应该注意的是:

  •  全局变量的声明语句只能写在.m文件的@implementation和@end之间 成员方法之外。不然的话会出现链接错误,编译不通过。切记:全局变量的声明语句不加extern。
  •  必须把声明全局变量控制器的头文件导入使用此全局变量的控制器的头文件中,最好是直接导入到pch文件中这样工程中的所有文件只要加上“extern 全局变量类型 全局变量名” 就可以直接使用已经声明过的全局变量了。
  • 在使用已声明过的全局变量的控制器中 必须加上“extern 全局变量类型 全局变量名” 至于添加位置可以在写在.m文件的@implementation和@end之间 成员方法之外。也可以写在.h文件的@interface之前,但是如果变量是自定义类的对象时必须要加自定义类的前向声明。
第二种: AppDelegate.h 中声明任意类型的变量属性(如果要想使变量属性名和变量名一致的话就在 AppDelegate.m文件中加@synthesize语句与之对应 ) 。在别的地方获取或赋值的方法如下:

AppDelegate *delegate = (AppDelegate *)[[UIApplicationsharedApplication]delegate];

delegate.strAppDelegate =@"AppDelegate中的全局变量";

 NSLog(@"AppDelegate全局=%@",delegate.strAppDelegate);

切记:AppDelegate也是一个单例对象,所以以同样的方式在其他文件的任何地方获取同名属性都是同一个。

第三种:直接创建单例对象。即将类定义为单例就意味着,全局只有一个此类的对象。无论再怎样修改 alloc  怎样做改动始终都是在一个对象上做操作。

第四种:使用NSUserDefaults类可以把任意类型的变量或对象类型存进沙盒目录下的 Library/Preference/plist文件中,但是要注意的是,如果要存放自定义的对象或类型还要让自定义类遵守NSCoding协议并实现编码解码方法。还要注意的是:此类还有removeObject方法用于删除plist文件下的某个属性,防止泄密。此外对于同样的key表示同一个属性,对同一key赋值多次会造成覆盖。

知识点二、如果使用一个单例直接在其类中设置单例属性即可,但是当有很多单例时就会变得相当繁琐。另外,一旦某个类被设置成了单例就意味着只有一个对象,永远无法改动。这时使用单例工厂就变得非常有用,单例工厂可以根据你传过来的类对象(类对象即[类名  Class] 不是类的对象)生产出一个此类的单例对象,每次要使用此类的单例对象时主要用单例工厂生产(调用单例工厂的方法即可)。而且还不影响此类别的对象的使用,切记:使用单例工厂生产的都是单例对象,在获取时也必须调用单例工厂来获取。

知识点三、由于成员方法必须由类或类的对象调用变得很麻烦,可以在.m文件中写一个函数,然后在别的地方直接使用即可,但前提是必须将此方法在头文件中声明 否则别的文件是找不到此函数的。函数的声明格式如下:

在其.h文件中@interface之上添加如下代码段:

#ifdef __cplusplus
extern "C"{
#endif
    id SingleForClass(Class a); // 已在.m 中添加函数的函数声明
#ifdef _cplusplus
}
#endif
格式有点类似于jsp的标签方法,然后把此头文件导入到pch文件中,工程中所有文件都可以直接使用此函数了。
新建工程一一验证如下:
工程目录如下:


编辑AppDelegate.h  添加变量如下:
//
//  AppDelegate.h
//  单例模式的简单使用
//
//  Created by apple on 15/9/28.
//  Copyright (c) 2015年 LiuXun. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;

// 定义全局变量的第一种形式——在Appdelegate.h文件中定义全局变量
@property (strong, nonatomic) NSString *strAppDelegate;

@end
新建单例工厂
编辑NSSingletonFactory.h如下:
//
//  NSSingletonFactory.h
//  单例模式的简单使用
//
//  Created by apple on 15/9/28.
//  Copyright (c) 2015年 LiuXun. All rights reserved.
//
// 单例工厂类
#import <Foundation/Foundation.h>
#define SingleFactory [NSSingletonFactory shareFactory]

#ifdef __cplusplus
extern "C"{
#endif
    id SingleForClass(Class a);  // 已在.m 中添加函数的函数声明
#ifdef _cplusplus
}
#endif

@interface NSSingletonFactory : NSObject <NSCopying>
{
    NSMutableDictionary *data;
}

+(NSSingletonFactory *) shareFactory;
-(id)shareInstanceFor:(Class) aclass;
-(id) shareInstanceFor:(Class)aclass category:(NSString *)key;

@end
编辑NSSingletonFactory.m如下:
//
//  NSSingletonFactory.m
//  单例模式的简单使用
//
//  Created by apple on 15/9/28.
//  Copyright (c) 2015年 LiuXun. All rights reserved.
//

#import "NSSingletonFactory.h"

@implementation NSSingletonFactory
-(id)init
{
    if (self = [super init]) {
        data = [NSMutableDictionary dictionary];
    }
    return self;
}

+(NSSingletonFactory *) shareFactory
{
    static NSSingletonFactory *share = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        share = [[super allocWithZone:NULL] init];
    });
    return share;
}

+(id)allocWithZone:(struct _NSZone *)zone
{
 return [self shareFactory];
}
-(id) copyWithZone:(NSZone *)zone
{
    return self;
}

-(void)setShareData:(id) shareData  forkey:(NSString *)key
{
    if (shareData == nil) {
        return;
    }
    [data setObject:shareData forKey:key];
}

-(id)getShareDataForKey:(NSString *)key
{
    return [data objectForKey:key];
}

-(id)shareInstanceFor:(Class) aclass
{
    NSString * className = [NSString stringWithFormat:@"%@",aclass];

    @synchronized(className){
        id shareData = [self getShareDataForKey:className];
        if (shareData == nil) {
            shareData = [[NSClassFromString(className) allocWithZone:NULL] init];
            [self setShareData:shareData forkey:className];
        }
        return shareData;
    }
}

-(id) shareInstanceFor:(Class)aclass category:(NSString *)key
{
    NSString *className = [NSString stringWithFormat:@"%@",aclass];
    NSString *classkey = [NSString stringWithFormat:@"%@+%@",aclass,key];
    @synchronized(classkey){
        id shareData = [self getShareDataForKey:classkey];
        if (shareData == nil) {
            shareData = [[NSClassFromString(className) allocWithZone:NULL] init];
            [self setShareData:shareData forkey:classkey];
        }
        return shareData;
    }
}

@end

id SingleForClass(Class a)
{
    return [SingleFactory shareInstanceFor:a];
}
新建单例Model 之 Person类:
编辑Person.h如下:
//
//  Person.h
//  单例模式的简单使用
//
//  Created by apple on 15/9/28.
//  Copyright (c) 2015年 LiuXun. All rights reserved.
//

#import <Foundation/Foundation.h>
@interface Person : NSObject
@property(nonatomic, strong) NSString *name;
@property (nonatomic, assign) int  age;
@property (nonatomic, assign) BOOL isMan;

+(Person *)shareInstance;
-(id) initWith:(NSString *) nam andAge:(int) age andSex:(BOOL) isman;

@end
编辑Person.m如下:
//
//  Person.m
//  单例模式的简单使用
//
//  Created by apple on 15/9/28.
//  Copyright (c) 2015年 LiuXun. All rights reserved.
//

#import "Person.h"

@implementation Person
 /*方式一: 利用synchronized为对象加锁实现同步访问*/
//+(Person *)shareInstance
//{
//    static Person *person = nil;
//    @synchronized(self)   // 主要防止异步访问这个类的对象
//    {
//        if (!person) {
//            person = [[super allocWithZone:NULL] init];
//        }
//    }
//    return person;
//}



/*方式二: 利用dispatch_once方法实现    dispatch_once方法比加锁要提高速度*/
 +(Person *)shareInstance
{
    static Person *person = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        person = [[super allocWithZone:NULL] init];
    });
    return person;
}

/*因为alloc方法会调用allocWithZone方法,为了避免单例遗漏,在
 allocWithZone 调用创建单例对象的类方法
 */
+(instancetype) allocWithZone:(struct _NSZone *)zone
{
  return [self shareInstance];  
}

-(id) initWith:(NSString *) nam andAge:(int) age andSex:(BOOL) isman
{
    if (self = [super init]) {
        self.name = nam;
        self.age = age;
        self.isMan = isman;
    }
    return self;
}

-(NSString *)description     /*重写此方法便于打印调试*/
{
    NSString *t = [NSString stringWithFormat:@"%@-%d-%d",self.name,self.age,self.isMan];
    return t;
}
@end
新建普通Model类——BooK类和Student类如下:
Book.h
//
//  Book.h
//  单例模式的简单使用
//
//  Created by apple on 15/9/28.
//  Copyright (c) 2015年 LiuXun. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface Book : NSObject

@property(nonatomic, strong) NSString *bookName;
@property (nonatomic, assign) int numberOfPage;
@property (nonatomic, strong) NSString *author;

-(id) initWithN:(NSString *)bNam andP:(int) pages andAuthor:(NSString *)auth;

@end
Book.m
//
//  Book.m
//  单例模式的简单使用
//
//  Created by apple on 15/9/28.
//  Copyright (c) 2015年 LiuXun. All rights reserved.
//

#import "Book.h"

@implementation Book

-(id) initWithN:(NSString *)bNam andP:(int) pages andAuthor:(NSString *)auth
{
    if (self = [super init]) {
        self.bookName = bNam;
        self.author = auth;
        self.numberOfPage = pages;
    }
    return self;
}

-(NSString *) description
{
    NSString *t = [NSString stringWithFormat:@"%@-%d-%@",self.bookName,self.numberOfPage,self.author];
    return t;
}
@end
Student.h
//
//  Student.h
//  单例模式的简单使用
//
//  Created by apple on 15/9/28.
//  Copyright (c) 2015年 LiuXun. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface Student : NSObject

@property(nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSString *ID;
@property (nonatomic, strong) NSString *school;

-(id) initWithNam:(NSString *) nam andID:(NSString *) Id andSchool:(NSString *)school;
@end
Student.m
//
//  Student.m
//  单例模式的简单使用
//
//  Created by apple on 15/9/28.
//  Copyright (c) 2015年 LiuXun. All rights reserved.
//

#import "Student.h"

@implementation Student

-(id) initWithNam:(NSString *) nam andID:(NSString *) Id andSchool:(NSString *)school
{
    if (self = [super init]) {
        self.name = nam;
        self.ID =Id;
        self.school = school;
    }
    return self;
}
-(NSString *)description
{
    NSString *t = [NSString stringWithFormat:@"%@-%@-%@",self.name,self.ID,self.school];
    return t;
}

@end

新建pch文件PrefixHeader.pch,把所有文件的头文件统统导入:
//
//  PrefixHeader.pch
//  单例模式的简单使用
//
//  Created by apple on 15/9/28.
//  Copyright (c) 2015年 LiuXun. All rights reserved.
//

#ifndef __________PrefixHeader_pch
#define __________PrefixHeader_pch

#import "AppDelegate.h"

#import "ViewController.h"
#import "ViewController2.h"

#import "Person.h"
#import "Student.h"
#import "Book.h"

#import "NSSingletonFactory.h"
 
#endif
编辑第一个控制器如下:
viewController.m
//
//  ViewController.m
//  单例模式的简单使用
//
//  Created by apple on 15/9/28.
//  Copyright (c) 2015年 LiuXun. All rights reserved.
//

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController
NSString *  str;
Student * stu ;  // 切记:要在其他文件使用的全局变量必须写在当前的.m文件中
/*extern可以将指定的本文件内对象或变量跨文件使用,
 即专门用于定义全局变量*/
- (void)viewDidLoad {
    [super viewDidLoad];
    str = @"XXXXXXXX";
    printf("===========在第一个控制器中的内容如下:==========\n");
    Person *per1 = [[Person alloc] initWith:@"刘勋" andAge:22 andSex:YES];
    NSLog(@"单例per1= %@",per1);

    Person *per2 = [[Person alloc] init];
    NSLog(@"单例per2= %@",per2);
    
    /*单例即 ——对于此类的对象在整个程序中之且存在一个,无论调用那个方法
     修改的都是一个对象的值*/
    Person *per3 = [[Person alloc] initWith:@"刘举" andAge:24 andSex:YES];
    NSLog(@"单例per3= %@",per3);
    
     Person* per4 = [[Person alloc] init];
    NSLog(@"单例per4= %@",per4);
   stu = [[Student alloc] initWithNam:@"小学生" andID:@"123456" andSchool:@"黄淮学院"];
    NSLog(@"全局stu=%@",stu);
    
    AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    delegate.strAppDelegate = @"AppDelegate中的全局变量";
    NSLog(@"AppDelegate全局=%@",delegate.strAppDelegate);
    
    Book *book = SingleForClass([Book class]);
    book.bookName =@"老人与海";
    book.numberOfPage = 500;
    book.author = @"海明威";
    NSLog(@"book= %@",book);
    ViewController2 *vc2 = [[ViewController2 alloc] init];
    [self presentViewController:vc2 animated:YES completion:nil];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end
viewController2.h
//
//  ViewController2.h
//  单例模式的简单使用
//
//  Created by apple on 15/9/28.
//  Copyright (c) 2015年 LiuXun. All rights reserved.
//

#import <UIKit/UIKit.h>

@class Student;
extern Student *stu;  // 使用extern定义全局变量的第一种表现形式
@interface ViewController2 : UIViewController

@end
viewController2.m
//
//  ViewController2.m
//  单例模式的简单使用
//
//  Created by apple on 15/9/28.
//  Copyright (c) 2015年 LiuXun. All rights reserved.
//

#import "ViewController2.h"

@interface ViewController2 ()

@end
@implementation ViewController2
// 方式二:extern传递传递任意变量
extern NSString *str;  // extern定义全局变量的第二种表现形式

- (void)viewDidLoad {
    [super viewDidLoad];
    printf("===========在第二个控制器中的内容如下:==========\n");
    Person *per5 = [[Person alloc] init];
    NSLog(@"单例per5= %@",per5);
    NSLog(@"全局stu= %@",stu);
    NSLog(@"全局str= %@",str);
    
    AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    NSLog(@"AppDelegate全局=%@",delegate.strAppDelegate);
    
    Book *book2 = SingleForClass([Book class]);
    NSLog(@"book2= %@",book2);

}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end
运行结果如下所示:









你可能感兴趣的:(使用全局变量的四种方式:extern、AppDelegate、定义单例对象、NSUserDefaults 和单例工厂的使用方法)