Grand Central Dispatch (GCD) Reference

Grand Central Dispatch (GCD) comprises language features, runtime libraries, and system enhancements that provide systemic, comprehensive improvements to the support for concurrent code execution on multicore hardware in iOS and OS X.

GCD拥有丰富的语言特性,多样的运行库以及能增强系统效率,对于硬件上多核处理器提供了广泛地系统级别的优化,在多核的iOS OS X硬件体系中,高并发执行能力得到有效地提升.

The BSD subsystem, CoreFoundation, and Cocoa APIs have all been extended to use these enhancements to help both the system and your application to run faster, more efficiently, and with improved responsiveness. Consider how difficult it is for a single application to use multiple cores effectively, let alone doing it on different computers with different numbers of computing cores or in an environment with multiple applications competing for those cores. GCD, operating at the system level, can better accommodate the needs of all running applications, matching them to the available system resources in a balanced fashion.

BSD子系统,CoreFoundation以及Cocoa中的许多APIs都已经大量使用这些新的特性来帮助系统以及你的应用程序提升性能,使其运行得更快,提升交互体验.考虑到要让一款应用能够很有效地利用多核处理器,不管是在不同的电脑上(这个电脑有着不同数量的处理器)或者是同一台电脑上不同应用如何分配多个处理器.GCD,在系统级别上进行运作,能够很好地对所有运行中的程序进行优化,让他们充分利用系统资源的同时,达到一个美妙的平衡.

以上是官方文档前两段的翻译,正如描述中所说,GCD偏向系统调用,更加偏向于底层的函数,效率很高,我将我对于GCD使用的理解加以汇总.

线程是最小的执行单位,而线程需要在指定的线程池中才能够执行,以下是创建线程池的方法.

dispatch_queue_t dispatch_queue_create(
   const char *label
   dispatch_queue_attr_t attr);

#pragma mark - 创建并行队列线程池,任务并发执行,一起执行
NS_INLINE dispatch_queue_t GCD_create_concurrent_queue(NSString *queueName)
{
    // DISPATCH_QUEUE_CONCURRENT
    // 线程池提供多个线程来执行任务,所以可以按序启动多个任务并发执行
    dispatch_queue_t concurrentQ
    = dispatch_queue_create([queueName cStringUsingEncoding:NSUTF8StringEncoding],
                            DISPATCH_QUEUE_CONCURRENT);
    
    return concurrentQ;
}
#pragma mark - 创建串行队列线程池,任务依次执行,上一个执行完毕才会执行下一个任务
NS_INLINE dispatch_queue_t GCD_create_serial_queue(NSString *queueName)
{
    // DISPATCH_QUEUE_SERIAL
    // 线程池只提供一个线程用来执行任务,所以后一个任务必须等到前一个任务执行结束才能开始(已经测试,一个任务执行完毕后才回去执行另外一个任务)
    dispatch_queue_t serialQ
    = dispatch_queue_create([queueName cStringUsingEncoding:NSUTF8StringEncoding],
                            DISPATCH_QUEUE_SERIAL);
    
    return serialQ;
}

#pragma mark - 销毁线程池
NS_INLINE void GCD_release_queue(dispatch_queue_t queue)
{
#if __has_feature(objc_arc)
#else
    dispatch_release(queue);
#endif
}

以下是创建一个单一线程的方法

#pragma mark - 在指定的线程池中执行该线程
NS_INLINE void GCD_dispatch_async(dispatch_queue_t queue, void (^block)())
{
    //在指定的线程池中执行操作
    dispatch_async(queue, ^{
        block();
    });
}

串行线程池

并发线程池

系统默认就有一个串行队列main_queue和并行队列global_queue,我对其进行了宏定义

// 系统子线程池(并发执行)
#define SYS_CONCURRENT_QUEUE_H  dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)
#define SYS_CONCURRENT_QUEUE_D  dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
#define SYS_CONCURRENT_QUEUE_L  dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0)
#define SYS_CONCURRENT_QUEUE_B  dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)
// 系统主线程池(序列执行)
#define SYS_SERIAL_QUEUE      dispatch_get_main_queue()

所以,一般是这么用的,子线程处理数据,结束后把数据传递到主线程,让主线程来更新UI

GCD_dispatch_async(SYS_CONCURRENT_QUEUE_L, ^{
    // long-running task code here
    GCD_dispatch_async(SYS_SERIAL_QUEUE, ^{
        // update UI code here
    });
});

线程的延时操作

#pragma mark - [GCD] 执行某种线程池中的延时操作
NS_INLINE void GCD_DelaySeconds(int64_t seconds, dispatch_queue_t queue, void (^block)(dispatch_queue_t queue))
{
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, seconds * NSEC_PER_SEC);
    dispatch_after(popTime, queue, ^(void){
        block(queue);
    });
}

线程组

#define SYS_CREATE_GROUP      dispatch_group_create()

#pragma mark - 线程组,用以监听所有的线程是否已经执行完毕了
NS_INLINE void GCD_dispatch_group_async(dispatch_group_t group, dispatch_queue_t queue, void (^block)())
{
    dispatch_group_async(group, queue, block);
}

以下是测试依次执行任务(线程)的代码以及结果,从现象以及结果可以看出,只有一个任务完整地执行完毕后才会执行下一个任务,这种线程池一次只处理一个任务

NS_INLINE NSData * dataFromNetUrlPath(NSString *path)
{
    //网络数据URL
    return [NSData dataWithContentsOfURL:[NSURL URLWithString:path]];
}

以下是测试并发执行任务(线程)的代码以及结果

即使是延时的操作都存在序列执行以及并发执行的区别,看结果

group也存在并发非并发问题,如下所示

GCD定时器

#pragma mark - 创建定时器
NS_INLINE dispatch_source_t GCD_create_timer(int64_t seconds, dispatch_queue_t queue, void (^block)(dispatch_source_t timer))
{
    //创建Timer
    dispatch_source_t _timer =
    dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
    
    //使用dispatch_source_set_timer函数设置timer参数
    dispatch_source_set_timer(_timer,
                              dispatch_time(DISPATCH_TIME_NOW, 0),
                              seconds * NSEC_PER_SEC,
                              0);
    
    //设置回调
    dispatch_source_set_event_handler(_timer, ^(){
                                          block(_timer);
                                      });
    
    //dispatch_source默认是Suspended状态,通过dispatch_resume函数开始它
    dispatch_resume(_timer);
    return _timer;
}

#pragma mark - 销毁定时器(记得释放定时器,ARC与非ARC都支持)
NS_INLINE void GCD_release_timer(dispatch_source_t timer)
{
#if __has_feature(objc_arc)
#else
    dispatch_release(timer);
#endif
}

GCD注意事项:

1. 选用了系统主线程池 dispatch_get_main_queue() 后,如果在这个线程池中执行了阻塞操作(例如执行了网络请求,但没有网络链接,网络超时),是会阻塞UI界面效果的,虽然,表面上看起来,启动了这个线程后就接着往下面执行了,这也说明了一个问题,UI控件的加载都是在主线程池中加载的,而主线程池本身就是串行线程池,所以,如果你写的代码在 dispatch_get_main_queue() 有着阻塞操作,会直接影响用户体验.

2. 同步线程 dispatch_sync 可以理解为一个代码块,必须执行完这个代码块之后才能往下面执行,但是,它不能在当前的线程池中执行,否则会造成死锁,要说用途,本人还没有研究出来^_^......

Calls to dispatch_sync() targeting the current queue will result in dead-lock

附录:

以下是本人自己封装的GCD类,支持ARC与非ARC,包含了GCD的queue,group以及semaphore,其属于初级封装,但见名知意.

提供源码以及使用方法如下

YXGCD.h

//
// YXGCD.h
//
// http://home.cnblogs.com/u/YouXianMing/
//
// Created by YouXian on 14-4-9.
// Copyright (c) 2014年 Y.X. All rights reserved.
// #import <Foundation/Foundation.h> // 系统子线程池(并发执行)
#define SYS_CONCURRENT_QUEUE_H dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)
#define SYS_CONCURRENT_QUEUE_D dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
#define SYS_CONCURRENT_QUEUE_L dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0)
#define SYS_CONCURRENT_QUEUE_B dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0) // 系统主线程池(序列执行)
#define SYS_SERIAL_QUEUE dispatch_get_main_queue()
#define SYS_UI_QUEUE dispatch_get_main_queue() //优先级枚举类型
typedef enum { HIGH_PRIORITY = DISPATCH_QUEUE_PRIORITY_HIGH,
LOW_PRIORITY = DISPATCH_QUEUE_PRIORITY_LOW,
DEFAULT_PRIORITY = DISPATCH_QUEUE_PRIORITY_DEFAULT,
BACKGROUND_PRIORITY = DISPATCH_QUEUE_PRIORITY_BACKGROUND, } QUEUE_PRIORITY; @interface YXGCD : NSObject #pragma mark - GCD_queue
+ (dispatch_queue_t)createSerialQueueWithName:(NSString *)name;
+ (dispatch_queue_t)createConcurrentQueueWithName:(NSString *)name;
+ (void)releaseQueue:(dispatch_queue_t)queue;
+ (void)asyncInQueue:(dispatch_queue_t)queue block:(void (^)())block;
+ (void)syncInQueue:(dispatch_queue_t)queue block:(void (^)())block;
+ (void)queue:(dispatch_queue_t)queue
asyncInGroup:(dispatch_group_t)group
block:(void (^)())block;
+ (void)queue:(dispatch_queue_t)queue
notifyInGroup:(dispatch_group_t)group
block:(void (^)())block; #pragma mark - GCD_group
+ (dispatch_group_t)createGroup;
+ (void)releaseGroup:(dispatch_group_t)group;
+ (void)enterGroup:(dispatch_group_t)group;
+ (void)leaveGroup:(dispatch_group_t)group;
+ (void)waitGroup:(dispatch_group_t)group;
+ (void)explicitlyIndicatesGroup:(dispatch_group_t)group
asyncInQueue:(dispatch_queue_t)queue
block:(void (^)())block;
+ (void)waitGroup:(dispatch_group_t)group
asyncInQueue:(dispatch_queue_t)queue
before:(void (^)())before
after:(void (^)())after;
+ (void)waitGroup:(dispatch_group_t)group
forTime:(int64_t)time
asyncInQueue:(dispatch_queue_t)queue
before:(void (^)())before
after:(void (^)(long result))after; #pragma mark - GCD_semaphore
+ (dispatch_semaphore_t)createSemaphoreWithValue:(long)value;
+ (void)releaseSemaphore:(dispatch_semaphore_t)semaphore;
+ (void)signalForSemaphore:(dispatch_semaphore_t)semaphore;
+ (void)waitForSemaphore:(dispatch_semaphore_t)semaphore;
+ (void)waitForSemaphore:(dispatch_semaphore_t)semaphore forTime:(int64_t)time; @end

YXGCD.m

//
// YXGCD.m
//
// http://home.cnblogs.com/u/YouXianMing/
//
// Created by YouXian on 14-4-9.
// Copyright (c) 2014年 Y.X. All rights reserved.
// #import "YXGCD.h" @implementation YXGCD + (void)asyncInQueue:(dispatch_queue_t)queue block:(void (^)())block
{
dispatch_async(queue, ^{
block();
});
} + (void)syncInQueue:(dispatch_queue_t)queue block:(void (^)())block
{
dispatch_sync(queue, ^{
block();
});
} + (void)asyncInBackgroundWithPriority:(QUEUE_PRIORITY)type block:(void (^)())block
{
dispatch_async(dispatch_get_global_queue(type, ), ^{
block();
});
} + (dispatch_queue_t)createSerialQueueWithName:(NSString *)name
{
dispatch_queue_t serialQ
= dispatch_queue_create([name cStringUsingEncoding:NSUTF8StringEncoding],
DISPATCH_QUEUE_SERIAL); return serialQ;
} + (dispatch_queue_t) createConcurrentQueueWithName:(NSString *)name
{
dispatch_queue_t concurrentQ
= dispatch_queue_create([name cStringUsingEncoding:NSUTF8StringEncoding],
DISPATCH_QUEUE_CONCURRENT); return concurrentQ;
} + (void)asyncInGroup:(dispatch_group_t)group
inQueue:(dispatch_queue_t)queue
block:(void (^)())block
{
dispatch_group_async(group, queue, block);
} + (void)queue:(dispatch_queue_t)queue
asyncInGroup:(dispatch_group_t)group
block:(void (^)())block
{
dispatch_group_async(group, queue, block);
} + (void)queue:(dispatch_queue_t)queue
notifyInGroup:(dispatch_group_t)group
block:(void (^)())block
{
dispatch_group_notify(group, queue, ^{
block();
});
} + (dispatch_group_t)createGroup
{
return dispatch_group_create();
} + (void)enterGroup:(dispatch_group_t)group
{
dispatch_group_enter(group);
} + (void)leaveGroup:(dispatch_group_t)group
{
dispatch_group_leave(group);
} + (void)waitGroup:(dispatch_group_t)group
{
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
} + (void)explicitlyIndicatesGroup:(dispatch_group_t)group
asyncInQueue:(dispatch_queue_t)queue
block:(void (^)())block
{
dispatch_group_enter(group);
dispatch_async(queue, ^{
block();
dispatch_group_leave(group);
});
} + (void)waitGroup:(dispatch_group_t)group
asyncInQueue:(dispatch_queue_t)queue
before:(void (^)())before
after:(void (^)())after
{
dispatch_async(queue, ^{
before();
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
after();
});
} + (void)waitGroup:(dispatch_group_t)group
forTime:(int64_t)time
asyncInQueue:(dispatch_queue_t)queue
before:(void (^)())before
after:(void (^)(long result))after
{
dispatch_async(queue, ^{
before();
long result = dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, time));
after(result);
});
} + (dispatch_semaphore_t)createSemaphoreWithValue:(long)value
{
return dispatch_semaphore_create(value);
} + (void)signalForSemaphore:(dispatch_semaphore_t)semaphore
{
dispatch_semaphore_signal(semaphore);
} + (void)waitForSemaphore:(dispatch_semaphore_t)semaphore
{
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
} + (void)waitForSemaphore:(dispatch_semaphore_t)semaphore forTime:(int64_t)time
{
dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, time));
} + (void)releaseSemaphore:(dispatch_semaphore_t)semaphore
{
#if __has_feature(objc_arc)
#else
dispatch_release(semaphore);
#endif
} + (void)releaseGroup:(dispatch_group_t)group
{
#if __has_feature(objc_arc)
#else
dispatch_release(group);
#endif
} + (void)releaseQueue:(dispatch_queue_t)queue
{
#if __has_feature(objc_arc)
#else
dispatch_release(queue);
#endif
} @end

用法:

在主线程中操作

    [YXGCD asyncInQueue:SYS_UI_QUEUE block:^{
// 更新UI操作代码
}];

在子线程中操作

    [YXGCD asyncInQueue:SYS_CONCURRENT_QUEUE_D block:^{
// 阻塞操作
}];

子线程阻塞操作,主线程更新UI

    [YXGCD asyncInQueue:SYS_CONCURRENT_QUEUE_D block:^{
// 阻塞操作 [YXGCD asyncInQueue:SYS_UI_QUEUE block:^{
// 更新UI操作
}];
}];

创建一个串行线程池,执行完后释放线程池(英文解释的含义是,当所有的任务执行完毕后,才会销毁线程池)

    /*
When your application no longer needs the dispatch queue, it should release
it with the dispatch_release function. Any pending blocks submitted to a
queue hold a reference to that queue, so the queue is not deallocated until
all pending blocks have completed.
*/ // 创建一个序列线程
dispatch_queue_t serialQueue = [YXGCD createSerialQueueWithName:@"Y.X."]; // 序列任务1
[YXGCD asyncInQueue:serialQueue block:^{
// 你的代码
}]; // 序列任务2
[YXGCD asyncInQueue:serialQueue block:^{
// 你的代码
}]; // 释放线程池
[YXGCD releaseQueue:serialQueue];

使用GCD-group实现线程的等待操作

    // 创建一个GCD-group
dispatch_group_t group = [YXGCD createGroup]; // 系统主线程的一个任务,加入到了监听组中
[YXGCD queue:SYS_UI_QUEUE asyncInGroup:group block:^{
// 代码
}]; // 系统默认优先级的一个子线程任务,加入到了监听组中
[YXGCD queue:SYS_CONCURRENT_QUEUE_D asyncInGroup:group block:^{
// 代码
}]; // 系统默认优先级的一个子线程,监听上面的任务执行完毕后,才会执行任务
[YXGCD queue:SYS_CONCURRENT_QUEUE_D notifyInGroup:group block:^{
// 代码
}]; // 释放GCD-group
[YXGCD releaseGroup:group];

另外一种实现线程等待的方式

    // 创建一个GCD-group
dispatch_group_t group = [YXGCD createGroup]; // 在系统默认子线程中执行代码,注意enterGroup与leaveGroup必须成对出现
[YXGCD enterGroup:group];
[YXGCD asyncInQueue:SYS_CONCURRENT_QUEUE_D block:^{
// 代码 [YXGCD leaveGroup:group];
}]; // 在系统主线程中执行代码,注意enterGroup与leaveGroup必须成对出现
[YXGCD enterGroup:group];
[YXGCD asyncInQueue:SYS_UI_QUEUE block:^{
// 代码 [YXGCD leaveGroup:group];
}]; // 在系统默认子线程中执行代码,等待上面的线程执行完毕
[YXGCD asyncInQueue:SYS_CONCURRENT_QUEUE_D block:^{
[YXGCD waitGroup:group];
// 上面两个线程执行完毕且leaveGroup后才会执行下面的代码
}]; // 释放线程组
[YXGCD releaseGroup:group];

封装了group的enter与leave操作,更简单易用

    // 创建一个GCD-group
dispatch_group_t group = [YXGCD createGroup]; // 封装group的enter与leave操作
[YXGCD explicitlyIndicatesGroup:group asyncInQueue:SYS_UI_QUEUE block:^{
// 代码
}]; // 封装group的enter与leave操作
[YXGCD explicitlyIndicatesGroup:group asyncInQueue:SYS_CONCURRENT_QUEUE_D block:^{
// 代码
}]; [YXGCD waitGroup:group asyncInQueue:SYS_CONCURRENT_QUEUE_D before:^{
// wait之前的操作
} after:^{
// 等到所有在组中的任务结束后,就会执行
}]; // 释放线程组
[YXGCD releaseGroup:group];

具有超时等待特性的group操作

    // 创建一个GCD-group
dispatch_group_t group = [YXGCD createGroup]; // 封装group的enter与leave操作
[YXGCD explicitlyIndicatesGroup:group asyncInQueue:SYS_UI_QUEUE block:^{
// 代码
}]; // 封装group的enter与leave操作
[YXGCD explicitlyIndicatesGroup:group asyncInQueue:SYS_CONCURRENT_QUEUE_D block:^{
// 代码
}]; // 等待3s,看所有组中的线程是否已经完成
[YXGCD waitGroup:group forTime: * NSEC_PER_SEC asyncInQueue:SYS_UI_QUEUE before:^{ } after:^(long result) {
if (result == )
{
NSLog(@"所有线程都完成了");
}
else
{
NSLog(@"有的线程没有完成,超时了");
}
}]; // 释放线程组
[YXGCD releaseGroup:group];

GCD信号量用法

    // 创建一个信号量
dispatch_semaphore_t semaphore = [YXGCD createSemaphoreWithValue:]; [YXGCD asyncInQueue:SYS_CONCURRENT_QUEUE_D block:^{
// 连续5次发送信号量
for (int i = ; i < ; i++)
{
// 模拟阻塞操作1s
sleep(); // 发送信号量
[YXGCD signalForSemaphore:semaphore];
}
}]; [YXGCD asyncInQueue:SYS_CONCURRENT_QUEUE_D block:^{
// 死循环,不停等待接收信号量
while ()
{
// 阻塞等待接收信号量
[YXGCD waitForSemaphore:semaphore]; // 你的操作
NSLog(@"Y.X.");
} }]; // 释放信号量
[YXGCD releaseSemaphore:semaphore];

Grand Central Dispatch (GCD)的更多相关文章

  1. IOS 多线程编程之Grand Central Dispatch(GCD)介绍和使用 多线程基础和练习

    介绍:前面内容源自网络 Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其他的对称多处理系统的系统.这建立在任务并行执行的线程池模式 ...

  2. [转] iOS多线程编程之Grand Central Dispatch(GCD)介绍和使用

    介绍: Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其他的对称多处理系统的系统.这建立在任务并行执行的线程池模式的基础上的.它首 ...

  3. iOS 多线程编程之Grand Central Dispatch(GCD)

    介绍: Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其它的对称多处理系统的系统.这建立在任务并行运行的线程池模式的基础上的. 它 ...

  4. Grand Central Dispatch(GCD)详解(转)

    概述 GCD是苹果异步执行任务技术,将应用程序中的线程管理的代码在系统级中实现.开发者只需要定义想要执行的任务并追加到适当的Dispatch Queue中,GCD就能生成必要的线程并计划执行任务.由于 ...

  5. Grand Central Dispatch(GCD)详解

    概述 GCD是苹果异步执行任务技术,将应用程序中的线程管理的代码在系统级中实现.开发者只需要定义想要执行的任务并追加到适当的Dispatch Queue中,GCD就能生成必要的线程并计划执行任务.由于 ...

  6. iOS多线程编程之Grand Central Dispatch(GCD)介绍和使用

    http://blog.csdn.net/totogo2010/article/details/8016129 GCD很好的博文

  7. NSThread 子线程 Cocoa NSOperation GCD(Grand Central Dispatch) 多线程

    单词:thread 英 θred:n 线.思路.vt 穿过.vi 穿透过 一.    进程.线程 进程:正在进行中的程序被称为进程,负责程序运行的内存分配,每一个进程都有自己独立的虚拟内存空间 线程: ...

  8. iOS开发-多线程之GCD(Grand Central Dispatch)

    Grand Central Dispatch(GCD)是一个强有力的方式取执行多线程任务,不管你在回调的时候是异步或者同步的,可以优化应用程序支持多核心处理器和其他的对称多处理系统的系统.开发使用的过 ...

  9. 在Swift中应用Grand Central Dispatch(上)转载自的goldenfiredo001的博客

    尽管Grand Central Dispatch(GCD)已经存在一段时间了,但并非每个人都知道怎么使用它.这是情有可原的,因为并发很棘手,而且GCD本身基于C的API在 Swift世界中很刺眼. 在 ...

随机推荐

  1. 用于软件包管理的21个Linux YUM命令 转载

    http://flycars001.iteye.com/blog/1949085 YUM到底是啥东东? YUM(Yellowdog Updater Modified)是一款开源命令行及图形化软件包管理 ...

  2. [git]安装git-pylint-commit-hook提高python项目中的代码质量

    什么是'git-pylint-commit-hook' 我在工作中,团队为了保证代码和提高代码的质量,要求每个项目都要求安装git-pylint-commit-hook,它是个钩子,会在你提交代码到本 ...

  3. java 版的复利计算器(张俊毅 周修文)

    (带有本金的选项卡的意思就是计算你在知道利率.年限和本息的情况下计算本金) 在利率的输入中能限制小数点的输入并且输入字母会被直接去除 每一个选项卡都有复利和单利的计算,并且在你计算之后会立即更新在下面 ...

  4. 重构第19天 提取工厂类(Extract Factory Class)

    理解:本文中的“提取工厂类”是指如果要创建的对象很多,则代码会变的很复杂.一种很好的方法就是提取工厂类. 详解:一般来说我们需要在代码中设置一些对象,以便获得它们的状态,从而使用对象,所谓的设置通常来 ...

  5. 微信公众平台入门开发教程.Net(C#)框架

    一.序言 一直在想第一次写博客,应该写点什么好?正好最近在研究微信公众平台开发,索性就记录下,分享下自己的心得,也分享下本人简单模仿asp.net运行机制所写的通用的微信公众平台开发.Net(c#)框 ...

  6. Javascript小笔记

    1.315360000000 毫秒 = 10年 2.Javascript 取时间截: JavaScript 获取当前时间戳: 第一种方法: var timestamp = Date.parse(new ...

  7. 字符串与json之间的相互转化

    先在数据库中建表: 再从后台将表取出来,然后转化为json格式,再将其执行ToString()操作后,赋值给前台的隐藏域. 注意引用using Newtonsoft.Json; 前台利用js将隐藏域中 ...

  8. MSIL指令集

    名称 说明 Add 将两个值相加并将结果推送到计算堆栈上. Add.Ovf 将两个整数相加,执行溢出检查,并且将结果推送到计算堆栈上. Add.Ovf.Un 将两个无符号整数值相加,执行溢出检查,并且 ...

  9. Flask and uWSGI - unable to load app 0 (mountpoint='') (callable not found or import error)

    Here is my directory structure: -/path/to/folder/run.py -|app -|__init__.py -|views.py -|templates - ...

  10. 在WPF中使用文件夹选择对话框

    开发中有时会想实现"选择某个文件夹"的效果: 在WPF中,使用Microsoft.Win32.OpenFileDialog只能选择文件,FolderBrowserDialog只能用 ...