iOS单例模式以及多线程使用深入详解

说到单例和多线程我们先来看看这两个的概念

一.多线程

说起多线程不得不说一线什么是线程,说到线程,脑海里有浮出一个概念,那就是进程

1.什么是进程

进程官方概念是资源分配的基本单位,按照我自己的理解,简单来说就是计算机运行一个程序就是一个进程,因为这是一个比较抽象的概念,每个人的理解都不一样,但是意思却是那么个意思

2.什么是线程

线程是CPU独立运行和独立调度的基本单位,每个进程至少有一个线程,是进程的执行路径

3.多线程

多线程是指一个进程同时执行多条路径

4.iOS中多线程通常使用NSThread、NSOperation和GCD

a、NSThread的几种开线程方式

*先创建,后启动

NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];

[thread start];

*直接启动

[NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];

[self performSelectorInBackground:@selector(run) withObject:nil];

*其他方式

NSThread *current = [NSThread currentThread];

+ (NSThread *)mainThread; // 获得主线程

*线程间的通信

performSelectorOnMainThread.....


b、GCD队列类型

*并发队列

获得全局的并发队列: dispatch_get_global_queue

*串行队列

dispatch_queue_create

*主队列

dispatch_get_main_queue

*线程间的通信

dispatch_async(

dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

   // 执行耗时的异步操作...

   dispatch_async(dispatch_get_main_queue(), ^{

       // 回到主线程,执行UI刷新操作

   });

});

*其他用法

dispatch_once

dispatch_after

dispatch_group_async\dispatch_group_notify

c、NSOperation和NSOperationQueue

*基本使用创建其子类

NSInvocationOperation

NSBlockOperation

*最大并发数量的设置

- (void)setMaxConcurrentOperationCount:(NSInteger)cnt;

*设置一依赖

[operationB addDependency:operationA]; // 操作B依赖于操作A

二、单例

1.什么是单例

永远只分配一块内存来创建对象

提供一个类方法,返回内部唯一的一个实例

最好保证init方法也只初始化一次

2.单例模式的使用场合

如果在整个应用程序中,共享一份资源,这个资源只需要创建初始化一次

3.单例的应用

我们说了,单例的使用是整个应用程序中共享一份资源,这个资源只需要创建初始化一次,所以我们保证共享资源的这个类(继承NSObject)创建出来的对象只有一个

先来看一下一般单例在ARC中的写法,我们再来说一下为什么要这么写

#import "Tools.h"


@implementation Tools

// 创建静态对象 防止外部访问

static Tools *_instance;

- (id)init

{

    if (self = [super init]) {

        static dispatch_once_t onceToken;

        dispatch_once(&onceToken, ^{

            // 加载资源

            

        });

    }

    return self;

}


+(instancetype)allocWithZone:(struct _NSZone *)zone

{

    //    @synchronized (self) {

    //        // 为了防止多线程同时访问对象,造成多次分配内存空间,所以要加上线程锁

    //        if (_instance == nil) {

    //            _instance = [super allocWithZone:zone];

    //        }

    //        return _instance;

    //    }

    // 也可以使用一次性代码

    static dispatch_once_t onceToken;

    dispatch_once(&onceToken, ^{

        if (_instance == nil) {

            _instance = [super allocWithZone:zone];

        }

    });

    return _instance;

}

// 为了使实例易于外界访问 我们一般提供一个类方法

// 类方法命名规范 share类名|default类名|类名

+(instancetype)shareTools

{

    //return _instance;

    // 最好用self 用Tools他的子类调用时会出现错误

    return [[self alloc]init];

}

// 为了严谨,也要重写copyWithZone 和 mutableCopyWithZone

-(id)copyWithZone:(NSZone *)zone

{

    return _instance;

}

-(id)mutableCopyWithZone:(NSZone *)zone

{

    return _instance;

}


为什么要这么写呢,解释一下,一般我们在创建一个对象的时候,通常都要初始化这个对象,例如我在使用Tool这个共享类的时候我需要初始化一下

Tool *tool1 = [[Tool alloc] init];

那么,我每次调alloc,就需要给这个对象分配一个内存空间,造成资源的浪费,感兴趣的可以打印tool的地址试一下,所以我们需要重写

+(instancetype)allocWithZone:(struct _NSZone *)zone

这个方法,让线程加锁,无论初始化多少次,保证之分配一次内存空间

现在,再来看一下,我们每次调alloc返回的都是同一个对象,那么我们使用类方法是不是比较方便呢,所以使用

+(instancetype)shareTool

{

    //return _instance;

    // 最好用self 用Tools他的子类调用时会出现错误

    return [[self alloc]init];

}

这里还有另一种完整的写法,这里每次alloc还是没次会调[super init]这个方法

+ (instancetype)sharedTools

{

    // 里面的代码永远只执行1次

    static dispatch_once_t onceToken;

    dispatch_once(&onceToken, ^{

        _instance = [[self alloc] init];

    });

    

    // 返回对象

    return _instance;

}

MRC中单例代码实现
配置好MRC环境之后,在ARC代码基础上重写下面的三个方法即可

-(oneway void)release

{

    

}

-(instancetype)retain

{

    return _instance;

}

-(NSUInteger)retainCount

{

    return MAXFLOAT;

}


三、单例的高级写法

如果想要一劳永逸,我们将面临两个问题
1:如何写一份单例代码在ARC和MRC环境下都适用?
2:如何使一份单例代码可以多个类共同使用
为了解决这两个问题,我们可以在 PCH文件使用代参数的宏和条件编译

利用条件编译来判断是ARC还是MRC环境

创建一个名叫Singleton的PCH文件

// ## : 连接字符串和参数

#define singleton_h(name) + (instancetype)shared##name;//传入的单例名叫什么,因为所有单例写法是一样的,只是名字不同而已


#if __has_feature(objc_arc) // 判断是否是ARC


#define singleton_m(name) \

static id _instance; \

+ (id)allocWithZone:(struct _NSZone *)zone \

{ \

    static dispatch_once_t onceToken; \

    dispatch_once(&onceToken, ^{ \

        _instance = [super allocWithZone:zone]; \

    }); \

    return _instance; \

} \

 \

+ (instancetype)shared##name \

{ \

    static dispatch_once_t onceToken; \

    dispatch_once(&onceToken, ^{ \

        _instance = [[self alloc] init]; \

    })\

    return _instance; \

} \

+ (id)copyWithZone:(struct _NSZone *)zone \

{ \

    return _instance; \

}


#else // 非ARC


#define singleton_m(name) \

static id _instance; \

+ (id)allocWithZone:(struct _NSZone *)zone \

{ \

static dispatch_once_t onceToken; \

dispatch_once(&onceToken, ^{ \

_instance = [super allocWithZone:zone]; \

}); \

return _instance; \

} \

\

+ (instancetype)shared##name \

{ \

static dispatch_once_t onceToken; \

dispatch_once(&onceToken, ^{ \

_instance = [[self alloc] init]; \

}); \

return _instance; \

} \

\

- (oneway void)release \

{ \

\

} \

\

- (id)autorelease \

{ \

return _instance; \

} \

\

- (id)retain \

{ \

return _instance; \

} \

\

- (NSUInteger)retainCount \

{ \

return 1; \

} \

\

+ (id)copyWithZone:(struct _NSZone *)zone \

{ \

return _instance; \

}


#endif

在每个单例里面的使用,导入头文件HMAudioTool.h

#import <Foundation/Foundation.h>

#import "Singleton.h"


@interface HMAudioTool : NSObject

singleton_h(AudioTool)

@end



HMAudioTool.m

#import "HMAudioTool.h"


@interface HMAudioTool()

@end


@implementation HMAudioTool

定义一份变量(整个程序运行过程中, 只有1份)

//static id _instance;


- (id)init

{

    if (self = [super init]) {

        static dispatch_once_t onceToken;

        dispatch_once(&onceToken, ^{

            // 加载资源

            

        });

    }

    return self;

}

singleton_m(AudioTool)



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
首先,需要在iOS项目中添加AssimpKit库。可以通过CocoaPods添加: ``` pod 'AssimpKit', '~> 3.0' ``` 或者手动下载并导入AssimpKit.framework。 接下来,需要将FBX模型文件添加到Xcode项目中。可以将文件直接拖拽到项目中或者通过“Add Files to…”选项添加。 在代码中使用AssimpKit加载FBX模型的步骤如下: 1. 导入AssimpKit库 ``` #import <AssimpKit/AssimpKit.h> ``` 2. 创建AssimpKit的场景对象 ``` NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"model" ofType:@"fbx"]; NSError *error; SCNScene *scene = [AssimpKitSceneLoader loadSceneFromFile:modelPath postProcessSteps:AssimpKit_PostProcess_Triangulate error:&error]; ``` 其中,`modelPath`为FBX模型文件的路径,`postProcessSteps`参数指定了模型加载时需要进行的后处理步骤,例如三角化、转换坐标系等。 3. 将场景对象中的模型添加到SceneKit场景中 ``` for (SCNNode *node in scene.rootNode.childNodes) { [sceneKitScene.rootNode addChildNode:node]; } ``` 其中,`sceneKitScene`为SceneKit场景对象。 4. 设置SceneKit场景的渲染器 ``` sceneKitView.scene = sceneKitScene; sceneKitView.allowsCameraControl = YES; sceneKitView.autoenablesDefaultLighting = YES; ``` 其中,`sceneKitView`为SceneKit视图对象。 5. 运行项目,即可在模拟器或真机上看到加载的模型。 需要注意的是,AssimpKit不支持所有的FBX模型文件,可能会存在加载失败的情况。如果需要加载较为复杂的模型,建议使用其他的模型加载库。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值