您的位置:首页 > 移动开发 > Objective-C

【iOS开发之Objective-C】单例的创建

2015-07-24 20:44 423 查看

1.什么是单例

在回答这个问题之前我们先来看看官方帮助文档是怎么写的。



这个是苹果给的解释,从这个示意图我们也可以叫较为清晰的明白是什么意思了。一个单例类无论应用程序请求多少回他都返回相同的实例。一个单例类只能有一个实例。

2.什么时候使用单例

还看看上面截图英文的最后一句,大意是:使用单例的情况下这是可取的的单点控制,如类提供一些一般性的服务或资源。换句话说就是,如果这个类是一个公共的部分,那么我们就可以来创建一个单例类了。

3.单例类有什么作用

下面是苹果官方文档的第二段:



主要看这句:A singleton class also prevents callers from copying, retaining, or releasing the instance.

大意是:一个单例类还可以防止调用者复制、保留或释放实例。水平有限暂时没有什么个人理解。O(∩_∩)O~

4.单例的具体举例

单例的文字描述也看了,图也看了。那么单例到底是个什么?下面就以一个小得工程来解释什么单例。

我们读书的时候通常都是一个班级会有一个班主任,教我们课程的会有什么物理老师和就业老师等。这些非班主任的老师一般都是会教几个班级的课程,但是一个班主任一般只会是一个班级的班主任。好了下面有这么一个问题:假设我们每个班级只有班主任有权利修改学生的分数,如果物理老师和就业老师要修改学生的分数,他们就只能是向班主任老师提出修改申请,告诉班主任老师他们想修改谁的分数,修改为多少。

问题来了,我们要怎么要分析这个问题呢?

第一步:分析需求;老师向班主任申请修改学生分数;

第二步:找对象抽象类;对象有班主任、物理老师、就业老师和学生;类有班主任类、物理老师类、就业老师类和学生类。

为什么不能把老师归为一个类呢?或是把物理老师和就业老师归为一个类?我们举这个例子是单例的一个练习。班主任老师和物理老师、就业老师有不同的行为,物理老师和就业老师不能修改学生分数,所以不能归为一类。物理老师和就业老师也不能归为一类,这个练习是单例的一个小练习,你硬是要归为一类也可以。( ⊙o⊙ )

第三步:找属性和行为;学生有分数和姓名这两个属性。物理老师和就业老师有向班主任老师申请修改某个学生的分数的行为。班主任老师才有修改学生分数的行为,修改之前必须要先存在这么学生,所以还有一个增加学生的行为;

第四步:类的具体实现:

1)学生部分:

#import <Foundation/Foundation.h>
@interface Student : NSObject{
NSString * _name;  //姓名
NSUInteger _score; //分数
}
- (void)setName:(NSString *)name;
- (void)setScore:(NSUInteger)score;
- (NSString *)getName;
- (NSUInteger )getScore;
@end


#import "Student.h"
@implementation Student

- (void)setName:(NSString *)name{
_name = name;
}
- (void)setScore:(NSUInteger)score{
_score = score;
}
- (NSString *)getName{
return _name;
}
- (NSUInteger)getScore{
return _score;
}
@end
为什么学生可以设置分数和姓名呢?因为没有这两个方法,我们不能个他得属性写入数据啊。

2)班主任老师:

#import <Foundation/Foundation.h>
#import "Student.h"
@interface ClassTeacher : NSObject{
NSMutableArray * _array; //提供一个容器,相当于花名册
}
- (instancetype)init;
- (void)addSudentInfoWithName:(NSString *)name withScore:(NSUInteger)score;
- (void)modifyStudentScoreWithName:(NSString *)name withScore:(NSUInteger)score;

- (void)showAllStudentInfo;
+ (ClassTeacher *)newAClassTeacher;
@end
#import "ClassTeacher.h"

@implementation ClassTeacher
- (instancetype)init{
self = [super init];
if (self) {
_array = [[NSMutableArray alloc] init];
}
return self;
}
//增加
- (void)addSudentInfoWithName:(NSString *)name withScore:(NSUInteger)score{
Student * student = [[Student alloc] init];
[student setName:name];
[student setScore:score];
[_array addObject:student];
}
//修改
- (void)modifyStudentScoreWithName:(NSString *)name withScore:(NSUInteger)score{
for (int i = 0;i < [_array count]; i ++) {
if ([name isEqualToString:[_array[i] getName]]) {
[_array[i] setScore:score];
NSLog(@"修改完成");
return;
}
}
}
+ (ClassTeacher *)newAClassTeacher{
static ClassTeacher * wu = nil;
if (!wu) {
wu= [[ClassTeacher alloc] init];
}
<p style="margin-top: 0px; margin-bottom: 0px;">        NSLog(@"%p",wu); //显示创建的班主任这个对象的指针地址</p>	return wu;
}
- (void)showAllStudentInfo{ //打印显示学生信息
for (int i = 0; i < [_array count]; i ++) {
NSLog(@"姓名:%@  分数:%ld",[_array[i] getName],[_array[i] getScore]);
}
}
@end


3)物理老师和就业老师:

//物理老师
#import "PhysicsTeacher.h"
@implementation PhysicsTeacher
- (void)PhysicsTeacherSetScore:(NSInteger)score withName:(NSString *)name{
ClassTeacher * wu = [ClassTeacher newAClassTeacher];
[wu modifyStudentScoreWithName:name withScore:score];
}
@end
#import <Foundation/Foundation.h>
#import "ClassTeacher.h"
@interface PhysicsTeacher : NSObject
- (void) PhysicsTeacherSetScore:(NSInteger)score withName:(NSString *)name;
@end
//就业老师
#import <Foundation/Foundation.h>
#import "ClassTeacher.h"
@interface JobTeacher : NSObject
- (void) jobTeacherSetScore:(NSInteger)score withName:(NSString *)name;
@end
#import "JobTeacher.h"
@implementation JobTeacher
- (void)jobTeacherSetScore:(NSInteger)score withName:(NSString *)name{
ClassTeacher * wu = [ClassTeacher newAClassTeacher];
[wu modifyStudentScoreWithName:name withScore:score];
}
@end
在这个例子里面物理老师和就业老师有相同的行为。

4)主程序和输出:

主程序就很简单了,显示班主任老师设置两个学生姓名和分数,并输出设置的结果。物理老师修改一个,就业老师修改一个,再输出修改后的结果。

#import <Foundation/Foundation.h>
#import "PhysicsTeacher.h"
#import "ClassTeacher.h"
#import "JobTeacher.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
ClassTeacher * xiaoli = [ClassTeacher newAClassTeacher];
[xiaoli addSudentInfoWithName:@"小明" withScore:78];
[xiaoli addSudentInfoWithName:@"小丽" withScore:87];
//显示增加了的学生的信息
[xiaoli showAllStudentInfo];
//就业老师修xiaozhang改小明的分数
JobTeacher * xiaozhang = [[JobTeacher alloc] init];
[xiaozhang jobTeacherSetScore:88 withName:@"小明"];
//物理老师xiaozhou修改小丽额分数
PhysicsTeacher * xiaozhou  = [[PhysicsTeacher alloc] init];
[xiaozhou PhysicsTeacherSetScore:77 withName:@"小丽"];
//显示修改后的学生的信息
[xiaoli showAllStudentInfo];
}
return 0;
}
下面我来看看程序的输出:

2015-07-24 20:07:48.874 1.单例[2248:303] 0x100602de0
2015-07-24 20:07:48.876 1.单例[2248:303] 姓名:小明  分数:78
2015-07-24 20:07:48.877 1.单例[2248:303] 姓名:小丽  分数:87
2015-07-24 20:07:48.878 1.单例[2248:303] 0x100602de0
2015-07-24 20:07:48.878 1.单例[2248:303] 修改完成
2015-07-24 20:07:48.879 1.单例[2248:303] 0x100602de0
2015-07-24 20:07:48.879 1.单例[2248:303] 修改完成
2015-07-24 20:07:48.880 1.单例[2248:303] 姓名:小明  分数:88
2015-07-24 20:07:48.882 1.单例[2248:303] 姓名:小丽  分数:77
Program ended with exit code: 0
最后我们看见的是,确实两个学生的分数都被修改了。同时也输出了三个一样的十六进制数据,这个就是xiaoli老师这个对象的在内存中的地址。说明我们第一次创建班主任xiaoli老师这个对象的时候,我们就给他分配了一次内存地址,

当我们物理老师和就业老师通知班主任老师的时候我们就不会再次重复的创建xiaoli班主任老师了。

5.单例的实现过程

单例的实现过是使用的一个加方法,加方法就是只有类才能使用的方法。关于加方法个减方法的区别,以后再说。

+ (ClassTeacher *)newAClassTeacher{
static ClassTeacher * wu = nil;
if (!wu) {
wu= [[ClassTeacher alloc] init];
}
<p style="margin-top: 0px; margin-bottom: 0px;">        NSLog(@"%p",wu); //显示创建的班主任这个对象的指针地址</p>	return wu;
}
主要是这一句:

<span style="font-size:18px;">static ClassTeacher * wu = nil;</span>
这里有两个关键点:一个是static关键字和空指针nil;也就是说每次我们在使用这个加方法取创建对象的时候我们就不会重复创建了。if(!wu)这个if语句,因为第一次还没这个wu的对象,我们就需要创建一个,以后有了我们就不会重复创建了。

再来看看物理老师和就业老师中的两个类似的方法:

- (void)jobTeacherSetScore:(NSInteger)score withName:(NSString *)name{
ClassTeacher * <strong><span style="font-size:14px;color:#ff0000;">wu</span></strong> = [ClassTeacher newAClassTeacher];
[wu modifyStudentScoreWithName:name withScore:score];
}
我们都是使用的一个加方法来创建了一个班主任wu的对象 在物理老师和就业老师的这两个方法中,注意这个大写的红色的wu,我们设置为一个是wu一个是liu也是可以的。

ClassTeacher * wu = [ClassTeacher newAClassTeacher];
再是班主任wu这个对象调用修改学生分数的方法去修改某个学生的分数:

[wu modifyStudentScoreWithName:name withScore:score];
这样,每次当物理老师或是就业老师通知班主任修改某个学生的分数的时候就不会修改到其他班级的同学(假设有同名同姓的学生存在)去了。从三个输出的十六进制的地址:
0x100602de0
我们就可以可以看出,每次我们都是请求的这一个对象。也就说明我们的单例创建是没问题的。

单例的创建还有什么方法,我暂时还没看见,目前就知道这一种,听说这是常用的一种。一旦我们理解了,记住它就不难了。

6.总结

1⃣️:什么是单例
2⃣️:什么时候使用单例

3⃣️:单例怎么创建

最后:
关于加方法和减方法以后再写。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: