From 3c13147f7476f75df1980432735d1fb25da8437e Mon Sep 17 00:00:00 2001 From: CoderShmily Date: Mon, 3 Apr 2017 20:41:30 +0800 Subject: [PATCH 001/148] Customize commit message --- categories/iOS/index.html | 310 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 310 insertions(+) create mode 100644 categories/iOS/index.html diff --git a/categories/iOS/index.html b/categories/iOS/index.html new file mode 100644 index 0000000..66bc9e3 --- /dev/null +++ b/categories/iOS/index.html @@ -0,0 +1,310 @@ + + + + + + Category: iOS | CoderShmily's Blog + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + + + + +
+
+ 2015 +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + +
+ + \ No newline at end of file From b5efe75da5e5fbcc33502f50fcdaee5acf5c5a31 Mon Sep 17 00:00:00 2001 From: CoderShmily Date: Mon, 3 Apr 2017 20:41:37 +0800 Subject: [PATCH 002/148] Customize commit message --- categories/iOS/index.html | 310 -------------------------------------- 1 file changed, 310 deletions(-) delete mode 100644 categories/iOS/index.html diff --git a/categories/iOS/index.html b/categories/iOS/index.html deleted file mode 100644 index 66bc9e3..0000000 --- a/categories/iOS/index.html +++ /dev/null @@ -1,310 +0,0 @@ - - - - - - Category: iOS | CoderShmily's Blog - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- -
-
- - - - - - -
-
- 2015 -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - -
- - - -
-
- -
- -
-
-
- - - - - - - - - - - - -
- - \ No newline at end of file From 66ecde5d4c837de4b18448ca3590457ee19771d5 Mon Sep 17 00:00:00 2001 From: CoderShmily Date: Tue, 4 Apr 2017 10:34:49 +0800 Subject: [PATCH 003/148] Customize commit message --- 2015/05/01/2015-05-01-Swift-ru-men/index.html | 2 + 2015/05/02/2015-05-02-singleton/index.html | 2 + .../2015-05-03-kvc-he-kvoshen-ru/index.html | 2 + .../index.html | 2 + .../05/2015-05-05-runtime-gai-shu/index.html | 2 + .../index.html | 2 + .../index.html | 2 + .../index.html | 2 + .../2016-11-15-Swift3.0-jie-shao/index.html | 9 +- categories/iOS/index.html | 310 ++++++++++++++++++ 10 files changed, 334 insertions(+), 1 deletion(-) create mode 100644 categories/iOS/index.html diff --git a/2015/05/01/2015-05-01-Swift-ru-men/index.html b/2015/05/01/2015-05-01-Swift-ru-men/index.html index d351d8e..a626034 100644 --- a/2015/05/01/2015-05-01-Swift-ru-men/index.html +++ b/2015/05/01/2015-05-01-Swift-ru-men/index.html @@ -110,6 +110,8 @@

+ +

特色

  • 苹果宣称 Swift 的特点是:快速、现代、安全、互动,而且明显优于 Objective-C 语言
  • 可以使用现有的 CocoaCocoa Touch 框架
  • diff --git a/2015/05/02/2015-05-02-singleton/index.html b/2015/05/02/2015-05-02-singleton/index.html index f22ae8a..77196fa 100644 --- a/2015/05/02/2015-05-02-singleton/index.html +++ b/2015/05/02/2015-05-02-singleton/index.html @@ -93,6 +93,8 @@

    + +

    单例在整个工程中,就相当于一个全局变量,就是不论在哪里需要用到这个类的实例变量,都可以通过单例方法来取得,而且一旦你创建了一个单例类,不论你在多少个界面中初始化调用了这个单例方法取得对象,它们所有的对象都是指向的同一块内存存储空间(即单例类保证了该类的实力对象是唯一存在的一个).

    单例模式的作用

      diff --git a/2015/05/03/2015-05-03-kvc-he-kvoshen-ru/index.html b/2015/05/03/2015-05-03-kvc-he-kvoshen-ru/index.html index aabedc5..bf1fbb2 100644 --- a/2015/05/03/2015-05-03-kvc-he-kvoshen-ru/index.html +++ b/2015/05/03/2015-05-03-kvc-he-kvoshen-ru/index.html @@ -93,6 +93,8 @@

      + +

      KVC 和 KVO深入

      KVC概述

      1.什么是KVC?

      KVC即NSKeyValueCoding,键/值编码,一个非正式的Protocol,以字符串的形式向对象发送消息,而不是通过调用存取方法,直接或通过实例变量访问的机制。

      diff --git a/2015/05/04/2015-05-04-runtime-dui-xiang-mo-xing/index.html b/2015/05/04/2015-05-04-runtime-dui-xiang-mo-xing/index.html index 959af91..3583749 100644 --- a/2015/05/04/2015-05-04-runtime-dui-xiang-mo-xing/index.html +++ b/2015/05/04/2015-05-04-runtime-dui-xiang-mo-xing/index.html @@ -96,6 +96,8 @@

      + +

      Objective-C语言是一门动态语言,它将很多静态语言在编译和链接时期做的事放到了运行时来处理。这种动态语言的优势在于:我们写代码时更具灵活性,如我们可以把消息转发给我们想要的对象,或者随意交换一个方法的实现等。

      这种特性意味着Objective-C不仅需要一个编译器,还需要一个运行时系统来执行编译的代码。对于Objective-C来说,这个运行时系统就像一个操作系统一样:它让所有的工作可以正常的运行。这个运行时系统即Objc Runtime。Objc Runtime其实是一个Runtime库,它基本上是用C和汇编写的,这个库使得C语言有了面向对象的能力。

      diff --git a/2015/05/05/2015-05-05-runtime-gai-shu/index.html b/2015/05/05/2015-05-05-runtime-gai-shu/index.html index c7f5893..278857f 100644 --- a/2015/05/05/2015-05-05-runtime-gai-shu/index.html +++ b/2015/05/05/2015-05-05-runtime-gai-shu/index.html @@ -93,6 +93,8 @@

      + +

      Runtime常用方法和一些应用

      Runtime方法列表

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      # class
      class_getInstanceMethod -> Method class_getInstanceMethod(Class cls, SEL name);// 返回给定类的指定的实例方法
      class_addMethod -> BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types);// 通过方法名SEL+原来的IMP实现给类添加新方法
      class_copyPropertyList -> objc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount) // 获取类的属性列表
      # method
      method_getTypeEncoding -> const char *method_getTypeEncoding(Method m);// Returns a string describing a method's parameter and return types.
      method_getImplementation -> IMP method_getImplementation(Method m);//获取Method中的IMP
      method_exchangeImplementations -> method_exchangeImplementations(Method m1, Method m2); //Returns a string describing a method's parameter and return types.
      method_setImplementation -> IMP method_setImplementation(Method m, IMP imp); // Sets the implementation of a method.
      # 关联对象
      objc_setAssociatedObject -> objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy);//Sets an associated value for a given object using a given key and association policy.
      objc_getAssociatedObject -> id objc_getAssociatedObject(id object, const void *key);// Returns the value associated with a given object for a given key.
      objc_removeAssociatedObjects -> objc_removeAssociatedObjects(id object);// 注意:Removes all associations for a given object.
      # 类
      object_isClass -> BOOL object_isClass(id obj);//Returns whether an object is a class object.
      object_getClass -> Class object_getClass(id obj);//Returns the class of an object.
      object_getClassName -> const char *object_getClassName(id obj);//Returns the class name of a given object.
      object_setClass -> Class object_setClass(id obj, Class cls);//Sets the class of an object.
      objc_getMetaClass -> Class objc_getMetaClass(const char *name);// 原类
      # 实例变量
      object_getIvar -> id object_getIvar(id obj, Ivar ivar);//Reads the value of an instance variable in an object.
      object_setIvar -> object_setIvar(id obj, Ivar ivar, id value);//Sets the value of an instance variable in an object.
      // Changes the value of an 实例变量 of a 实例
      object_getInstanceVariable -> Ivar object_getInstanceVariable(id obj, const char *name, void **outValue)
      object_setInstanceVariable -> Ivar object_setInstanceVariable(id obj, const char *name, void *value);
      # 属性
      property_getName -> const char *property_getName(objc_property_t property) // 传入上面的数组(指针)获取每个属性的名称
      property_getAttributes -> const char *property_getAttributes(objc_property_t property) // 返回属性的名称和@encode类型字符串
      # 发送消息
      objc_msgSend -> objc_msgSend(id obj, SEL name);
      diff --git a/2015/05/06/2015-05-06-objective-c-runtime-san-xiao-xi-chuan-di/index.html b/2015/05/06/2015-05-06-objective-c-runtime-san-xiao-xi-chuan-di/index.html index d3e3619..1b37a9e 100644 --- a/2015/05/06/2015-05-06-objective-c-runtime-san-xiao-xi-chuan-di/index.html +++ b/2015/05/06/2015-05-06-objective-c-runtime-san-xiao-xi-chuan-di/index.html @@ -93,6 +93,8 @@

      + +

      Objective-C Runtime的消息传递

      ###Objective-C – 消息传递
      Objective-C 扩展了 C 语言,并加入了面向对象特性和 Smalltalk 式的消息传递机制。而这个扩展的核心是一个用 C 和 编译语言 写的 Runtime 库。它是 Objective-C 面向对象和动态机制的基石.

      Objective-C 是一个动态语言,这意味着它不仅需要一个编译器,也需要一个运行时系统来动态得创建类和对象、进行消息传递和转发。理解 Objective-C 的 Runtime 机制可以帮我们更好的了解这个语言,适当的时候还能对语言进行扩展,从系统层面解决项目中的一些设计或技术问题。了解 Runtime ,要先了解它的核心 - 消息传递(Messaging)。

      diff --git a/2015/05/07/2015-05-07-objective-c-runtime-si-dong-tai-fang-fa-jue-yi-dynamic-method-resolution/index.html b/2015/05/07/2015-05-07-objective-c-runtime-si-dong-tai-fang-fa-jue-yi-dynamic-method-resolution/index.html index 7eaf212..f0d35ab 100644 --- a/2015/05/07/2015-05-07-objective-c-runtime-si-dong-tai-fang-fa-jue-yi-dynamic-method-resolution/index.html +++ b/2015/05/07/2015-05-07-objective-c-runtime-si-dong-tai-fang-fa-jue-yi-dynamic-method-resolution/index.html @@ -93,6 +93,8 @@

      + +

      Objective-C Runtime之动态方法决议

      动态方法决议/动态方法解析(Dynamic Method Resolution)

      diff --git a/2015/05/15/2015-05-15-sdwebimageyuan-ma-jie-xi/index.html b/2015/05/15/2015-05-15-sdwebimageyuan-ma-jie-xi/index.html index af8ace3..caef481 100644 --- a/2015/05/15/2015-05-15-sdwebimageyuan-ma-jie-xi/index.html +++ b/2015/05/15/2015-05-15-sdwebimageyuan-ma-jie-xi/index.html @@ -93,6 +93,8 @@

      + +

      SDWebImage源码解析

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      86
      87
      88
      89
      90
      91
      92
      93
      94
      95
      96
      97
      98
      99
      100
      101
      102
      103
      104
      105
      106
      107
      108
      109
      110
      111
      112
      113
      114
      115
      116
      117
      118
      119
      120
      121
      122
      123
      124
      125
      126
      127
      128
      129
      130
      131
      132
      133
      134
      135
      136
      137
      138
      139
      140
      141
      142
      143
      144
      145
      146
      147
      148
      149
      150
      151
      152
      153
      154
      155
      156
      157
      158
      159
      160
      161
      162
      163
      164
      165
      166
      167
      168
      169
      170
      171
      172
      173
      174
      175
      176
      177
      178
      179
      180
      181
      182
      183
      184
      185
      186
      187
      188
      189
      190
      191
      192
      193
      194
      195
      196
      197
      198
      199
      200
      201
      202
      203
      204
      205
      206
      207
      208
      209
      210
      211
      212
      213
      214
      215
      216
      217
      218
      219
      220
      221
      222
      223
      224
      225
      226
      227
      228
      229
      230
      231
      232
      233
      234
      235
      236
      237
      238
      239
      240
      241
      242
      243
      244
      245
      246
      247
      248
      249
      250
      251
      252
      253
      254
      255
      256
      257
      258
      259
      260
      261
      262
      263
      264
      265
      266
      267
      268
      269
      270
      271
      272
      273
      274
      275
      276
      277
      278
      279
      280
      281
      282
      283
      284
      285
      286
      287
      288
      289
      290
      291
      292
      293
      294
      295
      296
      297
      298
      299
      300
      301
      302
      303
      304
      305
      306
      307
      308
      309
      310
      311
      312
      313
      314
      315
      316
      317
      318
      319
      320
      321
      322
      323
      324
      325
      326
      327
      328
      329
      330
      331
      332
      333
      334
      335
      336
      337
      338
      339
      340
      341
      342
      343
      344
      345
      346
      347
      348
      349
      350
      351
      352
      353
      354
      355
      356
      357
      358
      359
      360
      361
      362
      363
      364
      365
      366
      367
      368
      369
      370
      371
      372
      373
      374
      375
      376
      377
      378
      379
      380
      381
      382
      383
      /*
      * This file is part of the SDWebImage package.
      * (c) Olivier Poitrey <rs@dailymotion.com>
      *
      * For the full copyright and license information, please view the LICENSE
      * file that was distributed with this source code.
      */
      #import "SDWebImageCompat.h"
      #import "SDWebImageOperation.h"
      #import "SDWebImageDownloader.h"
      #import "SDImageCache.h"
      typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) {
      /**
      * By default, when a URL fail to be downloaded, the URL is blacklisted so the library won't keep trying.
      * This flag disable this blacklisting.
      */
      /**
      *默认情况下,如果一个url在下载的时候失败了,那么这个url会被加入黑名单并且library不会尝试再次下载,这个flag会阻止library把失败的url加入黑名单(简单来说如果选择了这个flag,那么即使某个url下载失败了,sdwebimage还是会尝试再次下载他.)
      */
      SDWebImageRetryFailed = 1 << 0,
      /**
      * By default, image downloads are started during UI interactions, this flags disable this feature,
      * leading to delayed download on UIScrollView deceleration for instance.
      */
      /**
      *默认情况下,图片会在交互发生的时候下载(例如你滑动tableview的时候),这个flag会禁止这个特性,导致的结果就是在scrollview减速的时候
      *才会开始下载(也就是你滑动的时候scrollview不下载,你手从屏幕上移走,scrollview开始减速的时候才会开始下载图片)
      */
      SDWebImageLowPriority = 1 << 1,
      /**
      * This flag disables on-disk caching
      */
      /*
      *这个flag禁止磁盘缓存,只有内存缓存
      */
      SDWebImageCacheMemoryOnly = 1 << 2,
      /**
      * This flag enables progressive download, the image is displayed progressively during download as a browser would do.
      * By default, the image is only displayed once completely downloaded.
      */
      /*
      *这个flag会在图片下载的时候就显示(就像你用浏览器浏览网页的时候那种图片下载,一截一截的显示(待确认))
      *
      */
      SDWebImageProgressiveDownload = 1 << 3,
      /**
      * Even if the image is cached, respect the HTTP response cache control, and refresh the image from remote location if needed.
      * The disk caching will be handled by NSURLCache instead of SDWebImage leading to slight performance degradation.
      * This option helps deal with images changing behind the same request URL, e.g. Facebook graph api profile pics.
      * If a cached image is refreshed, the completion block is called once with the cached image and again with the final image.
      *
      * Use this flag only if you can't make your URLs static with embeded cache busting parameter.
      */
      /*
      *这个选项的意思看的不是很懂,大意是即使一个图片缓存了,还是会重新请求.并且缓存侧略依据NSURLCache而不是SDWebImage.
      *
      */
      SDWebImageRefreshCached = 1 << 4,
      /**
      * In iOS 4+, continue the download of the image if the app goes to background. This is achieved by asking the system for
      * extra time in background to let the request finish. If the background task expires the operation will be cancelled.
      */
      /*
      *启动后台下载,加入你进入一个页面,有一张图片正在下载这时候你让app进入后台,图片还是会继续下载(这个估计要开backgroundfetch才有用)
      */
      SDWebImageContinueInBackground = 1 << 5,
      /**
      * Handles cookies stored in NSHTTPCookieStore by setting
      * NSMutableURLRequest.HTTPShouldHandleCookies = YES;
      */
      /*
      *可以控制存在NSHTTPCookieStore的cookies.(我没用过,等用过的人过来解释一下)
      */
      SDWebImageHandleCookies = 1 << 6,
      /**
      * Enable to allow untrusted SSL ceriticates.
      * Useful for testing purposes. Use with caution in production.
      */
      /*
      *允许不安全的SSL证书,在正式环境中慎用
      */
      SDWebImageAllowInvalidSSLCertificates = 1 << 7,
      /**
      * By default, image are loaded in the order they were queued. This flag move them to
      * the front of the queue and is loaded immediately instead of waiting for the current queue to be loaded (which
      * could take a while).
      */
      /*
      *默认情况下,image在装载的时候是按照他们在队列中的顺序装载的(就是先进先出).这个flag会把他们移动到队列的前端,并且立刻装载
      *而不是等到当前队列装载的时候再装载.
      */
      SDWebImageHighPriority = 1 << 8,
      /**
      * By default, placeholder images are loaded while the image is loading. This flag will delay the loading
      * of the placeholder image until after the image has finished loading.
      */
      /*
      *默认情况下,占位图会在图片下载的时候显示.这个flag开启会延迟占位图显示的时间,等到图片下载完成之后才会显示占位图.(等图片显示完了我干嘛还显示占位图?或许是我理解错了?)
      */
      SDWebImageDelayPlaceholder = 1 << 9,
      /**
      * We usually don't call transformDownloadedImage delegate method on animated images,
      * as most transformation code would mangle it.
      * Use this flag to transform them anyway.
      */
      /*
      *是否transform图片(没用过,还要再看,但是据我估计,是否是图片有可能方向不对需要调整方向,例如采用iPhone拍摄的照片如果不纠正方向,那么图片是向左旋转90度的.可能很多人不知道iPhone的摄像头并不是竖直的,而是向左偏了90度.具体请google.)
      */
      SDWebImageTransformAnimatedImage = 1 << 10,
      };
      typedef void(^SDWebImageCompletionBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL);
      typedef void(^SDWebImageCompletionWithFinishedBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL);
      typedef NSString *(^SDWebImageCacheKeyFilterBlock)(NSURL *url);
      @class SDWebImageManager;
      @protocol SDWebImageManagerDelegate <NSObject>
      @optional
      /**
      * Controls which image should be downloaded when the image is not found in the cache.
      *
      * @param imageManager The current `SDWebImageManager`
      * @param imageURL The url of the image to be downloaded
      *
      * @return Return NO to prevent the downloading of the image on cache misses. If not implemented, YES is implied.
      */
      /*
      *主要作用是当缓存里没有发现某张图片的缓存时,是否选择下载这张图片(默认是yes),可以选择no,那么sdwebimage在缓存中没有找到这张图片的时候不会选择下载
      */
      - (BOOL)imageManager:(SDWebImageManager *)imageManager shouldDownloadImageForURL:(NSURL *)imageURL;
      /**
      * Allows to transform the image immediately after it has been downloaded and just before to cache it on disk and memory.
      * NOTE: This method is called from a global queue in order to not to block the main thread.
      *
      * @param imageManager The current `SDWebImageManager`
      * @param image The image to transform
      * @param imageURL The url of the image to transform
      *
      * @return The transformed image object.
      */
      /**
      *在图片下载完成并且还没有加入磁盘缓存或者内存缓存的时候就transform这个图片.这个方法是在异步线程执行的,防治阻塞主线程.
      *至于为什么在异步执行很简单,对一张图片纠正方向(也就是transform)是很耗资源的,一张2M大小的图片纠正方向你可以用instrument测试一下耗时.
      *很恐怖
      */
      - (UIImage *)imageManager:(SDWebImageManager *)imageManager transformDownloadedImage:(UIImage *)image withURL:(NSURL *)imageURL;
      @end
      /**
      * The SDWebImageManager is the class behind the UIImageView+WebCache category and likes.
      * It ties the asynchronous downloader (SDWebImageDownloader) with the image cache store (SDImageCache).
      * You can use this class directly to benefit from web image downloading with caching in another context than
      * a UIView.
      *
      * Here is a simple example of how to use SDWebImageManager:
      *
      * @code
      SDWebImageManager *manager = [SDWebImageManager sharedManager];
      [manager downloadImageWithURL:imageURL
      options:0
      progress:nil
      completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
      if (image) {
      // do something with image
      }
      }];
      * @endcode
      */
      /*
      *这一段是阐述SDWebImageManager是干嘛的.其实UIImageView+WebCache这个category背后执行操作的就是这个SDWebImageManager.他会绑定一个下载器也就是SDWebImageDownloader和一个缓存SDImageCache.后面的大意应该是讲你可以直接使用一个其他上下文环境的SDWebImageManager,而不是仅仅限于一个UIView.
      */
      @interface SDWebImageManager : NSObject
      @property (weak, nonatomic) id <SDWebImageManagerDelegate> delegate;
      /**
      *如同上文所说,一个SDWebImageManager会绑定一个imageCache和一个下载器.
      */
      @property (strong, nonatomic, readonly) SDImageCache *imageCache;
      @property (strong, nonatomic, readonly) SDWebImageDownloader *imageDownloader;
      /**
      * The cache filter is a block used each time SDWebImageManager need to convert an URL into a cache key. This can
      * be used to remove dynamic part of an image URL.
      *
      * The following example sets a filter in the application delegate that will remove any query-string from the
      * URL before to use it as a cache key:
      *
      * @code
      [[SDWebImageManager sharedManager] setCacheKeyFilter:^(NSURL *url) {
      url = [[NSURL alloc] initWithScheme:url.scheme host:url.host path:url.path];
      return [url absoluteString];
      }];
      * @endcode
      */
      /*
      * 这个cacheKeyFilter是干嘛的呢?很简单.1他是一个block.2.这个block的作用就是生成一个image的key.因为sdwebimage的缓存原理你可以当成是一个字典,每一个字典的value就是一张image,那么这个value对应的key是什么呢?就是cacheKeyFilter根据某个规则对这个图片的url做一些操作生成的.上面的示例就显示了怎么利用这个block把image的url重新组合生成一个key.以后当sdwebimage检测到你
      */
      @property (nonatomic, copy) SDWebImageCacheKeyFilterBlock cacheKeyFilter;
      /**
      * Returns global SDWebImageManager instance.
      *
      * @return SDWebImageManager shared instance
      */
      /*
      *这个不用我解释了吧,生成一个SDWebImagemanager的单例.
      */
      + (SDWebImageManager *)sharedManager;
      /**
      * Downloads the image at the given URL if not present in cache or return the cached version otherwise.
      * 从给定的URL中下载一个之前没有被缓存的Image.
      *
      * @param url The URL to the image
      * @param options A mask to specify options to use for this request
      * @param progressBlock A block called while image is downloading
      * @param completedBlock A block called when operation has been completed.
      *
      * This parameter is required.
      *
      * This block has no return value and takes the requested UIImage as first parameter.
      * In case of error the image parameter is nil and the second parameter may contain an NSError.
      *
      * The third parameter is an `SDImageCacheType` enum indicating if the image was retrived from the local cache
      * or from the memory cache or from the network.
      *
      * The last parameter is set to NO when the SDWebImageProgressiveDownload option is used and the image is
      * downloading. This block is thus called repetidly with a partial image. When image is fully downloaded, the
      * block is called a last time with the full image and the last parameter set to YES.
      *
      * @return Returns an NSObject conforming to SDWebImageOperation. Should be an instance of SDWebImageDownloaderOperation
      */
      /*
      * 这个方法主要就是SDWebImage下载图片的方法了.
      * 第一个参数是必须要的,就是image的url
      * 第二个参数就是我们上面的Options,你可以定制化各种各样的操作.详情参上.
      * 第三个参数是一个回调block,用于图片在下载过程中的回调.(英文注释应该是有问题的.)
      * 第四个参数是一个下载完成的回调.会在图片下载完成后回调.
      * 返回值是一个NSObject类,并且这个NSObject类是conforming一个协议这个协议叫做SDWebImageOperation,这个协议很简单,就是一个cancel掉operation的协议.
      */
      - (id <SDWebImageOperation>)downloadImageWithURL:(NSURL *)url
      options:(SDWebImageOptions)options
      progress:(SDWebImageDownloaderProgressBlock)progressBlock
      completed:(SDWebImageCompletionWithFinishedBlock)completedBlock;
      /**
      * Saves image to cache for given URL
      *
      * @param image The image to cache
      * @param url The URL to the image
      *
      */
      /*
      * 将图片存入cache的方法,类似于字典的setValue: forKey:
      */
      - (void)saveImageToCache:(UIImage *)image forURL:(NSURL *)url;
      /**
      * Cancel all current opreations
      */
      /*
      *取消掉当前所有的下载图片的operation
      */
      - (void)cancelAll;
      /**
      * Check one or more operations running
      */
      /*
      * check一下是否有一个或者多个operation正在执行(简单来说就是check是否有图片在下载)
      */
      - (BOOL)isRunning;
      /**
      * Check if image has already been cached
      *
      * @param url image url
      *
      * @return if the image was already cached
      */
      /*
      * 通过一个image的url是否已经存在,如果存在返回yes,否则返回no
      */
      - (BOOL)cachedImageExistsForURL:(NSURL *)url;
      /**
      * Check if image has already been cached on disk only
      *
      * @param url image url
      *
      * @return if the image was already cached (disk only)
      */
      /*
      * 检测一个image是否已经被缓存到磁盘(是否存且仅存在disk里).
      */
      - (BOOL)diskImageExistsForURL:(NSURL *)url;
      /**
      * Async check if image has already been cached
      *
      * @param url image url
      * @param completionBlock the block to be executed when the check is finished
      *
      * @note the completion block is always executed on the main queue
      */
      /*
      * 如果检测到图片已经被缓存,那么执行回调block.这个block会永远执行在主线程.也就是你可以在这个回调block里更新ui.
      */
      - (void)cachedImageExistsForURL:(NSURL *)url
      completion:(SDWebImageCheckCacheCompletionBlock)completionBlock;
      /**
      * Async check if image has already been cached on disk only
      *
      * @param url image url
      * @param completionBlock the block to be executed when the check is finished
      *
      * @note the completion block is always executed on the main queue
      */
      /*
      * 如果检测到图片已经被缓存在磁盘(存且仅存在disk),那么执行回调block.这个block会永远执行在主线程.也就是你可以在这个回调block里更新ui.
      */
      - (void)diskImageExistsForURL:(NSURL *)url
      completion:(SDWebImageCheckCacheCompletionBlock)completionBlock;
      /**
      *Return the cache key for a given URL
      */
      /*
      * 通过image的url返回image存在缓存里的key.有人会问了,为什么不直接把图片的url当做image的key来使用呢?而是非要对url做一些处理才能当做key.我的解释是,我也不太清楚.可能为了防止重复吧.
      */
      - (NSString *)cacheKeyForURL:(NSURL *)url;
      @end
      #pragma mark - Deprecated
      typedef void(^SDWebImageCompletedBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType) __deprecated_msg("Block type deprecated. Use `SDWebImageCompletionBlock`");
      typedef void(^SDWebImageCompletedWithFinishedBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished) __deprecated_msg("Block type deprecated. Use `SDWebImageCompletionWithFinishedBlock`");
      // 已被废弃
      @interface SDWebImageManager (Deprecated)
      /**
      * Downloads the image at the given URL if not present in cache or return the cached version otherwise.
      *
      * @deprecated This method has been deprecated. Use `downloadImageWithURL:options:progress:completed:`
      */
      - (id <SDWebImageOperation>)downloadWithURL:(NSURL *)url
      options:(SDWebImageOptions)options
      progress:(SDWebImageDownloaderProgressBlock)progressBlock
      completed:(SDWebImageCompletedWithFinishedBlock)completedBlock __deprecated_msg("Method deprecated. Use `downloadImageWithURL:options:progress:completed:`");
      @end
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      86
      87
      88
      89
      90
      91
      92
      93
      94
      95
      96
      97
      98
      99
      100
      101
      102
      103
      104
      105
      106
      107
      108
      109
      110
      111
      112
      113
      114
      115
      116
      117
      118
      119
      120
      121
      122
      123
      124
      125
      126
      127
      128
      129
      130
      131
      132
      133
      134
      135
      136
      137
      138
      139
      140
      141
      142
      143
      144
      145
      146
      147
      148
      149
      150
      151
      152
      153
      154
      155
      156
      157
      158
      159
      160
      161
      162
      163
      164
      165
      166
      167
      168
      169
      170
      171
      172
      173
      174
      175
      176
      177
      178
      179
      180
      181
      182
      183
      184
      185
      186
      187
      188
      189
      190
      191
      192
      193
      194
      195
      196
      197
      198
      199
      200
      201
      202
      203
      204
      205
      206
      207
      208
      209
      210
      211
      212
      213
      214
      215
      216
      217
      218
      219
      220
      221
      222
      223
      224
      225
      226
      227
      228
      229
      230
      231
      232
      233
      234
      235
      236
      237
      238
      239
      240
      241
      242
      243
      244
      245
      246
      247
      248
      249
      250
      251
      252
      253
      254
      255
      256
      257
      258
      259
      260
      261
      262
      263
      264
      265
      266
      267
      268
      269
      270
      271
      272
      273
      274
      275
      276
      277
      278
      279
      280
      281
      282
      283
      284
      285
      286
      287
      288
      289
      290
      291
      292
      293
      294
      295
      296
      297
      298
      299
      300
      301
      302
      303
      304
      305
      306
      307
      308
      309
      310
      311
      312
      313
      314
      315
      316
      317
      318
      319
      320
      321
      322
      323
      324
      325
      326
      327
      328
      329
      330
      331
      332
      333
      334
      335
      336
      337
      338
      339
      340
      341
      342
      343
      344
      345
      346
      347
      348
      349
      350
      351
      352
      353
      354
      355
      356
      357
      358
      359
      360
      361
      362
      363
      364
      365
      366
      367
      368
      369
      370
      371
      372
      373
      374
      375
      376
      377
      378
      379
      380
      381
      382
      383
      384
      385
      386
      387
      388
      389
      390
      #import <Foundation/Foundation.h>
      /*
      * This file is part of the SDWebImage package.
      *
      * For the full copyright and license information, please view the LICENSE
      * file that was distributed with this source code.
      */
      #import "SDWebImageManager.h"
      #import <objc/message.h>
      // 内部类.
      @interface SDWebImageCombinedOperation : NSObject <SDWebImageOperation>
      @property (assign, nonatomic, getter = isCancelled) BOOL cancelled;
      @property (copy, nonatomic) SDWebImageNoParamsBlock cancelBlock;
      @property (strong, nonatomic) NSOperation *cacheOperation;
      @end
      @interface SDWebImageManager ()
      @property (strong, nonatomic, readwrite) SDImageCache *imageCache;
      @property (strong, nonatomic, readwrite) SDWebImageDownloader *imageDownloader;
      @property (strong, nonatomic) NSMutableSet *failedURLs;
      @property (strong, nonatomic) NSMutableArray *runningOperations;
      @end
      @implementation SDWebImageManager
      // 利用disptach_once 特性生成一个单例,用烂了的方法.不赘述.
      + (id)sharedManager {
      static dispatch_once_t once;
      static id instance;
      dispatch_once(&once, ^{
      instance = [self new];
      });
      return instance;
      }
      // 初始化方法.
      // 1.获得一个SDImageCache的单例.2.获取一个SDWebImageDownloader的单例.3.新建一个MutableSet来存储下载失败的url.
      // 4.新建一个用来存储下载operation的可变数组.
      // 为什么不用MutableArray储存下载失败的URL?
      // 因为NSSet类有一个特性,就是Hash.实际上NSSet是一个哈希表,哈希表比数组优秀的地方是什么呢?就是查找速度快.查找同样一个元素,哈希表只需要通过key
      // 即可取到,而数组至少需要遍历依次.因为SDWebImage里有关失败URL的业务需求是,一个失败的URL只需要储存一次.这样的话Set自然比Array更合适.
      - (id)init {
      if ((self = [super init])) {
      _imageCache = [self createCache];
      _imageDownloader = [SDWebImageDownloader sharedDownloader];
      _failedURLs = [NSMutableSet new];
      _runningOperations = [NSMutableArray new];
      }
      return self;
      }
      // 获取一个cache的单例
      - (SDImageCache *)createCache {
      return [SDImageCache sharedImageCache];
      }
      // 利用Image的URL生成一个缓存时需要的key.
      // 这里有两种情况,第一种是如果检测到cacheKeyFilter不为空时,利用cacheKeyFilter来处理URL生成一个key.
      // 如果为空,那么直接返回URL的string内容,当做key.
      - (NSString *)cacheKeyForURL:(NSURL *)url {
      if (self.cacheKeyFilter) {
      return self.cacheKeyFilter(url);
      }
      else {
      return [url absoluteString];
      }
      }
      // 检测一张图片是否已被缓存.
      // 首先检测内存缓存是否存在这张图片,如果已有,直接返回yes.
      // 如果内存缓存里没有这张图片,那么调用diskImageExistsWithKey这个方法去硬盘缓存里找
      - (BOOL)cachedImageExistsForURL:(NSURL *)url {
      NSString *key = [self cacheKeyForURL:url];
      if ([self.imageCache imageFromMemoryCacheForKey:key] != nil) return YES;
      return [self.imageCache diskImageExistsWithKey:key];
      }
      // 检测硬盘里是否缓存了图片
      - (BOOL)diskImageExistsForURL:(NSURL *)url {
      NSString *key = [self cacheKeyForURL:url];
      return [self.imageCache diskImageExistsWithKey:key];
      }
      // 首先生成一个用来cache 住Image的key(利用key的url生成)
      // 然后检测内存缓存里是否已经有这张图片
      // 如果已经被缓存,那么再主线程里回调block
      // 如果没有检测到,那么调用diskImageExistsWithKey,这个方法会在异步线程里,将图片存到硬盘,当然在存图之前也会检测是否已在硬盘缓存图片.
      - (void)cachedImageExistsForURL:(NSURL *)url
      completion:(SDWebImageCheckCacheCompletionBlock)completionBlock {
      NSString *key = [self cacheKeyForURL:url];
      BOOL isInMemoryCache = ([self.imageCache imageFromMemoryCacheForKey:key] != nil);
      if (isInMemoryCache) {
      // making sure we call the completion block on the main queue
      dispatch_async(dispatch_get_main_queue(), ^{
      if (completionBlock) {
      completionBlock(YES);
      }
      });
      return;
      }
      [self.imageCache diskImageExistsWithKey:key completion:^(BOOL isInDiskCache) {
      // the completion block of checkDiskCacheForImageWithKey:completion: is always called on the main queue, no need to further dispatch
      if (completionBlock) {
      completionBlock(isInDiskCache);
      }
      }];
      }
      //将图片存入硬盘
      - (void)diskImageExistsForURL:(NSURL *)url
      completion:(SDWebImageCheckCacheCompletionBlock)completionBlock {
      NSString *key = [self cacheKeyForURL:url];
      [self.imageCache diskImageExistsWithKey:key completion:^(BOOL isInDiskCache) {
      // the completion block of checkDiskCacheForImageWithKey:completion: is always called on the main queue, no need to further dispatch
      if (completionBlock) {
      completionBlock(isInDiskCache);
      }
      }];
      }
      // 通过url建立一个operation用来下载图片.
      - (id <SDWebImageOperation>)downloadImageWithURL:(NSURL *)url
      options:(SDWebImageOptions)options
      progress:(SDWebImageDownloaderProgressBlock)progressBlock
      completed:(SDWebImageCompletionWithFinishedBlock)completedBlock {
      // Invoking this method without a completedBlock is pointless
      NSAssert(completedBlock != nil, @"If you mean to prefetch the image, use -[SDWebImagePrefetcher prefetchURLs] instead");
      // Very common mistake is to send the URL using NSString object instead of NSURL. For some strange reason, XCode won't
      // throw any warning for this type mismatch. Here we failsafe this error by allowing URLs to be passed as NSString.
      if ([url isKindOfClass:NSString.class]) {
      url = [NSURL URLWithString:(NSString *)url];
      }
      // Prevents app crashing on argument type error like sending NSNull instead of NSURL
      if (![url isKindOfClass:NSURL.class]) {
      url = nil;
      }
      __block SDWebImageCombinedOperation *operation = [SDWebImageCombinedOperation new];
      __weak SDWebImageCombinedOperation *weakOperation = operation;
      BOOL isFailedUrl = NO;
      // 创建一个互斥锁防止现在有别的线程修改failedURLs.
      // 判断这个url是否是fail过的.如果url failed过的那么isFailedUrl就是true
      @synchronized (self.failedURLs) {
      isFailedUrl = [self.failedURLs containsObject:url];
      }
      // 如果url不存在那么直接返回一个block,如果url存在.那么继续进行判断.
      // options与SDWebImageRetryFailed这个option进行按位与操作.判断用户的options里是否有retry这个option.
      // 如果用户的options里没有retry这个选项并且isFaileUrl 是true.那么就回调一个error的block.
      if (!url || (!(options & SDWebImageRetryFailed) && isFailedUrl)) {
      dispatch_main_sync_safe(^{
      NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorFileDoesNotExist userInfo:nil];
      completedBlock(nil, error, SDImageCacheTypeNone, YES, url);
      });
      return operation;
      }
      // 创建一个互斥锁防止现在有别的线程修改runningOperations.
      @synchronized (self.runningOperations) {
      [self.runningOperations addObject:operation];
      }
      NSString *key = [self cacheKeyForURL:url];
      // cacheOperation应该是一个用来下载图片并且缓存的operation
      operation.cacheOperation = [self.imageCache queryDiskCacheForKey:key done:^(UIImage *image, SDImageCacheType cacheType) {
      // 判断operation这时候有没有执行cancel操作,如果cancel掉了就把这个operation从我们的operation数组里remove掉然后return
      if (operation.isCancelled) {
      @synchronized (self.runningOperations) {
      [self.runningOperations removeObject:operation];
      }
      return;
      }
      if ((!image || options & SDWebImageRefreshCached) && (![self.delegate respondsToSelector:@selector(imageManager:shouldDownloadImageForURL:)] || [self.delegate imageManager:self shouldDownloadImageForURL:url])) {
      if (image && options & SDWebImageRefreshCached) {
      dispatch_main_sync_safe(^{
      // If image was found in the cache bug SDWebImageRefreshCached is provided, notify about the cached image
      // AND try to re-download it in order to let a chance to NSURLCache to refresh it from server.
      completedBlock(image, nil, cacheType, YES, url);
      });
      }
      // download if no image or requested to refresh anyway, and download allowed by delegate
      // 下面都是判断我们的options里包含哪些SDWebImageOptions,然后给我们的downloaderOptions相应的添加对应的SDWebImageDownloaderOptions. downloaderOptions |= SDWebImageDownloaderLowPriority这种表达式的意思等同于
      // downloaderOptions = downloaderOptions | SDWebImageDownloaderLowPriority
      SDWebImageDownloaderOptions downloaderOptions = 0;
      if (options & SDWebImageLowPriority) downloaderOptions |= SDWebImageDownloaderLowPriority;
      if (options & SDWebImageProgressiveDownload) downloaderOptions |= SDWebImageDownloaderProgressiveDownload;
      if (options & SDWebImageRefreshCached) downloaderOptions |= SDWebImageDownloaderUseNSURLCache;
      if (options & SDWebImageContinueInBackground) downloaderOptions |= SDWebImageDownloaderContinueInBackground;
      if (options & SDWebImageHandleCookies) downloaderOptions |= SDWebImageDownloaderHandleCookies;
      if (options & SDWebImageAllowInvalidSSLCertificates) downloaderOptions |= SDWebImageDownloaderAllowInvalidSSLCertificates;
      if (options & SDWebImageHighPriority) downloaderOptions |= SDWebImageDownloaderHighPriority;
      if (image && options & SDWebImageRefreshCached) {
      // force progressive off if image already cached but forced refreshing
      downloaderOptions &= ~SDWebImageDownloaderProgressiveDownload;
      // ignore image read from NSURLCache if image if cached but force refreshing
      downloaderOptions |= SDWebImageDownloaderIgnoreCachedResponse;
      }
      // 调用imageDownloader去下载image并且返回执行这个request的download的operation
      id <SDWebImageOperation> subOperation = [self.imageDownloader downloadImageWithURL:url options:downloaderOptions progress:progressBlock completed:^(UIImage *downloadedImage, NSData *data, NSError *error, BOOL finished) {
      if (weakOperation.isCancelled) {
      // Do nothing if the operation was cancelled
      // See #699 for more details
      // if we would call the completedBlock, there could be a race condition between this block and another completedBlock for the same object, so if this one is called second, we will overwrite the new data
      }
      else if (error) {
      dispatch_main_sync_safe(^{
      if (!weakOperation.isCancelled) {
      completedBlock(nil, error, SDImageCacheTypeNone, finished, url);
      }
      });
      if (error.code != NSURLErrorNotConnectedToInternet && error.code != NSURLErrorCancelled && error.code != NSURLErrorTimedOut) {
      @synchronized (self.failedURLs) {
      [self.failedURLs addObject:url];
      }
      }
      }
      else {
      if ((options & SDWebImageRetryFailed)) {
      @synchronized (self.failedURLs) {
      [self.failedURLs removeObject:url];
      }
      }
      BOOL cacheOnDisk = !(options & SDWebImageCacheMemoryOnly);
      if (options & SDWebImageRefreshCached && image && !downloadedImage) {
      // Image refresh hit the NSURLCache cache, do not call the completion block
      }
      else if (downloadedImage && (!downloadedImage.images || (options & SDWebImageTransformAnimatedImage)) && [self.delegate respondsToSelector:@selector(imageManager:transformDownloadedImage:withURL:)]) {
      dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
      UIImage *transformedImage = [self.delegate imageManager:self transformDownloadedImage:downloadedImage withURL:url];
      if (transformedImage && finished) {
      BOOL imageWasTransformed = ![transformedImage isEqual:downloadedImage];
      [self.imageCache storeImage:transformedImage recalculateFromImage:imageWasTransformed imageData:data forKey:key toDisk:cacheOnDisk];
      }
      dispatch_main_sync_safe(^{
      if (!weakOperation.isCancelled) {
      completedBlock(transformedImage, nil, SDImageCacheTypeNone, finished, url);
      }
      });
      });
      }
      else {
      if (downloadedImage && finished) {
      [self.imageCache storeImage:downloadedImage recalculateFromImage:NO imageData:data forKey:key toDisk:cacheOnDisk];
      }
      dispatch_main_sync_safe(^{
      if (!weakOperation.isCancelled) {
      completedBlock(downloadedImage, nil, SDImageCacheTypeNone, finished, url);
      }
      });
      }
      }
      if (finished) {
      @synchronized (self.runningOperations) {
      [self.runningOperations removeObject:operation];
      }
      }
      }];
      operation.cancelBlock = ^{
      [subOperation cancel];
      @synchronized (self.runningOperations) {
      [self.runningOperations removeObject:weakOperation];
      }
      };
      }
      else if (image) {
      dispatch_main_sync_safe(^{
      if (!weakOperation.isCancelled) {
      completedBlock(image, nil, cacheType, YES, url);
      }
      });
      @synchronized (self.runningOperations) {
      [self.runningOperations removeObject:operation];
      }
      }
      else {
      // Image not in cache and download disallowed by delegate
      dispatch_main_sync_safe(^{
      if (!weakOperation.isCancelled) {
      completedBlock(nil, nil, SDImageCacheTypeNone, YES, url);
      }
      });
      @synchronized (self.runningOperations) {
      [self.runningOperations removeObject:operation];
      }
      }
      }];
      return operation;
      }
      - (void)saveImageToCache:(UIImage *)image forURL:(NSURL *)url {
      if (image && url) {
      NSString *key = [self cacheKeyForURL:url];
      [self.imageCache storeImage:image forKey:key toDisk:YES];
      }
      }
      // cancel掉所有正在执行的operation
      - (void)cancelAll {
      @synchronized (self.runningOperations) {
      NSArray *copiedOperations = [self.runningOperations copy];
      [copiedOperations makeObjectsPerformSelector:@selector(cancel)];
      [self.runningOperations removeObjectsInArray:copiedOperations];
      }
      }
      // 判断是否有正在运行的operation
      - (BOOL)isRunning {
      return self.runningOperations.count > 0;
      }
      @end
      @implementation SDWebImageCombinedOperation
      - (void)setCancelBlock:(SDWebImageNoParamsBlock)cancelBlock {
      // check if the operation is already cancelled, then we just call the cancelBlock
      if (self.isCancelled) {
      if (cancelBlock) {
      cancelBlock();
      }
      _cancelBlock = nil; // don't forget to nil the cancelBlock, otherwise we will get crashes
      } else {
      _cancelBlock = [cancelBlock copy];
      }
      }
      - (void)cancel {
      self.cancelled = YES;
      if (self.cacheOperation) {
      [self.cacheOperation cancel];
      self.cacheOperation = nil;
      }
      if (self.cancelBlock) {
      self.cancelBlock();
      // TODO: this is a temporary fix to #809.
      // Until we can figure the exact cause of the crash, going with the ivar instead of the setter
      // self.cancelBlock = nil;
      _cancelBlock = nil;
      }
      }
      @end
      @implementation SDWebImageManager (Deprecated)
      // deprecated method, uses the non deprecated method
      // adapter for the completion block
      - (id <SDWebImageOperation>)downloadWithURL:(NSURL *)url options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletedWithFinishedBlock)completedBlock {
      return [self downloadImageWithURL:url
      options:options
      progress:progressBlock
      completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
      if (completedBlock) {
      completedBlock(image, error, cacheType, finished);
      }
      }];
      }
      @end
      diff --git a/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html b/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html index 89871bf..1489896 100644 --- a/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html +++ b/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html @@ -11,7 +11,7 @@ - + @@ -93,6 +93,13 @@

      + + +
      + 文章目录 +
      1. 1. Any AnyObject NSObject
      2. 2. 条件判断
        1. 2.1. 1. if的使用
        2. 2.2. 2. 三目运算符
        3. 2.3. 3. guard
        4. 2.4. 4. switch的用法
          1. 2.4.1. 1. switch与基本数据
          2. 2.4.2. 2. switch与区间
          3. 2.4.3. 3. switch与枚举
          4. 2.4.4. 4. switch与元组
      3. 3. 循环
        1. 3.1. 1. for循环
        2. 3.2. 2. while循环
          1. 3.2.1. 1. while循环
          2. 3.2.2. 2. repeat~while循环
      4. 4. 字符串处理
      5. 5. 数组
      6. 6. 字典
      7. 7. 元组
      8. 8. 可选类型
        1. 8.1. 2. 可选类型 (才能赋值为nil)
        2. 8.2. 3. 四种方式使用可选类型的值
          1. 8.2.1. 1. 判断 + 直接解包
          2. 8.2.2. 2. 可选绑定
          3. 8.2.3. 3. guard守护
          4. 8.2.4. 4. 空合运算符
      9. 9. 类型转换
      10. 10. 函数
        1. 10.1. 1. 函数的四种类型
          1. 10.1.1. 1. 无参数,无返回值
          2. 10.1.2. 2. 无参数,有返回值
          3. 10.1.3. 3. 有参数,无返回值
          4. 10.1.4. 4. 有参数,有返回值
        2. 10.2. 函数其他注意
          1. 10.2.1. 1. 省略第一个外部参数的名字
          2. 10.2.2. 2. 设置参数默认值
          3. 10.2.3. 3. 设置可变参数
          4. 10.2.4. 4. 修改内部参数的值
          5. 10.2.5. 5. 设置参数为地址传递
          6. 10.2.6. 6. 函数嵌套
          7. 10.2.7. 7. 函数的类型
          8. 10.2.8. 8. 区分不同函数
      11. 11. 枚举
      12. 12. 结构体
        1. 12.1. 1. 结构体基本使用
        2. 12.2. 2. 结构体扩充构造函数
      13. 13.
        1. 13.1. 1. 类的声明初始化
        2. 13.2. 2. 类的属性和方法
        3. 13.3. 3. 类的继承之KVC使用
        4. 13.4. 4. 类的循环引用
        5. 13.5. 5. 结构体和类的区别
        6. 13.6. 6. OC中使用Swift的类和结构体
        7. 13.7. 7. Swift中调用OC
      14. 14. 三大特性
      15. 15. 可选链
      16. 16. 协议
        1. 16.1. 1.协议的基本使用
        2. 16.2. 2. 协议中使用代理
        3. 16.3. 3. 协议中的可选
      17. 17. 闭包
        1. 17.1. 1.闭包的基本使用
        2. 17.2. 2. 尾随闭包和逃逸闭包
        3. 17.3. 3. 闭包的循环引用(4中解决方式)
      18. 18. 懒加载
      19. 19. 注释
      20. 20. 访问权限
        1. 20.1. 访问修饰符
      21. 21. 方法抛出异常
      22. 22. Playground
        1. 22.1. 1. Playground异步执行
        2. 22.2. 2. MarkDown语法
        3. 22.3. 3. TimeLine使用
        4. 22.4. 4. Playground的Sources目录
      +
      +

      Swift3.0相关的语法介绍

      [TOC]

      diff --git a/categories/iOS/index.html b/categories/iOS/index.html new file mode 100644 index 0000000..66bc9e3 --- /dev/null +++ b/categories/iOS/index.html @@ -0,0 +1,310 @@ + + + + + + Category: iOS | CoderShmily's Blog + + + + + + + + + + + + + + + + + + + + + + + + + +
      +
      + +
      +
      + + + + + + +
      +
      + 2015 +
      +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + +
      + + + +
      +
      + +
      + +
      +
      +
      + + + + + + + + + + + + +
      + + \ No newline at end of file From 56852b5faf41121d936ae40ab604280d9bb038d7 Mon Sep 17 00:00:00 2001 From: CoderShmily Date: Tue, 4 Apr 2017 10:35:48 +0800 Subject: [PATCH 004/148] Customize commit message --- .../2016-11-15-Swift3.0-jie-shao/index.html | 3 +- categories/iOS/index.html | 310 ------------------ 2 files changed, 1 insertion(+), 312 deletions(-) delete mode 100644 categories/iOS/index.html diff --git a/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html b/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html index 1489896..078e898 100644 --- a/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html +++ b/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html @@ -11,7 +11,7 @@ - + @@ -102,7 +102,6 @@

      Swift3.0相关的语法介绍

      -

      [TOC]

      Any AnyObject NSObject

      Int Double String struct都是结构体

      1. Any : 一个协议声明
      2. diff --git a/categories/iOS/index.html b/categories/iOS/index.html deleted file mode 100644 index 66bc9e3..0000000 --- a/categories/iOS/index.html +++ /dev/null @@ -1,310 +0,0 @@ - - - - - - Category: iOS | CoderShmily's Blog - - - - - - - - - - - - - - - - - - - - - - - - - -
        -
        - -
        -
        - - - - - - -
        -
        - 2015 -
        -
        - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        - - -
        - - - -
        -
        - -
        - -
        -
        -
        - - - - - - - - - - - - -
        - - \ No newline at end of file From ddefe902474b0665cf75195ff5568928943fda2a Mon Sep 17 00:00:00 2001 From: CoderShmily Date: Tue, 4 Apr 2017 10:37:12 +0800 Subject: [PATCH 005/148] Customize commit message --- .../2016-11-15-Swift3.0-jie-shao/index.html | 32 +- categories/iOS/index.html | 310 ++++++++++++++++++ index.html | 119 ++++++- 3 files changed, 449 insertions(+), 12 deletions(-) create mode 100644 categories/iOS/index.html diff --git a/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html b/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html index 078e898..9f42e60 100644 --- a/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html +++ b/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html @@ -5,16 +5,37 @@ Swift3.0学习笔记 | CoderShmily's Blog - + - - + + - + @@ -100,8 +121,7 @@

        1. 1. Any AnyObject NSObject
        2. 2. 条件判断
          1. 2.1. 1. if的使用
          2. 2.2. 2. 三目运算符
          3. 2.3. 3. guard
          4. 2.4. 4. switch的用法
            1. 2.4.1. 1. switch与基本数据
            2. 2.4.2. 2. switch与区间
            3. 2.4.3. 3. switch与枚举
            4. 2.4.4. 4. switch与元组
        3. 3. 循环
          1. 3.1. 1. for循环
          2. 3.2. 2. while循环
            1. 3.2.1. 1. while循环
            2. 3.2.2. 2. repeat~while循环
        4. 4. 字符串处理
        5. 5. 数组
        6. 6. 字典
        7. 7. 元组
        8. 8. 可选类型
          1. 8.1. 2. 可选类型 (才能赋值为nil)
          2. 8.2. 3. 四种方式使用可选类型的值
            1. 8.2.1. 1. 判断 + 直接解包
            2. 8.2.2. 2. 可选绑定
            3. 8.2.3. 3. guard守护
            4. 8.2.4. 4. 空合运算符
        9. 9. 类型转换
        10. 10. 函数
          1. 10.1. 1. 函数的四种类型
            1. 10.1.1. 1. 无参数,无返回值
            2. 10.1.2. 2. 无参数,有返回值
            3. 10.1.3. 3. 有参数,无返回值
            4. 10.1.4. 4. 有参数,有返回值
          2. 10.2. 函数其他注意
            1. 10.2.1. 1. 省略第一个外部参数的名字
            2. 10.2.2. 2. 设置参数默认值
            3. 10.2.3. 3. 设置可变参数
            4. 10.2.4. 4. 修改内部参数的值
            5. 10.2.5. 5. 设置参数为地址传递
            6. 10.2.6. 6. 函数嵌套
            7. 10.2.7. 7. 函数的类型
            8. 10.2.8. 8. 区分不同函数
        11. 11. 枚举
        12. 12. 结构体
          1. 12.1. 1. 结构体基本使用
          2. 12.2. 2. 结构体扩充构造函数
        13. 13.
          1. 13.1. 1. 类的声明初始化
          2. 13.2. 2. 类的属性和方法
          3. 13.3. 3. 类的继承之KVC使用
          4. 13.4. 4. 类的循环引用
          5. 13.5. 5. 结构体和类的区别
          6. 13.6. 6. OC中使用Swift的类和结构体
          7. 13.7. 7. Swift中调用OC
        14. 14. 三大特性
        15. 15. 可选链
        16. 16. 协议
          1. 16.1. 1.协议的基本使用
          2. 16.2. 2. 协议中使用代理
          3. 16.3. 3. 协议中的可选
        17. 17. 闭包
          1. 17.1. 1.闭包的基本使用
          2. 17.2. 2. 尾随闭包和逃逸闭包
          3. 17.3. 3. 闭包的循环引用(4中解决方式)
        18. 18. 懒加载
        19. 19. 注释
        20. 20. 访问权限
          1. 20.1. 访问修饰符
        21. 21. 方法抛出异常
        22. 22. Playground
          1. 22.1. 1. Playground异步执行
          2. 22.2. 2. MarkDown语法
          3. 22.3. 3. TimeLine使用
          4. 22.4. 4. Playground的Sources目录

      -

      Swift3.0相关的语法介绍

      - +

      Any AnyObject NSObject

      Int Double String struct都是结构体

      1. Any : 一个协议声明
      2. diff --git a/categories/iOS/index.html b/categories/iOS/index.html new file mode 100644 index 0000000..66bc9e3 --- /dev/null +++ b/categories/iOS/index.html @@ -0,0 +1,310 @@ + + + + + + Category: iOS | CoderShmily's Blog + + + + + + + + + + + + + + + + + + + + + + + + + +
        +
        + +
        +
        + + + + + + +
        +
        + 2015 +
        +
        + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        + + +
        + + + +
        +
        + +
        + +
        +
        +
        + + + + + + + + + + + + +
        + + \ No newline at end of file diff --git a/index.html b/index.html index f57a601..f9d49da 100644 --- a/index.html +++ b/index.html @@ -94,12 +94,119 @@

        -

        Swift3.0相关的语法介绍

        - -

        - Read More -

        - + + + +

        Any AnyObject NSObject

        Int Double String struct都是结构体

        +
          +
        1. Any : 一个协议声明
        2. +
        3. AnyObject : 一个具体的协议,协议里面没有内容,默认情况下,所有的类,都遵循了这个协议
        4. +
        5. NSObjectNSObject
        6. +
        +

        条件判断

        swift中没有非零即真和零为假的说法,只有严格的Bool(true/false)

        +

        1. if的使用

        1
        2
        3
        4
        5
        6
        7
        8
        let a = 1
        if a == 1 {
        print("test")
        }else if a == 2{
        print("sss")
        }else {
        print("wwqw")
        }
        +

        2. 三目运算符

        1
        a == 1 ? print("first") : print("hello")
        +

        3. guard

          +
        1. guard条件成立,继续往下走,不成立执行else里面的语句
        2. +
        3. else后要跳出语句,配合return,continue,break,throw等使用
        4. +
        +
        1
        2
        3
        4
        5
        6
        7
        8
        9
        func funcTest() {
        let a = 1
        guard a == 1 else {
        print("a != 1")
        return
        }
        print("a == 1")
        }
        +

        4. switch的用法

        1. switch与基本数据

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        // 必须要加default, 但是有些情况可以不加,例如枚举的各个情况都判断过了
        // 判断类型 可以是浮点型,String,对象。
        let a = 11
        switch a {
        case 1, 11:
        print("1, 11")
        fallthrough // 会有穿透效果,如果这个case为true,也执行下个case的内容
        case 2:
        print("2")
        default:
        print("不知道")
        }
        +

        2. switch与区间

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        let score = 10.0
        switch score {
        case 0 ..< 60:
        print("不及格")
        case 60 ..< 90:
        print("及格")
        case 90 ..< 100:
        print("优秀")
        default:
        print("default")
        }
        +

        3. switch与枚举

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        enum Direction {
        case up
        case down
        case left
        case right
        }
        let rr = Direction.right
        switch rr {
        case Direction.up:
        print("up")
        case Direction.down:
        print("down")
        case Direction.left:
        print("right")
        case Direction.right:
        print("right")
        //default: // 此时可以省略default,因为各个情况都已经判断过,default也不会执行
        // print("ss")
        }
        +

        4. switch与元组

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        let point = (10, 25)
        switch point {
        case (0, 0):
        print("坐标在原点")
        case (1...10, 10...20): // 可以在元组中再加上区间
        print("坐标的X和Y在1~10之间")
        case (_, 0): // X可以是任意数
        print("坐标的X在X轴上")
        case (var x, var y): // x,y来接收参数 一定为true
        print("333")
        case var(x,y): where x y // x,y来接收参数 xy则一定为true
        print("1111")
        default:
        print("Other")
        }
        +

        循环

        1. for循环

        1
        2
        3
        4
        5
        6
        7
        8
        for i in 0 ..< 10 {
        print(i)
        }
        // _代表忽略的意思
        for _ in 0 ..< 10 {
        print("test")
        }
        +

        2. while循环

        1. while循环

        1
        2
        3
        4
        5
        var i = 10
        while i 0 {
        i -= 1
        print(i)
        }
        +

        2. repeat~while循环

        1
        2
        3
        4
        5
        // do 特殊含义,捕捉异常
        repeat {
        i += 1
        print(i)
        } while i < 10
        +

        字符串处理

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        let str2 = "123"
        let int4 = 10
        // 字符串拼接
        str2 + "\(int4)"
        // 遍历字符串
        for i in str2.characters {
        print(i)
        }
        str2.lengthOfBytes(using: String.Encoding.utf8)
        str2.characters.count
        String(format: "%02d", 1)
        // 截取字符串
        str2.substring(from: str2.startIndex)
        str2.substring(to: str2.index(after: str2.startIndex))
        str2.substring(from: str2.index(str2.startIndex, offsetBy: 2))
        str2.substring(from: str2.index(str2.endIndex, offsetBy: -1))
        let range = str2.startIndex ..< str2.endIndex
        str2.substring(with: range)
        str2.replaceSubrange(range, with: "sss")
        // 转为OC的NSString处理
        let str3 = (str2 as NSString).substring(to: 2)
        +

        数组

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        45
        46
        47
        48
        49
        50
        51
        52
        53
        54
        // 数组的声明和初始化
        let arr1 = [2]
        var arr2 : [Any] = [1, 2, "ii", 11, "ss", "w"]
        let arr3 = [1, 1.1, "ss"] as [Any]
        // 相同类型的数组可以直接相加
        arr2 + arr3
        // 获取
        arr2.first
        arr2.last
        arr2[0]
        // 追加
        arr2.append(2.0)
        // 修改
        arr2[0] = 1
        // 插入
        arr2.insert("sww", at: 2)
        // 删除
        arr2.remove(at: 0)
        arr2.removeFirst()
        arr2.removeFirst(1)
        // 操作数组的区间
        let rang2 = 0 ..< 2
        arr2.removeSubrange(0 ..< 2)
        // 获取数组最大最小
        var arr = [1, 2]
        arr.min()
        arr.max()
        var arr4 = ["a", "3.3"]
        // 比的ASCII码
        arr4.min()
        arr4.max()
        // 数组的遍历
        for i in 0 ..< arr2.count {
        print(arr2[i])
        }
        // 利用元组获取数组的 角标+ 值
        for (key ,value) in arr2.enumerated() {
        print(key, value)
        }
        for i in arr2[0...2] {
        print(i)
        }
        // 转为OC数组的遍历
        (arr2 as NSArray).enumerateObjects({ (value, idx, stop) in
        print(value, idx)
        })
        +

        字典

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        var dict : [String : Any] = ["key" : 1, "key2" : "value"]
        dict["key"] = 2
        let index = dict.index(forKey: "key")
        // index为nil报错
        dict.remove(at: index!)
        // 有则改,无则加
        dict.updateValue("value2", forKey: "key2")
        dict.removeValue(forKey: "key2")
        dict.removeAll()
        for value in dict.values {
        print(value)
        }
        for (key ,value) in dict {
        print(key, value)
        }
        // 类扩展---字典的相+
        extension Dictionary {
        static func +(dic : Dictionary, dic2 : Dictionary) - Dictionary
        {
        var result = dic
        for (key , value) in dic2 {
        result[key] = value
        }
        return result
        }
        }
        +

        元组

        1
        2
        3
        4
        5
        6
        7
        // 元组类型 (name: String, Int, score: Int), 可以作为返回值
        let yz = (name : "zhangsan", _ : 18, score : 2)
        yz.0
        yz.name
        yz.score
        let(name, age, score) = ("zhangsan", 2, 2)
        +

        可选类型

        ##1. 非可选类型 (使用的时候必须有值)

        +
        1
        let sum : Int
        +

        2. 可选类型 (才能赋值为nil)

        Swift中的nil != OC中的nil,Swift种的nil就是一个特殊含义的字符,表示没有值

        +
        1
        2
        3
        4
        5
        6
        7
        8
        // let sum0 : Int?
        // let sum0 : Optional<Int = 2
        let sum1 : Int!
        sum = nil
        // sum0 (Int?)需要解包才能使用
        // sum1 (Int!)赋值后可以直接使用,不用解包
        +

        3. 四种方式使用可选类型的值

        1. 判断 + 直接解包

        1
        2
        3
        if sum != nil {
        sum!
        }
        +

        2. 可选绑定

        1
        2
        3
        if let tmp = sum {
        tmp
        }
        +

        3. guard守护

        1
        2
        3
        4
        5
        6
        func funcl(tmp : Int?) {
        guard let test = tmp else {
        return
        }
        test
        }
        +

        4. 空合运算符

        1
        2
        3
        // 如果sum == nil,那么取 ?? 后面的值
        // 如果 sum != nil, 取 sum! 强制解包后的值
        let tmp2 = sum ?? 0
        +

        类型转换

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        var a = 8.8
        a is Int
        a is Double
        let str = "123"
        str as NSString
        str as Any
        // as! 代表,肯定可以转换成功,转换的结果,是非可选 不能为nil
        // as? 代表,系统尝试帮你进行转换,转失败了,就为nil
        +

        函数

        1. 函数的四种类型

        1. 无参数,无返回值

        1
        2
        3
        4
        5
        6
        7
        8
        9
        func func1() {
        }
        func func2() - Void {
        }
        func func3() - () {
        }
        +

        2. 无参数,有返回值

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        func func1() {
        }
        func func2() - Int {
        return 0
        }
        // 返回元组
        func func3() - (Int, String) {
        return (1, "123")
        }
        +

        3. 有参数,无返回值

        1
        2
        3
        func func1(age : Int) {
        }
        +

        4. 有参数,有返回值

        1
        2
        3
        func func3(age : Int) - (Int, String) {
        return (1, "123")
        }
        +

        函数其他注意

        1. 省略第一个外部参数的名字

        1
        2
        3
        4
        5
        // 省略第一个内部参数(函数内部可以使用的参数)
        // 从swift3.0开始默认第一个参数既是外部参数(函数调用时可以看到的参数)也是内部参数
        func func2(_ name : Int, name2 : Int) - Int {
        return 0
        }
        +

        2. 设置参数默认值

        1
        2
        3
        4
        // 设置默认值,会生成几种组合(带不带第二个参数的)
        func func2(name : Int, name2 : Int = 1) - Int {
        return 0
        }
        +

        3. 设置可变参数

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        // 可变参数 类型...
        // 函数内部,把这个参数,当做数组来处理
        // 函数外部,直接可以传递多个值,用逗号隔开
        func addNum(nums : Int...) - Int {
        var result = 0
        for num in nums {
        result += num
        }
        return result
        }
        addNum(nums: 1, 2, 3)
        +

        4. 修改内部参数的值

        1
        2
        3
        4
        5
        6
        7
        8
        // 默认不能修改内部参数的值
        func change(num : Int) {
        // num 为常亮,不能修改
        var num = num
        num = 3
        }
        let a = 0
        change(num: a)
        +

        5. 设置参数为地址传递

        1
        2
        3
        4
        // inout设置第一个参数为地址传递
        func func1(name : inout Int, name2 : Int) - Int {
        return 0
        }
        +

        6. 函数嵌套

        1
        2
        3
        4
        5
        func test() {
        func test2() {
        print("sss")
        }
        }
        +

        7. 函数的类型

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        // (Int, Int) - Int
        // 函数的类型 : 参数类型 和返回值类型
        func add(num : Int, num2 : Int) - Int{
        return num + num2
        }
        // (Int, Int) - Int
        // 函数的类型 : 参数类型 和返回值类型
        func jian(num : Int, num2 : Int) - Int{
        return num - num2
        }
        func exec(n1 : Int, n2 : Int, fun : (Int, Int) - Int) {
        let result = fun(n1 ,n2)
        print(result)
        }
        exec(n1: 3, n2: 2, fun: add)
        exec(n1: 3, n2: 2, fun: jian)
        +

        8. 区分不同函数

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        func test() {
        }
        // 参数返回值不同
        func test() - Int {
        return 0
        }
        // 参数类型不同
        func test(age : Int) - Int {
        return 0
        }
        // 参数名字不同
        func test(_ age : Int) - Int {
        return 0
        }
        // 参数名字不同
        func test(name : Int) - Int {
        return 0
        }
        +

        枚举

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        // 在swift里面,枚举类型,默认情况,不表示任何类型,就是一个标识
        // 类型首字母大写,元素小写
        enum Direction {
        case east
        case west
        }
        enum Direction2 {
        case east, west
        }
        enum Direction3 : Int {
        case east = 1
        case west = 3
        case north // Direction3.north.rawValue = 4 会自己累加
        case south
        }
        // 只有后边指定类型才能敲出rawValue
        // Direction4.left.rawValue 取出的值就是指定的类型
        enum Direction4 : String {
        case left = "left"
        case right = "right"
        case top
        case down
        func func1() {
        print("wwwww")
        }
        static func func2() {
        print("rrrr")
        }
        }
        let rv = Direction3.north.rawValue
        let rv2 = Direction3(rawValue: 1)
        let rv3 = Direction4(rawValue: "left")
        func test(path : Direction4) {
        if path == .left {
        print(path.rawValue)
        }
        }
        +

        结构体

        1. 结构体基本使用

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        // 类型方法 static func
        // 实例方法 func
        // 无论是枚举,还是结构体,都可以写方法
        struct Point {
        // 实例属性
        var x : Double
        var y : Double
        // 实例方法
        func distance() - Double {
        return x - y
        }
        mutating func distance2() - Double {
        x += 2 // 修改实例属性 方法要加mutating
        print(Point.z) // 访问类型属性
        return x - y
        }
        // 类型属性
        static var z : Double = 0 // 需要初始化
        // 类型方法
        static func dis() {
        // print(x) 不能直接访问x
        print(z)
        print(Point.z)
        }
        }
        +

        2. 结构体扩充构造函数

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        struct Point {
        // 实例属性
        var x : Double
        var y : Double
        var z : Double?
        // 自定义 “构造函数” != 普通函数
        // 不加func,必须使用init作为名称
        // 在构造函数内部,必须要保证,所有的非可选属性,必须有值
        // 如果我们自定义了构造函数,那么系统生成的逐一构造器,就没有了
        init(x : Double, y : Double) {
        self.x = x
        self.y = y
        }
        init(x : Double, y : Double, z : Double) {
        self.x = x
        self.y = y
        self.z = z
        }
        }
        +

        1. 类的声明初始化

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        // swift类,是可以不继承父类,那它本身就是rootClass
        // 可以写属性和方法
        // 属性:实例属性,类型属性
        // 方法:实例方法,类型方法
        // 类,默认情况下,不会生成逐一构造器(目的,保证所有的非可选属性有值)
        // 默认情况下,不能保证,所有的非可选属性有值
        // 一个实例对象被创建好以后,必须保证里面所有的非可选属性有值
        // 方案1:在构造函数中入手,给非可选属性初始化
        // 方案2:把非可选 - 可选
        // 方案3:给非可选的属性赋值默认值
        class Person {
        var age : Int
        init(age : Int) {
        // 为了不与age参数冲突才使用self
        self.age = age
        }
        init() {
        age = 2
        }
        }
        // 不会生成逐一构造器
        let p = Person()
        let p2 = Person(age: 3)
        +

        2. 类的属性和方法

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        45
        46
        47
        48
        49
        class Person {
        // 实例属性 - 存储属性(可以用来存储数值的属性)
        var score = 1
        var score2 : Int = 0 {
        willSet {
        score2 // old
        newValue // new
        }
        // willSet(changeName) {
        // score2 // old
        // changeName // new
        // }
        didSet {
        score2 // new
        oldValue // old
        }
        }
        // 实例属性 - 计算属性(并不是直接用来存储数值的,它是通过某些计算得来的数值)
        var b : Int {
        get {
        return score + score2
        }
        set {
        newValue
        }
        }
        // 类型属性
        static var c = 1
        static var d : Int?
        // 实例方法
        func func1() {
        self.score += 1
        }
        // 类型方法 - 不可以被子类重写override
        static func func2() {
        print("rrrr", c)
        }
        // 类型方法 - 可以被子类重写(结构体不能用class声明方法)
        class func func3() {
        print("sss")
        }
        // 结构体不能使用deinit析构函数
        // 析构函数只能被定义在class类中,不能在extension中
        deinit {
        print("类死了")
        }
        }
        +

        3. 类的继承之KVC使用

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        class Person : NSObject {
        var age : Int = 0
        var name : String = ""
        init(dic : [String : Any]) {
        // KVC实现之前,必须调用父类的init方法初始化
        super.init()
        setValuesForKeys(dic)
        }
        }
        let dic : [String : Any] = ["name" : "zhangsan", "age" : 33]
        let stu = Person(dic: dic)
        +

        4. 类的循环引用

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        class Person {
        var dog : Dog?
        deinit {
        print("人挂了")
        }
        }
        class Dog {
        // 使用weak来避免循环引用 (unowned也可以)
        weak var master : Person?
        deinit {
        print("🐶挂了")
        }
        }
        var p : Person? = Person()
        var d : Dog? = Dog()
        p?.dog = d
        d?.master = p
        p = nil
        d = nil
        +

        5. 结构体和类的区别

          +
        1. 结构体有逐一构造器,类没有
        2. +
        3. 结构体是值类型,类是引用类型
        4. +
        5. 结构体不能继承(意味着没有多态)
        6. +
        +

        6. OC中使用Swift的类和结构体

          +
        1. OC与Swift混编,Swift中的函数名要符合OC的规范,重载的方法用@objc指定名字,避免冲突
        2. +
        3. 如果是类,必须要继承自NSObject,而且用public关键字对类、方法、属性等进行修饰
        4. +
        5. 如果是协议最好继承自NSObjectProtocol(也就对应OC中的基协议),用标识符@objc,而且声明为public
        6. +
        7. Build Settings搜索-Swift,找到 Objective-C Generated Interface Header Name 里面的.h文件即为OC调用时,要包含的头文件 #import "XXX-Swift.h"
        8. +
        +
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        public class Person : NSObject {
        public var name : String = ""
        public func getAge() {
        print("hello age")
        }
        }
        @objc
        public protocol work : NSObjectProtocol{
        func goWork()
        }
        +

        7. Swift中调用OC

          +
        1. Swift项目创建OC文件时回生成.h桥接文件,可以在Build SettingsObjective-C Bridging Header中找到,也可以自己创建.h文件,路径跟系统生成的一致
        2. +
        3. 在.h文件包含对应的OC头文件
        4. +
        +

        三大特性

        类的三大特性:封装、继承、多态

        +
        1
        2
        3
        4
        5
        6
        7
        8
        class Test : NSObject {
        // 类继承NSObject后,下面两个方法会报错,说是转换到OC以后两个方法有冲突
        func chongzai(a : Int) {
        }
        func chongzai(a : Double) {
        }
        }
        +

        解决办法:

        +
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        public class Test : NSObject {
        public func chongzai(a : Int) {
        }
        // 通过此标识,自定义生成的方法名,解决重复冲突
        @objc(chongzai:)
        public func chongzai(a : Double) {
        }
        }
        // 项目名称为app,弹框选择的是不桥接
        // Build Settings搜索-Swift,找到 Objective-C Generated Interface Header Name 里面的.h文件即为要包含的头文件
        #import "app-Swift.h"
        @implementation ViewController
        - (void)viewDidLoad {
        [super viewDidLoad];
        Test *t = [[Test alloc] init];
        [t chongzaiWithA:(NSInteger)];
        }
        +

        可选链

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        class Person {
        var dog : Dog?
        }
        class Dog {
        var name : String = "wangcai"
        var toy : Toy?
        }
        class Toy {
        var price : Double = 0.0
        }
        let p = Person()
        // 如果可选链的结果是nil,就代表链条中间至少有一个环节断了
        // () == Void != nil
        p.dog?.toy?.price
        +

        协议

        1.协议的基本使用

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        protocol work {
        func run()
        }
        // 枚举也可以遵循协议
        enum Direction : work {
        case left
        case right
        // 实例方法
        func run() {
        print("Direction run")
        }
        }
        Direction.left.run()
        // 协议可以继承,这里不叫遵循,遵循work协议是要实现函数的
        protocol work2 : NSObjectProtocol{
        func run2()
        }
        // 如果遵循了协议,要求,必须实现协议里的所有方法
        // 同时继承 + 遵循协议,不支持多继承
        // NSObject 实现了NSObjectProtocol协议的所有方法
        class Stu : NSObject, work2 {
        func run2() {
        print("Stu run2")
        }
        }
        +

        2. 协议中使用代理

          +
        1. weak 修饰类,work : class,轻量级
        2. +
        3. work : NSObjectProtocol也可以,但是遵循work协议的类,都要继承要NSObject
        4. +
        +
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        protocol work : NSObjectProtocol{
        func run()
        }
        //protocol work : class{
        // func run()
        //}
        class Stu {
        weak var delegate : work?
        func run() {
        print("Stu run2")
        }
        }
        +

        3. 协议中的可选

        协议中的可选,仅仅是OC的特性,Swift是不支持的
        解决方案:就是让Swift协议,拥有OC特性

        +
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        @objc
        protocol work {
        @objc optional func run()
        }
        class Stu : work {
        func run() {
        print("Stu run2")
        }
        }
        +

        #泛型

        +
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        // 泛化的类型,不是某一个具体的类型, <T中的T可以自定义名字
        func exchange<T(num1 : inout T, num2 : inout T) {
        let tmp = num1
        num1 = num2
        num2 = tmp
        }
        class Person {
        }
        // 限制 T 必须继承自 Person
        func exchange2<T(num1 : inout T, num2 : inout T) - Int where T : Person {
        let tmp = num1
        num1 = num2
        num2 = tmp
        return 0
        }
        var a = 3
        var b = 9
        var p1 = Person()
        var p2 = Person()
        exchange(num1: &a, num2: &b)
        // 参数必须继承自 Person
        exchange2(num1: &p1, num2: &p2)
        +

        闭包

        闭包 == 特殊的函数

        +

        1.闭包的基本使用

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        // 函数
        func add(num1 : Int, num2 : Int) - Int {
        return num1 + num2
        }
        // 简单的闭包
        // 如果闭包,参数是没有的,可以省略,in和in前面的内容
        var bibao : ()-() = {
        // ()-() in // 可以省略
        }
        // 带参数的闭包
        var bibao2 : (Int, Int)-(Int) = {
        // (varg1, varg2) in
        (varg1 : Int, varg2 : Int) in
        return varg1 + varg2
        }
        bibao2(10, 20)
        // 闭包当做参数
        func exec(n1 : Int, n2 : Int, block : (Int, Int)-(Int)) - Int {
        return block(n1, n2)
        }
        exec(n1: 20, n2: 30, block: add)
        exec(n1: 20, n2: 30, block: bibao2)
        exec(n1: 20, n2: 30, block: {
        (a : Int, b : Int)-(Int) in
        return a * b
        })
        +

        2. 尾随闭包和逃逸闭包

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        //尾随闭包是一个书写在函数括号之后的闭包表达式,函数支持将其作为最后一个参数调用。在使用尾随闭包时,你不用写出它的参数标签(此处是bb)
        // 如果一个函数的参数,是一个闭包类型,那么默认情况下,是一个“非逃逸”闭包;(闭包,生命周期,是函数)
        func test(a : Int, bb : (Int, Int)-(Int)) {
        let result = bb(a, 3)
        print(result)
        }
        test(a: 20) { (sum1, sum2) - (Int) in
        return sum1 - sum2
        }
        // @escaping : 代表,这个闭包,是逃逸闭包,以后,有可能,会被其他的闭包,延长生命周期(强引用)
        func test2(bb : @escaping (Int, Int)-(Int)) {
        bb(23, 3)
        let queue = DispatchQueue(label: "xx")
        let time = DispatchTime.now() + DispatchTimeInterval.seconds(2)
        queue.asyncAfter(deadline: time) {
        // 此处编译器会提示添加 @escaping
        _ = bb(10, 3)
        }
        }
        test2 { (sum, sum2) - (Int) in
        return sum * sum2
        }
        +

        3. 闭包的循环引用(4中解决方式)

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        class Person {
        class Person {
        var resultBlock : (()-())?
        var age : Int = 0
        func test() {
        // weak 对象最后会被置为 nil,所以var
        weak var weakSelf = self
        resultBlock = {
        print("222",weakSelf?.age)
        }
        resultBlock?()
        }
        func test2() {
        resultBlock = {
        [weak self] in
        print(self?.age)
        }
        resultBlock?()
        }
        func test3() {
        // unowned == __unsafe_unretained 最后不会置为nil,编译器建议为let
        unowned let weakSelf = self
        resultBlock = {
        print(weakSelf.age)
        }
        resultBlock?()
        }
        func test4() {
        resultBlock = {
        [unowned self] in
        print(self.age)
        }
        resultBlock?()
        }
        deinit {
        print("人被释放了")
        }
        }
        var p : Person? = Person()
        p?.test()
        p = nil
        +

        懒加载

        只是在第一次访问的时候,会调用相应的函数,获取实例,下次即使值为nil,也不会再次调用相应的函数,获取新的实例

        +
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        class Dog {
        var name : String = "wangcai"
        init() {
        print("创建了小狗")
        }
        }
        // 懒加载
        // 函数:构造函数,一般的函数,闭包
        // = 后面可以跟的值:具体的指,构造“函数”
        // 所谓的懒加载,是指,在用的时候,再通过后面的函数,获取相应的实例
        class Person {
        lazy var dog : Dog = Dog()
        // 这样的懒加载可以对创建的对象进行修改
        lazy var dog2 : Dog = Person.getDog()
        // 懒加载内容放到闭包,最后调用闭包
        lazy var dog3 : Dog = {
        let d = Dog()
        d.name = "dog3"
        return d
        }()
        lazy var dog4 : Dog = {
        $0.name = "dog4"
        return $0
        }(Dog())
        static func getDog() - Dog {
        let d = Dog()
        d.name = "getDog"
        return d
        }
        }
        +

        注释

        1
        2
        3
        // MARK: - ARC
        // TODO: - todo
        // FIXME: 解决bug
        +

        访问权限

          +
        1. Swift中的访问控制模型基于模块和源文件、类这三个概念
        2. +
        3. Swift访问权限,作用于类,属性,方法等
        4. +
        5. Swift中的访问级别遵循一个基本原则:不可以在某个实体中定义访问级别更高的实体(类如果都不能访问,里面的属性方法就算开放了也不能访问)

          访问修饰符

        6. +
        7. internal : 在本模块中都可以访问,(默认),子类也可以继承
        8. +
        9. private : 当前类私有
        10. +
        11. fileprivate : 在当前源文件中可以访问
        12. +
        13. public : 跨模块时,如果修饰类,则无法继承。修饰方法,不能被override
        14. +
        15. open : 跨模块时,如果修饰类,可以继承。修饰方法,可以被override
        16. +
        +

        方法抛出异常

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        // Error 就是在告诉编译器,这个枚举,可以充当具体的异常值
        enum FileError : Error{
        case notExists
        case notFormat
        case notContent
        }
        // path 不存在 nil
        // path存在,但是,路径对应的文件格式不对 .png
        func readFile(path : String) throws - String {
        // 1. 判断文件路径是否存在
        let isExists = FileManager.default.fileExists(atPath: path)
        if !isExists {
        // 在这里面,抛出,出现问题的原因
        // 如果想要成为,异常值,必须要遵循一个协议Error
        throw FileError.notExists
        // return
        }
        // 2. 读取文件内容
        // 判定,如果这个构造函数,出现了异常,一般都是格式不正确
        var content : String = ""
        do {
        content = try String(contentsOfFile: path)
        } catch {
        // 捕捉到异常,会执行这个闭包
        throw FileError.notFormat
        }
        if content.lengthOfBytes(using: String.Encoding.utf8) == 0 {
        throw FileError.notContent
        }
        return content
        }
        +

        Playground

        1. Playground异步执行

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        // Playground中的代码会从上到下执行,并在执行完毕之后立即停止,如果想要测试异步处理(比如网络请求)
        // 1. 导入PlaygroundSupport
        // import PlaygroundSupport
        // 2. 让Playground永远执行
        //PlaygroundPage.current.needsIndefiniteExecution = true
        // 3. 停止执行
        // PlaygroundPage.current.finishExecution()
        import PlaygroundSupport
        PlaygroundPage.current.needsIndefiniteExecution = true
        let queue = DispatchQueue(label: "xx")
        let time = DispatchTime.now() + DispatchTimeInterval.seconds(2)
        queue.asyncAfter(deadline: time) {
        print("finish")
        PlaygroundPage.current.finishExecution()
        }
        print("first")
        +

        2. MarkDown语法

        从Xcode右边文件属性,选中Render Documentation看渲染效果

        1
        2
        3
        4
        5
        //: [Previous](@previous)
        //: [Next](@next)
        //PageName为页名字不能有空格
        //: [Go to AnyPage](PageName)

        +

        3. TimeLine使用

        点击右上角双环(Show the Assistant editor),在代码中做的动画可以在TimeLine中预览

        +

        4. Playground的Sources目录

          +
        1. 放到Sources目录下的源文件会被编译成模块(module)并自动导入到Playground中,只会编译一次
        2. +
        3. 使用注意:需要使用public关键字修饰资源文建中,需要暴露给外界的内容
        4. +
        +
        From 1e1bafbdeb7b7aefadef63827c1ffe10b4864f36 Mon Sep 17 00:00:00 2001 From: CoderShmily Date: Tue, 4 Apr 2017 10:38:21 +0800 Subject: [PATCH 006/148] Customize commit message --- categories/iOS/index.html | 310 -------------------------------------- 1 file changed, 310 deletions(-) delete mode 100644 categories/iOS/index.html diff --git a/categories/iOS/index.html b/categories/iOS/index.html deleted file mode 100644 index 66bc9e3..0000000 --- a/categories/iOS/index.html +++ /dev/null @@ -1,310 +0,0 @@ - - - - - - Category: iOS | CoderShmily's Blog - - - - - - - - - - - - - - - - - - - - - - - - - -
        -
        - -
        -
        - - - - - - -
        -
        - 2015 -
        -
        - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        - - -
        - - - -
        -
        - -
        - -
        -
        -
        - - - - - - - - - - - - -
        - - \ No newline at end of file From 680c36c0c5e88f9480f5e5ba24071af341821729 Mon Sep 17 00:00:00 2001 From: CoderShmily Date: Tue, 4 Apr 2017 10:39:03 +0800 Subject: [PATCH 007/148] Customize commit message --- .../2016-11-15-Swift3.0-jie-shao/index.html | 33 +- categories/iOS/index.html | 310 ++++++++++++++++++ index.html | 119 +------ 3 files changed, 322 insertions(+), 140 deletions(-) create mode 100644 categories/iOS/index.html diff --git a/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html b/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html index 9f42e60..9a40dfd 100644 --- a/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html +++ b/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html @@ -5,37 +5,16 @@ Swift3.0学习笔记 | CoderShmily's Blog - + - - + + - + @@ -118,10 +97,10 @@

        文章目录 -
        1. 1. Any AnyObject NSObject
        2. 2. 条件判断
          1. 2.1. 1. if的使用
          2. 2.2. 2. 三目运算符
          3. 2.3. 3. guard
          4. 2.4. 4. switch的用法
            1. 2.4.1. 1. switch与基本数据
            2. 2.4.2. 2. switch与区间
            3. 2.4.3. 3. switch与枚举
            4. 2.4.4. 4. switch与元组
        3. 3. 循环
          1. 3.1. 1. for循环
          2. 3.2. 2. while循环
            1. 3.2.1. 1. while循环
            2. 3.2.2. 2. repeat~while循环
        4. 4. 字符串处理
        5. 5. 数组
        6. 6. 字典
        7. 7. 元组
        8. 8. 可选类型
          1. 8.1. 2. 可选类型 (才能赋值为nil)
          2. 8.2. 3. 四种方式使用可选类型的值
            1. 8.2.1. 1. 判断 + 直接解包
            2. 8.2.2. 2. 可选绑定
            3. 8.2.3. 3. guard守护
            4. 8.2.4. 4. 空合运算符
        9. 9. 类型转换
        10. 10. 函数
          1. 10.1. 1. 函数的四种类型
            1. 10.1.1. 1. 无参数,无返回值
            2. 10.1.2. 2. 无参数,有返回值
            3. 10.1.3. 3. 有参数,无返回值
            4. 10.1.4. 4. 有参数,有返回值
          2. 10.2. 函数其他注意
            1. 10.2.1. 1. 省略第一个外部参数的名字
            2. 10.2.2. 2. 设置参数默认值
            3. 10.2.3. 3. 设置可变参数
            4. 10.2.4. 4. 修改内部参数的值
            5. 10.2.5. 5. 设置参数为地址传递
            6. 10.2.6. 6. 函数嵌套
            7. 10.2.7. 7. 函数的类型
            8. 10.2.8. 8. 区分不同函数
        11. 11. 枚举
        12. 12. 结构体
          1. 12.1. 1. 结构体基本使用
          2. 12.2. 2. 结构体扩充构造函数
        13. 13.
          1. 13.1. 1. 类的声明初始化
          2. 13.2. 2. 类的属性和方法
          3. 13.3. 3. 类的继承之KVC使用
          4. 13.4. 4. 类的循环引用
          5. 13.5. 5. 结构体和类的区别
          6. 13.6. 6. OC中使用Swift的类和结构体
          7. 13.7. 7. Swift中调用OC
        14. 14. 三大特性
        15. 15. 可选链
        16. 16. 协议
          1. 16.1. 1.协议的基本使用
          2. 16.2. 2. 协议中使用代理
          3. 16.3. 3. 协议中的可选
        17. 17. 闭包
          1. 17.1. 1.闭包的基本使用
          2. 17.2. 2. 尾随闭包和逃逸闭包
          3. 17.3. 3. 闭包的循环引用(4中解决方式)
        18. 18. 懒加载
        19. 19. 注释
        20. 20. 访问权限
          1. 20.1. 访问修饰符
        21. 21. 方法抛出异常
        22. 22. Playground
          1. 22.1. 1. Playground异步执行
          2. 22.2. 2. MarkDown语法
          3. 22.3. 3. TimeLine使用
          4. 22.4. 4. Playground的Sources目录
        +
        1. 1. Swift3.0学习笔记
        2. 2. Any AnyObject NSObject
        3. 3. 条件判断
          1. 3.1. 1. if的使用
          2. 3.2. 2. 三目运算符
          3. 3.3. 3. guard
          4. 3.4. 4. switch的用法
            1. 3.4.1. 1. switch与基本数据
            2. 3.4.2. 2. switch与区间
            3. 3.4.3. 3. switch与枚举
            4. 3.4.4. 4. switch与元组
        4. 4. 循环
          1. 4.1. 1. for循环
          2. 4.2. 2. while循环
            1. 4.2.1. 1. while循环
            2. 4.2.2. 2. repeat~while循环
        5. 5. 字符串处理
        6. 6. 数组
        7. 7. 字典
        8. 8. 元组
        9. 9. 可选类型
          1. 9.1. 2. 可选类型 (才能赋值为nil)
          2. 9.2. 3. 四种方式使用可选类型的值
            1. 9.2.1. 1. 判断 + 直接解包
            2. 9.2.2. 2. 可选绑定
            3. 9.2.3. 3. guard守护
            4. 9.2.4. 4. 空合运算符
        10. 10. 类型转换
        11. 11. 函数
          1. 11.1. 1. 函数的四种类型
            1. 11.1.1. 1. 无参数,无返回值
            2. 11.1.2. 2. 无参数,有返回值
            3. 11.1.3. 3. 有参数,无返回值
            4. 11.1.4. 4. 有参数,有返回值
          2. 11.2. 函数其他注意
            1. 11.2.1. 1. 省略第一个外部参数的名字
            2. 11.2.2. 2. 设置参数默认值
            3. 11.2.3. 3. 设置可变参数
            4. 11.2.4. 4. 修改内部参数的值
            5. 11.2.5. 5. 设置参数为地址传递
            6. 11.2.6. 6. 函数嵌套
            7. 11.2.7. 7. 函数的类型
            8. 11.2.8. 8. 区分不同函数
        12. 12. 枚举
        13. 13. 结构体
          1. 13.1. 1. 结构体基本使用
          2. 13.2. 2. 结构体扩充构造函数
        14. 14.
          1. 14.1. 1. 类的声明初始化
          2. 14.2. 2. 类的属性和方法
          3. 14.3. 3. 类的继承之KVC使用
          4. 14.4. 4. 类的循环引用
          5. 14.5. 5. 结构体和类的区别
          6. 14.6. 6. OC中使用Swift的类和结构体
          7. 14.7. 7. Swift中调用OC
        15. 15. 三大特性
        16. 16. 可选链
        17. 17. 协议
          1. 17.1. 1.协议的基本使用
          2. 17.2. 2. 协议中使用代理
          3. 17.3. 3. 协议中的可选
        18. 18. 闭包
          1. 18.1. 1.闭包的基本使用
          2. 18.2. 2. 尾随闭包和逃逸闭包
          3. 18.3. 3. 闭包的循环引用(4中解决方式)
        19. 19. 懒加载
        20. 20. 注释
        21. 21. 访问权限
          1. 21.1. 访问修饰符
        22. 22. 方法抛出异常
        23. 23. Playground
          1. 23.1. 1. Playground异步执行
          2. 23.2. 2. MarkDown语法
          3. 23.3. 3. TimeLine使用
          4. 23.4. 4. Playground的Sources目录
        - +

        Swift3.0学习笔记

        Any AnyObject NSObject

        Int Double String struct都是结构体

        1. Any : 一个协议声明
        2. diff --git a/categories/iOS/index.html b/categories/iOS/index.html new file mode 100644 index 0000000..66bc9e3 --- /dev/null +++ b/categories/iOS/index.html @@ -0,0 +1,310 @@ + + + + + + Category: iOS | CoderShmily's Blog + + + + + + + + + + + + + + + + + + + + + + + + + +
          +
          + +
          +
          + + + + + + +
          +
          + 2015 +
          +
          + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          + + +
          + + + +
          +
          + +
          + +
          +
          +
          + + + + + + + + + + + + +
          + + \ No newline at end of file diff --git a/index.html b/index.html index f9d49da..fd22727 100644 --- a/index.html +++ b/index.html @@ -94,119 +94,12 @@

          - - - -

          Any AnyObject NSObject

          Int Double String struct都是结构体

          -
            -
          1. Any : 一个协议声明
          2. -
          3. AnyObject : 一个具体的协议,协议里面没有内容,默认情况下,所有的类,都遵循了这个协议
          4. -
          5. NSObjectNSObject
          6. -
          -

          条件判断

          swift中没有非零即真和零为假的说法,只有严格的Bool(true/false)

          -

          1. if的使用

          1
          2
          3
          4
          5
          6
          7
          8
          let a = 1
          if a == 1 {
          print("test")
          }else if a == 2{
          print("sss")
          }else {
          print("wwqw")
          }
          -

          2. 三目运算符

          1
          a == 1 ? print("first") : print("hello")
          -

          3. guard

            -
          1. guard条件成立,继续往下走,不成立执行else里面的语句
          2. -
          3. else后要跳出语句,配合return,continue,break,throw等使用
          4. -
          -
          1
          2
          3
          4
          5
          6
          7
          8
          9
          func funcTest() {
          let a = 1
          guard a == 1 else {
          print("a != 1")
          return
          }
          print("a == 1")
          }
          -

          4. switch的用法

          1. switch与基本数据

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          // 必须要加default, 但是有些情况可以不加,例如枚举的各个情况都判断过了
          // 判断类型 可以是浮点型,String,对象。
          let a = 11
          switch a {
          case 1, 11:
          print("1, 11")
          fallthrough // 会有穿透效果,如果这个case为true,也执行下个case的内容
          case 2:
          print("2")
          default:
          print("不知道")
          }
          -

          2. switch与区间

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          let score = 10.0
          switch score {
          case 0 ..< 60:
          print("不及格")
          case 60 ..< 90:
          print("及格")
          case 90 ..< 100:
          print("优秀")
          default:
          print("default")
          }
          -

          3. switch与枚举

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          enum Direction {
          case up
          case down
          case left
          case right
          }
          let rr = Direction.right
          switch rr {
          case Direction.up:
          print("up")
          case Direction.down:
          print("down")
          case Direction.left:
          print("right")
          case Direction.right:
          print("right")
          //default: // 此时可以省略default,因为各个情况都已经判断过,default也不会执行
          // print("ss")
          }
          -

          4. switch与元组

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          let point = (10, 25)
          switch point {
          case (0, 0):
          print("坐标在原点")
          case (1...10, 10...20): // 可以在元组中再加上区间
          print("坐标的X和Y在1~10之间")
          case (_, 0): // X可以是任意数
          print("坐标的X在X轴上")
          case (var x, var y): // x,y来接收参数 一定为true
          print("333")
          case var(x,y): where x y // x,y来接收参数 xy则一定为true
          print("1111")
          default:
          print("Other")
          }
          -

          循环

          1. for循环

          1
          2
          3
          4
          5
          6
          7
          8
          for i in 0 ..< 10 {
          print(i)
          }
          // _代表忽略的意思
          for _ in 0 ..< 10 {
          print("test")
          }
          -

          2. while循环

          1. while循环

          1
          2
          3
          4
          5
          var i = 10
          while i 0 {
          i -= 1
          print(i)
          }
          -

          2. repeat~while循环

          1
          2
          3
          4
          5
          // do 特殊含义,捕捉异常
          repeat {
          i += 1
          print(i)
          } while i < 10
          -

          字符串处理

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          22
          23
          24
          25
          26
          let str2 = "123"
          let int4 = 10
          // 字符串拼接
          str2 + "\(int4)"
          // 遍历字符串
          for i in str2.characters {
          print(i)
          }
          str2.lengthOfBytes(using: String.Encoding.utf8)
          str2.characters.count
          String(format: "%02d", 1)
          // 截取字符串
          str2.substring(from: str2.startIndex)
          str2.substring(to: str2.index(after: str2.startIndex))
          str2.substring(from: str2.index(str2.startIndex, offsetBy: 2))
          str2.substring(from: str2.index(str2.endIndex, offsetBy: -1))
          let range = str2.startIndex ..< str2.endIndex
          str2.substring(with: range)
          str2.replaceSubrange(range, with: "sss")
          // 转为OC的NSString处理
          let str3 = (str2 as NSString).substring(to: 2)
          -

          数组

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          22
          23
          24
          25
          26
          27
          28
          29
          30
          31
          32
          33
          34
          35
          36
          37
          38
          39
          40
          41
          42
          43
          44
          45
          46
          47
          48
          49
          50
          51
          52
          53
          54
          // 数组的声明和初始化
          let arr1 = [2]
          var arr2 : [Any] = [1, 2, "ii", 11, "ss", "w"]
          let arr3 = [1, 1.1, "ss"] as [Any]
          // 相同类型的数组可以直接相加
          arr2 + arr3
          // 获取
          arr2.first
          arr2.last
          arr2[0]
          // 追加
          arr2.append(2.0)
          // 修改
          arr2[0] = 1
          // 插入
          arr2.insert("sww", at: 2)
          // 删除
          arr2.remove(at: 0)
          arr2.removeFirst()
          arr2.removeFirst(1)
          // 操作数组的区间
          let rang2 = 0 ..< 2
          arr2.removeSubrange(0 ..< 2)
          // 获取数组最大最小
          var arr = [1, 2]
          arr.min()
          arr.max()
          var arr4 = ["a", "3.3"]
          // 比的ASCII码
          arr4.min()
          arr4.max()
          // 数组的遍历
          for i in 0 ..< arr2.count {
          print(arr2[i])
          }
          // 利用元组获取数组的 角标+ 值
          for (key ,value) in arr2.enumerated() {
          print(key, value)
          }
          for i in arr2[0...2] {
          print(i)
          }
          // 转为OC数组的遍历
          (arr2 as NSArray).enumerateObjects({ (value, idx, stop) in
          print(value, idx)
          })
          -

          字典

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          22
          23
          24
          25
          26
          27
          28
          29
          30
          31
          32
          var dict : [String : Any] = ["key" : 1, "key2" : "value"]
          dict["key"] = 2
          let index = dict.index(forKey: "key")
          // index为nil报错
          dict.remove(at: index!)
          // 有则改,无则加
          dict.updateValue("value2", forKey: "key2")
          dict.removeValue(forKey: "key2")
          dict.removeAll()
          for value in dict.values {
          print(value)
          }
          for (key ,value) in dict {
          print(key, value)
          }
          // 类扩展---字典的相+
          extension Dictionary {
          static func +(dic : Dictionary, dic2 : Dictionary) - Dictionary
          {
          var result = dic
          for (key , value) in dic2 {
          result[key] = value
          }
          return result
          }
          }
          -

          元组

          1
          2
          3
          4
          5
          6
          7
          // 元组类型 (name: String, Int, score: Int), 可以作为返回值
          let yz = (name : "zhangsan", _ : 18, score : 2)
          yz.0
          yz.name
          yz.score
          let(name, age, score) = ("zhangsan", 2, 2)
          -

          可选类型

          ##1. 非可选类型 (使用的时候必须有值)

          -
          1
          let sum : Int
          -

          2. 可选类型 (才能赋值为nil)

          Swift中的nil != OC中的nil,Swift种的nil就是一个特殊含义的字符,表示没有值

          -
          1
          2
          3
          4
          5
          6
          7
          8
          // let sum0 : Int?
          // let sum0 : Optional<Int = 2
          let sum1 : Int!
          sum = nil
          // sum0 (Int?)需要解包才能使用
          // sum1 (Int!)赋值后可以直接使用,不用解包
          -

          3. 四种方式使用可选类型的值

          1. 判断 + 直接解包

          1
          2
          3
          if sum != nil {
          sum!
          }
          -

          2. 可选绑定

          1
          2
          3
          if let tmp = sum {
          tmp
          }
          -

          3. guard守护

          1
          2
          3
          4
          5
          6
          func funcl(tmp : Int?) {
          guard let test = tmp else {
          return
          }
          test
          }
          -

          4. 空合运算符

          1
          2
          3
          // 如果sum == nil,那么取 ?? 后面的值
          // 如果 sum != nil, 取 sum! 强制解包后的值
          let tmp2 = sum ?? 0
          -

          类型转换

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          var a = 8.8
          a is Int
          a is Double
          let str = "123"
          str as NSString
          str as Any
          // as! 代表,肯定可以转换成功,转换的结果,是非可选 不能为nil
          // as? 代表,系统尝试帮你进行转换,转失败了,就为nil
          -

          函数

          1. 函数的四种类型

          1. 无参数,无返回值

          1
          2
          3
          4
          5
          6
          7
          8
          9
          func func1() {
          }
          func func2() - Void {
          }
          func func3() - () {
          }
          -

          2. 无参数,有返回值

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          func func1() {
          }
          func func2() - Int {
          return 0
          }
          // 返回元组
          func func3() - (Int, String) {
          return (1, "123")
          }
          -

          3. 有参数,无返回值

          1
          2
          3
          func func1(age : Int) {
          }
          -

          4. 有参数,有返回值

          1
          2
          3
          func func3(age : Int) - (Int, String) {
          return (1, "123")
          }
          -

          函数其他注意

          1. 省略第一个外部参数的名字

          1
          2
          3
          4
          5
          // 省略第一个内部参数(函数内部可以使用的参数)
          // 从swift3.0开始默认第一个参数既是外部参数(函数调用时可以看到的参数)也是内部参数
          func func2(_ name : Int, name2 : Int) - Int {
          return 0
          }
          -

          2. 设置参数默认值

          1
          2
          3
          4
          // 设置默认值,会生成几种组合(带不带第二个参数的)
          func func2(name : Int, name2 : Int = 1) - Int {
          return 0
          }
          -

          3. 设置可变参数

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          // 可变参数 类型...
          // 函数内部,把这个参数,当做数组来处理
          // 函数外部,直接可以传递多个值,用逗号隔开
          func addNum(nums : Int...) - Int {
          var result = 0
          for num in nums {
          result += num
          }
          return result
          }
          addNum(nums: 1, 2, 3)
          -

          4. 修改内部参数的值

          1
          2
          3
          4
          5
          6
          7
          8
          // 默认不能修改内部参数的值
          func change(num : Int) {
          // num 为常亮,不能修改
          var num = num
          num = 3
          }
          let a = 0
          change(num: a)
          -

          5. 设置参数为地址传递

          1
          2
          3
          4
          // inout设置第一个参数为地址传递
          func func1(name : inout Int, name2 : Int) - Int {
          return 0
          }
          -

          6. 函数嵌套

          1
          2
          3
          4
          5
          func test() {
          func test2() {
          print("sss")
          }
          }
          -

          7. 函数的类型

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          // (Int, Int) - Int
          // 函数的类型 : 参数类型 和返回值类型
          func add(num : Int, num2 : Int) - Int{
          return num + num2
          }
          // (Int, Int) - Int
          // 函数的类型 : 参数类型 和返回值类型
          func jian(num : Int, num2 : Int) - Int{
          return num - num2
          }
          func exec(n1 : Int, n2 : Int, fun : (Int, Int) - Int) {
          let result = fun(n1 ,n2)
          print(result)
          }
          exec(n1: 3, n2: 2, fun: add)
          exec(n1: 3, n2: 2, fun: jian)
          -

          8. 区分不同函数

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          func test() {
          }
          // 参数返回值不同
          func test() - Int {
          return 0
          }
          // 参数类型不同
          func test(age : Int) - Int {
          return 0
          }
          // 参数名字不同
          func test(_ age : Int) - Int {
          return 0
          }
          // 参数名字不同
          func test(name : Int) - Int {
          return 0
          }
          -

          枚举

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          22
          23
          24
          25
          26
          27
          28
          29
          30
          31
          32
          33
          34
          35
          36
          37
          38
          39
          40
          41
          42
          43
          44
          // 在swift里面,枚举类型,默认情况,不表示任何类型,就是一个标识
          // 类型首字母大写,元素小写
          enum Direction {
          case east
          case west
          }
          enum Direction2 {
          case east, west
          }
          enum Direction3 : Int {
          case east = 1
          case west = 3
          case north // Direction3.north.rawValue = 4 会自己累加
          case south
          }
          // 只有后边指定类型才能敲出rawValue
          // Direction4.left.rawValue 取出的值就是指定的类型
          enum Direction4 : String {
          case left = "left"
          case right = "right"
          case top
          case down
          func func1() {
          print("wwwww")
          }
          static func func2() {
          print("rrrr")
          }
          }
          let rv = Direction3.north.rawValue
          let rv2 = Direction3(rawValue: 1)
          let rv3 = Direction4(rawValue: "left")
          func test(path : Direction4) {
          if path == .left {
          print(path.rawValue)
          }
          }
          -

          结构体

          1. 结构体基本使用

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          22
          23
          24
          25
          26
          27
          28
          // 类型方法 static func
          // 实例方法 func
          // 无论是枚举,还是结构体,都可以写方法
          struct Point {
          // 实例属性
          var x : Double
          var y : Double
          // 实例方法
          func distance() - Double {
          return x - y
          }
          mutating func distance2() - Double {
          x += 2 // 修改实例属性 方法要加mutating
          print(Point.z) // 访问类型属性
          return x - y
          }
          // 类型属性
          static var z : Double = 0 // 需要初始化
          // 类型方法
          static func dis() {
          // print(x) 不能直接访问x
          print(z)
          print(Point.z)
          }
          }
          -

          2. 结构体扩充构造函数

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          struct Point {
          // 实例属性
          var x : Double
          var y : Double
          var z : Double?
          // 自定义 “构造函数” != 普通函数
          // 不加func,必须使用init作为名称
          // 在构造函数内部,必须要保证,所有的非可选属性,必须有值
          // 如果我们自定义了构造函数,那么系统生成的逐一构造器,就没有了
          init(x : Double, y : Double) {
          self.x = x
          self.y = y
          }
          init(x : Double, y : Double, z : Double) {
          self.x = x
          self.y = y
          self.z = z
          }
          }
          -

          1. 类的声明初始化

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          22
          23
          24
          // swift类,是可以不继承父类,那它本身就是rootClass
          // 可以写属性和方法
          // 属性:实例属性,类型属性
          // 方法:实例方法,类型方法
          // 类,默认情况下,不会生成逐一构造器(目的,保证所有的非可选属性有值)
          // 默认情况下,不能保证,所有的非可选属性有值
          // 一个实例对象被创建好以后,必须保证里面所有的非可选属性有值
          // 方案1:在构造函数中入手,给非可选属性初始化
          // 方案2:把非可选 - 可选
          // 方案3:给非可选的属性赋值默认值
          class Person {
          var age : Int
          init(age : Int) {
          // 为了不与age参数冲突才使用self
          self.age = age
          }
          init() {
          age = 2
          }
          }
          // 不会生成逐一构造器
          let p = Person()
          let p2 = Person(age: 3)
          -

          2. 类的属性和方法

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          22
          23
          24
          25
          26
          27
          28
          29
          30
          31
          32
          33
          34
          35
          36
          37
          38
          39
          40
          41
          42
          43
          44
          45
          46
          47
          48
          49
          class Person {
          // 实例属性 - 存储属性(可以用来存储数值的属性)
          var score = 1
          var score2 : Int = 0 {
          willSet {
          score2 // old
          newValue // new
          }
          // willSet(changeName) {
          // score2 // old
          // changeName // new
          // }
          didSet {
          score2 // new
          oldValue // old
          }
          }
          // 实例属性 - 计算属性(并不是直接用来存储数值的,它是通过某些计算得来的数值)
          var b : Int {
          get {
          return score + score2
          }
          set {
          newValue
          }
          }
          // 类型属性
          static var c = 1
          static var d : Int?
          // 实例方法
          func func1() {
          self.score += 1
          }
          // 类型方法 - 不可以被子类重写override
          static func func2() {
          print("rrrr", c)
          }
          // 类型方法 - 可以被子类重写(结构体不能用class声明方法)
          class func func3() {
          print("sss")
          }
          // 结构体不能使用deinit析构函数
          // 析构函数只能被定义在class类中,不能在extension中
          deinit {
          print("类死了")
          }
          }
          -

          3. 类的继承之KVC使用

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          class Person : NSObject {
          var age : Int = 0
          var name : String = ""
          init(dic : [String : Any]) {
          // KVC实现之前,必须调用父类的init方法初始化
          super.init()
          setValuesForKeys(dic)
          }
          }
          let dic : [String : Any] = ["name" : "zhangsan", "age" : 33]
          let stu = Person(dic: dic)
          -

          4. 类的循环引用

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          class Person {
          var dog : Dog?
          deinit {
          print("人挂了")
          }
          }
          class Dog {
          // 使用weak来避免循环引用 (unowned也可以)
          weak var master : Person?
          deinit {
          print("🐶挂了")
          }
          }
          var p : Person? = Person()
          var d : Dog? = Dog()
          p?.dog = d
          d?.master = p
          p = nil
          d = nil
          -

          5. 结构体和类的区别

            -
          1. 结构体有逐一构造器,类没有
          2. -
          3. 结构体是值类型,类是引用类型
          4. -
          5. 结构体不能继承(意味着没有多态)
          6. -
          -

          6. OC中使用Swift的类和结构体

            -
          1. OC与Swift混编,Swift中的函数名要符合OC的规范,重载的方法用@objc指定名字,避免冲突
          2. -
          3. 如果是类,必须要继承自NSObject,而且用public关键字对类、方法、属性等进行修饰
          4. -
          5. 如果是协议最好继承自NSObjectProtocol(也就对应OC中的基协议),用标识符@objc,而且声明为public
          6. -
          7. Build Settings搜索-Swift,找到 Objective-C Generated Interface Header Name 里面的.h文件即为OC调用时,要包含的头文件 #import "XXX-Swift.h"
          8. -
          -
          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          public class Person : NSObject {
          public var name : String = ""
          public func getAge() {
          print("hello age")
          }
          }
          @objc
          public protocol work : NSObjectProtocol{
          func goWork()
          }
          -

          7. Swift中调用OC

            -
          1. Swift项目创建OC文件时回生成.h桥接文件,可以在Build SettingsObjective-C Bridging Header中找到,也可以自己创建.h文件,路径跟系统生成的一致
          2. -
          3. 在.h文件包含对应的OC头文件
          4. -
          -

          三大特性

          类的三大特性:封装、继承、多态

          -
          1
          2
          3
          4
          5
          6
          7
          8
          class Test : NSObject {
          // 类继承NSObject后,下面两个方法会报错,说是转换到OC以后两个方法有冲突
          func chongzai(a : Int) {
          }
          func chongzai(a : Double) {
          }
          }
          -

          解决办法:

          -
          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          public class Test : NSObject {
          public func chongzai(a : Int) {
          }
          // 通过此标识,自定义生成的方法名,解决重复冲突
          @objc(chongzai:)
          public func chongzai(a : Double) {
          }
          }
          // 项目名称为app,弹框选择的是不桥接
          // Build Settings搜索-Swift,找到 Objective-C Generated Interface Header Name 里面的.h文件即为要包含的头文件
          #import "app-Swift.h"
          @implementation ViewController
          - (void)viewDidLoad {
          [super viewDidLoad];
          Test *t = [[Test alloc] init];
          [t chongzaiWithA:(NSInteger)];
          }
          -

          可选链

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          class Person {
          var dog : Dog?
          }
          class Dog {
          var name : String = "wangcai"
          var toy : Toy?
          }
          class Toy {
          var price : Double = 0.0
          }
          let p = Person()
          // 如果可选链的结果是nil,就代表链条中间至少有一个环节断了
          // () == Void != nil
          p.dog?.toy?.price
          -

          协议

          1.协议的基本使用

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          22
          23
          24
          25
          26
          27
          protocol work {
          func run()
          }
          // 枚举也可以遵循协议
          enum Direction : work {
          case left
          case right
          // 实例方法
          func run() {
          print("Direction run")
          }
          }
          Direction.left.run()
          // 协议可以继承,这里不叫遵循,遵循work协议是要实现函数的
          protocol work2 : NSObjectProtocol{
          func run2()
          }
          // 如果遵循了协议,要求,必须实现协议里的所有方法
          // 同时继承 + 遵循协议,不支持多继承
          // NSObject 实现了NSObjectProtocol协议的所有方法
          class Stu : NSObject, work2 {
          func run2() {
          print("Stu run2")
          }
          }
          -

          2. 协议中使用代理

            -
          1. weak 修饰类,work : class,轻量级
          2. -
          3. work : NSObjectProtocol也可以,但是遵循work协议的类,都要继承要NSObject
          4. -
          -
          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          protocol work : NSObjectProtocol{
          func run()
          }
          //protocol work : class{
          // func run()
          //}
          class Stu {
          weak var delegate : work?
          func run() {
          print("Stu run2")
          }
          }
          -

          3. 协议中的可选

          协议中的可选,仅仅是OC的特性,Swift是不支持的
          解决方案:就是让Swift协议,拥有OC特性

          -
          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          @objc
          protocol work {
          @objc optional func run()
          }
          class Stu : work {
          func run() {
          print("Stu run2")
          }
          }
          -

          #泛型

          -
          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          22
          23
          24
          25
          26
          // 泛化的类型,不是某一个具体的类型, <T中的T可以自定义名字
          func exchange<T(num1 : inout T, num2 : inout T) {
          let tmp = num1
          num1 = num2
          num2 = tmp
          }
          class Person {
          }
          // 限制 T 必须继承自 Person
          func exchange2<T(num1 : inout T, num2 : inout T) - Int where T : Person {
          let tmp = num1
          num1 = num2
          num2 = tmp
          return 0
          }
          var a = 3
          var b = 9
          var p1 = Person()
          var p2 = Person()
          exchange(num1: &a, num2: &b)
          // 参数必须继承自 Person
          exchange2(num1: &p1, num2: &p2)
          -

          闭包

          闭包 == 特殊的函数

          -

          1.闭包的基本使用

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          22
          23
          24
          25
          26
          27
          28
          29
          // 函数
          func add(num1 : Int, num2 : Int) - Int {
          return num1 + num2
          }
          // 简单的闭包
          // 如果闭包,参数是没有的,可以省略,in和in前面的内容
          var bibao : ()-() = {
          // ()-() in // 可以省略
          }
          // 带参数的闭包
          var bibao2 : (Int, Int)-(Int) = {
          // (varg1, varg2) in
          (varg1 : Int, varg2 : Int) in
          return varg1 + varg2
          }
          bibao2(10, 20)
          // 闭包当做参数
          func exec(n1 : Int, n2 : Int, block : (Int, Int)-(Int)) - Int {
          return block(n1, n2)
          }
          exec(n1: 20, n2: 30, block: add)
          exec(n1: 20, n2: 30, block: bibao2)
          exec(n1: 20, n2: 30, block: {
          (a : Int, b : Int)-(Int) in
          return a * b
          })
          -

          2. 尾随闭包和逃逸闭包

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          22
          23
          24
          //尾随闭包是一个书写在函数括号之后的闭包表达式,函数支持将其作为最后一个参数调用。在使用尾随闭包时,你不用写出它的参数标签(此处是bb)
          // 如果一个函数的参数,是一个闭包类型,那么默认情况下,是一个“非逃逸”闭包;(闭包,生命周期,是函数)
          func test(a : Int, bb : (Int, Int)-(Int)) {
          let result = bb(a, 3)
          print(result)
          }
          test(a: 20) { (sum1, sum2) - (Int) in
          return sum1 - sum2
          }
          // @escaping : 代表,这个闭包,是逃逸闭包,以后,有可能,会被其他的闭包,延长生命周期(强引用)
          func test2(bb : @escaping (Int, Int)-(Int)) {
          bb(23, 3)
          let queue = DispatchQueue(label: "xx")
          let time = DispatchTime.now() + DispatchTimeInterval.seconds(2)
          queue.asyncAfter(deadline: time) {
          // 此处编译器会提示添加 @escaping
          _ = bb(10, 3)
          }
          }
          test2 { (sum, sum2) - (Int) in
          return sum * sum2
          }
          -

          3. 闭包的循环引用(4中解决方式)

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          22
          23
          24
          25
          26
          27
          28
          29
          30
          31
          32
          33
          34
          35
          36
          37
          38
          39
          40
          41
          42
          43
          44
          class Person {
          class Person {
          var resultBlock : (()-())?
          var age : Int = 0
          func test() {
          // weak 对象最后会被置为 nil,所以var
          weak var weakSelf = self
          resultBlock = {
          print("222",weakSelf?.age)
          }
          resultBlock?()
          }
          func test2() {
          resultBlock = {
          [weak self] in
          print(self?.age)
          }
          resultBlock?()
          }
          func test3() {
          // unowned == __unsafe_unretained 最后不会置为nil,编译器建议为let
          unowned let weakSelf = self
          resultBlock = {
          print(weakSelf.age)
          }
          resultBlock?()
          }
          func test4() {
          resultBlock = {
          [unowned self] in
          print(self.age)
          }
          resultBlock?()
          }
          deinit {
          print("人被释放了")
          }
          }
          var p : Person? = Person()
          p?.test()
          p = nil
          -

          懒加载

          只是在第一次访问的时候,会调用相应的函数,获取实例,下次即使值为nil,也不会再次调用相应的函数,获取新的实例

          -
          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          22
          23
          24
          25
          26
          27
          28
          29
          30
          31
          32
          33
          class Dog {
          var name : String = "wangcai"
          init() {
          print("创建了小狗")
          }
          }
          // 懒加载
          // 函数:构造函数,一般的函数,闭包
          // = 后面可以跟的值:具体的指,构造“函数”
          // 所谓的懒加载,是指,在用的时候,再通过后面的函数,获取相应的实例
          class Person {
          lazy var dog : Dog = Dog()
          // 这样的懒加载可以对创建的对象进行修改
          lazy var dog2 : Dog = Person.getDog()
          // 懒加载内容放到闭包,最后调用闭包
          lazy var dog3 : Dog = {
          let d = Dog()
          d.name = "dog3"
          return d
          }()
          lazy var dog4 : Dog = {
          $0.name = "dog4"
          return $0
          }(Dog())
          static func getDog() - Dog {
          let d = Dog()
          d.name = "getDog"
          return d
          }
          }
          -

          注释

          1
          2
          3
          // MARK: - ARC
          // TODO: - todo
          // FIXME: 解决bug
          -

          访问权限

            -
          1. Swift中的访问控制模型基于模块和源文件、类这三个概念
          2. -
          3. Swift访问权限,作用于类,属性,方法等
          4. -
          5. Swift中的访问级别遵循一个基本原则:不可以在某个实体中定义访问级别更高的实体(类如果都不能访问,里面的属性方法就算开放了也不能访问)

            访问修饰符

          6. -
          7. internal : 在本模块中都可以访问,(默认),子类也可以继承
          8. -
          9. private : 当前类私有
          10. -
          11. fileprivate : 在当前源文件中可以访问
          12. -
          13. public : 跨模块时,如果修饰类,则无法继承。修饰方法,不能被override
          14. -
          15. open : 跨模块时,如果修饰类,可以继承。修饰方法,可以被override
          16. -
          -

          方法抛出异常

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          22
          23
          24
          25
          26
          27
          28
          29
          30
          31
          32
          33
          // Error 就是在告诉编译器,这个枚举,可以充当具体的异常值
          enum FileError : Error{
          case notExists
          case notFormat
          case notContent
          }
          // path 不存在 nil
          // path存在,但是,路径对应的文件格式不对 .png
          func readFile(path : String) throws - String {
          // 1. 判断文件路径是否存在
          let isExists = FileManager.default.fileExists(atPath: path)
          if !isExists {
          // 在这里面,抛出,出现问题的原因
          // 如果想要成为,异常值,必须要遵循一个协议Error
          throw FileError.notExists
          // return
          }
          // 2. 读取文件内容
          // 判定,如果这个构造函数,出现了异常,一般都是格式不正确
          var content : String = ""
          do {
          content = try String(contentsOfFile: path)
          } catch {
          // 捕捉到异常,会执行这个闭包
          throw FileError.notFormat
          }
          if content.lengthOfBytes(using: String.Encoding.utf8) == 0 {
          throw FileError.notContent
          }
          return content
          }
          -

          Playground

          1. Playground异步执行

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          // Playground中的代码会从上到下执行,并在执行完毕之后立即停止,如果想要测试异步处理(比如网络请求)
          // 1. 导入PlaygroundSupport
          // import PlaygroundSupport
          // 2. 让Playground永远执行
          //PlaygroundPage.current.needsIndefiniteExecution = true
          // 3. 停止执行
          // PlaygroundPage.current.finishExecution()
          import PlaygroundSupport
          PlaygroundPage.current.needsIndefiniteExecution = true
          let queue = DispatchQueue(label: "xx")
          let time = DispatchTime.now() + DispatchTimeInterval.seconds(2)
          queue.asyncAfter(deadline: time) {
          print("finish")
          PlaygroundPage.current.finishExecution()
          }
          print("first")
          -

          2. MarkDown语法

          从Xcode右边文件属性,选中Render Documentation看渲染效果

          1
          2
          3
          4
          5
          //: [Previous](@previous)
          //: [Next](@next)
          //PageName为页名字不能有空格
          //: [Go to AnyPage](PageName)

          -

          3. TimeLine使用

          点击右上角双环(Show the Assistant editor),在代码中做的动画可以在TimeLine中预览

          -

          4. Playground的Sources目录

            -
          1. 放到Sources目录下的源文件会被编译成模块(module)并自动导入到Playground中,只会编译一次
          2. -
          3. 使用注意:需要使用public关键字修饰资源文建中,需要暴露给外界的内容
          4. -
          - +

          Swift3.0学习笔记

          + +

          + Read More +

          +
          From a74949f8b287586bf743888b51609c613ad974b0 Mon Sep 17 00:00:00 2001 From: CoderShmily Date: Tue, 4 Apr 2017 10:42:05 +0800 Subject: [PATCH 008/148] Customize commit message --- .../2016-11-15-Swift3.0-jie-shao/index.html | 13 +- categories/iOS/index.html | 310 ------------------ index.html | 2 +- 3 files changed, 8 insertions(+), 317 deletions(-) delete mode 100644 categories/iOS/index.html diff --git a/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html b/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html index 9a40dfd..6c37a07 100644 --- a/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html +++ b/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html @@ -5,16 +5,16 @@ Swift3.0学习笔记 | CoderShmily's Blog - + - - + + - + @@ -97,10 +97,11 @@

          文章目录 -
          1. 1. Swift3.0学习笔记
          2. 2. Any AnyObject NSObject
          3. 3. 条件判断
            1. 3.1. 1. if的使用
            2. 3.2. 2. 三目运算符
            3. 3.3. 3. guard
            4. 3.4. 4. switch的用法
              1. 3.4.1. 1. switch与基本数据
              2. 3.4.2. 2. switch与区间
              3. 3.4.3. 3. switch与枚举
              4. 3.4.4. 4. switch与元组
          4. 4. 循环
            1. 4.1. 1. for循环
            2. 4.2. 2. while循环
              1. 4.2.1. 1. while循环
              2. 4.2.2. 2. repeat~while循环
          5. 5. 字符串处理
          6. 6. 数组
          7. 7. 字典
          8. 8. 元组
          9. 9. 可选类型
            1. 9.1. 2. 可选类型 (才能赋值为nil)
            2. 9.2. 3. 四种方式使用可选类型的值
              1. 9.2.1. 1. 判断 + 直接解包
              2. 9.2.2. 2. 可选绑定
              3. 9.2.3. 3. guard守护
              4. 9.2.4. 4. 空合运算符
          10. 10. 类型转换
          11. 11. 函数
            1. 11.1. 1. 函数的四种类型
              1. 11.1.1. 1. 无参数,无返回值
              2. 11.1.2. 2. 无参数,有返回值
              3. 11.1.3. 3. 有参数,无返回值
              4. 11.1.4. 4. 有参数,有返回值
            2. 11.2. 函数其他注意
              1. 11.2.1. 1. 省略第一个外部参数的名字
              2. 11.2.2. 2. 设置参数默认值
              3. 11.2.3. 3. 设置可变参数
              4. 11.2.4. 4. 修改内部参数的值
              5. 11.2.5. 5. 设置参数为地址传递
              6. 11.2.6. 6. 函数嵌套
              7. 11.2.7. 7. 函数的类型
              8. 11.2.8. 8. 区分不同函数
          12. 12. 枚举
          13. 13. 结构体
            1. 13.1. 1. 结构体基本使用
            2. 13.2. 2. 结构体扩充构造函数
          14. 14.
            1. 14.1. 1. 类的声明初始化
            2. 14.2. 2. 类的属性和方法
            3. 14.3. 3. 类的继承之KVC使用
            4. 14.4. 4. 类的循环引用
            5. 14.5. 5. 结构体和类的区别
            6. 14.6. 6. OC中使用Swift的类和结构体
            7. 14.7. 7. Swift中调用OC
          15. 15. 三大特性
          16. 16. 可选链
          17. 17. 协议
            1. 17.1. 1.协议的基本使用
            2. 17.2. 2. 协议中使用代理
            3. 17.3. 3. 协议中的可选
          18. 18. 闭包
            1. 18.1. 1.闭包的基本使用
            2. 18.2. 2. 尾随闭包和逃逸闭包
            3. 18.3. 3. 闭包的循环引用(4中解决方式)
          19. 19. 懒加载
          20. 20. 注释
          21. 21. 访问权限
            1. 21.1. 访问修饰符
          22. 22. 方法抛出异常
          23. 23. Playground
            1. 23.1. 1. Playground异步执行
            2. 23.2. 2. MarkDown语法
            3. 23.3. 3. TimeLine使用
            4. 23.4. 4. Playground的Sources目录
          +
          1. 1. Any AnyObject NSObject
          2. 2. 条件判断
            1. 2.1. 1. if的使用
            2. 2.2. 2. 三目运算符
            3. 2.3. 3. guard
            4. 2.4. 4. switch的用法
              1. 2.4.1. 1. switch与基本数据
              2. 2.4.2. 2. switch与区间
              3. 2.4.3. 3. switch与枚举
              4. 2.4.4. 4. switch与元组
          3. 3. 循环
            1. 3.1. 1. for循环
            2. 3.2. 2. while循环
              1. 3.2.1. 1. while循环
              2. 3.2.2. 2. repeat~while循环
          4. 4. 字符串处理
          5. 5. 数组
          6. 6. 字典
          7. 7. 元组
          8. 8. 可选类型
            1. 8.1. 2. 可选类型 (才能赋值为nil)
            2. 8.2. 3. 四种方式使用可选类型的值
              1. 8.2.1. 1. 判断 + 直接解包
              2. 8.2.2. 2. 可选绑定
              3. 8.2.3. 3. guard守护
              4. 8.2.4. 4. 空合运算符
          9. 9. 类型转换
          10. 10. 函数
            1. 10.1. 1. 函数的四种类型
              1. 10.1.1. 1. 无参数,无返回值
              2. 10.1.2. 2. 无参数,有返回值
              3. 10.1.3. 3. 有参数,无返回值
              4. 10.1.4. 4. 有参数,有返回值
            2. 10.2. 函数其他注意
              1. 10.2.1. 1. 省略第一个外部参数的名字
              2. 10.2.2. 2. 设置参数默认值
              3. 10.2.3. 3. 设置可变参数
              4. 10.2.4. 4. 修改内部参数的值
              5. 10.2.5. 5. 设置参数为地址传递
              6. 10.2.6. 6. 函数嵌套
              7. 10.2.7. 7. 函数的类型
              8. 10.2.8. 8. 区分不同函数
          11. 11. 枚举
          12. 12. 结构体
            1. 12.1. 1. 结构体基本使用
            2. 12.2. 2. 结构体扩充构造函数
          13. 13.
            1. 13.1. 1. 类的声明初始化
            2. 13.2. 2. 类的属性和方法
            3. 13.3. 3. 类的继承之KVC使用
            4. 13.4. 4. 类的循环引用
            5. 13.5. 5. 结构体和类的区别
            6. 13.6. 6. OC中使用Swift的类和结构体
            7. 13.7. 7. Swift中调用OC
          14. 14. 三大特性
          15. 15. 可选链
          16. 16. 协议
            1. 16.1. 1.协议的基本使用
            2. 16.2. 2. 协议中使用代理
            3. 16.3. 3. 协议中的可选
          17. 17. 闭包
            1. 17.1. 1.闭包的基本使用
            2. 17.2. 2. 尾随闭包和逃逸闭包
            3. 17.3. 3. 闭包的循环引用(4中解决方式)
          18. 18. 懒加载
          19. 19. 注释
          20. 20. 访问权限
            1. 20.1. 访问修饰符
          21. 21. 方法抛出异常
          22. 22. Playground
            1. 22.1. 1. Playground异步执行
            2. 22.2. 2. MarkDown语法
            3. 22.3. 3. TimeLine使用
            4. 22.4. 4. Playground的Sources目录
          -

          Swift3.0学习笔记

          +

          总结一些 Swift3.0学习笔记

          +

          Any AnyObject NSObject

          Int Double String struct都是结构体

          1. Any : 一个协议声明
          2. diff --git a/categories/iOS/index.html b/categories/iOS/index.html deleted file mode 100644 index 66bc9e3..0000000 --- a/categories/iOS/index.html +++ /dev/null @@ -1,310 +0,0 @@ - - - - - - Category: iOS | CoderShmily's Blog - - - - - - - - - - - - - - - - - - - - - - - - - -
            -
            - -
            -
            - - - - - - -
            -
            - 2015 -
            -
            - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
            - - -
            - - - -
            -
            - -
            - -
            -
            -
            - - - - - - - - - - - - -
            - - \ No newline at end of file diff --git a/index.html b/index.html index fd22727..f695886 100644 --- a/index.html +++ b/index.html @@ -94,7 +94,7 @@

            -

            Swift3.0学习笔记

            +

            总结一些 Swift3.0学习笔记

            Read More From 4af8e8fee5bb92d5deb8c55b7c94ca2328714e44 Mon Sep 17 00:00:00 2001 From: CoderShmily Date: Tue, 4 Apr 2017 10:42:14 +0800 Subject: [PATCH 009/148] Customize commit message --- categories/iOS/index.html | 310 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 310 insertions(+) create mode 100644 categories/iOS/index.html diff --git a/categories/iOS/index.html b/categories/iOS/index.html new file mode 100644 index 0000000..66bc9e3 --- /dev/null +++ b/categories/iOS/index.html @@ -0,0 +1,310 @@ + + + + + + Category: iOS | CoderShmily's Blog + + + + + + + + + + + + + + + + + + + + + + + + + +

            +
            + +
            +
            + + + + + + +
            +
            + 2015 +
            +
            + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
            + + +
            + + + +
            +
            + +
            + +
            +
            +
            + + + + + + + + + + + + +
            + + \ No newline at end of file From 64b2ba2d8e43597741bace94902873468f3235e7 Mon Sep 17 00:00:00 2001 From: CoderShmily Date: Tue, 4 Apr 2017 10:43:31 +0800 Subject: [PATCH 010/148] Customize commit message --- categories/iOS/index.html | 310 -------------------------------------- 1 file changed, 310 deletions(-) delete mode 100644 categories/iOS/index.html diff --git a/categories/iOS/index.html b/categories/iOS/index.html deleted file mode 100644 index 66bc9e3..0000000 --- a/categories/iOS/index.html +++ /dev/null @@ -1,310 +0,0 @@ - - - - - - Category: iOS | CoderShmily's Blog - - - - - - - - - - - - - - - - - - - - - - - - - -
            -
            - -
            -
            - - - - - - -
            -
            - 2015 -
            -
            - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
            - - -
            - - - -
            -
            - -
            - -
            -
            -
            - - - - - - - - - - - - -
            - - \ No newline at end of file From e29623ea3fcd3382d425840fb802b826ab5fa0df Mon Sep 17 00:00:00 2001 From: CoderShmily Date: Tue, 4 Apr 2017 10:47:39 +0800 Subject: [PATCH 011/148] Customize commit message --- categories/iOS/index.html | 310 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 310 insertions(+) create mode 100644 categories/iOS/index.html diff --git a/categories/iOS/index.html b/categories/iOS/index.html new file mode 100644 index 0000000..66bc9e3 --- /dev/null +++ b/categories/iOS/index.html @@ -0,0 +1,310 @@ + + + + + + Category: iOS | CoderShmily's Blog + + + + + + + + + + + + + + + + + + + + + + + + + +
            +
            + +
            +
            + + + + + + +
            +
            + 2015 +
            +
            + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
            + + +
            + + + +
            +
            + +
            + +
            +
            +
            + + + + + + + + + + + + +
            + + \ No newline at end of file From 9fc8e629c0f9eaa4dc975bee2ea22019fff908d1 Mon Sep 17 00:00:00 2001 From: CoderShmily Date: Tue, 4 Apr 2017 10:57:16 +0800 Subject: [PATCH 012/148] Customize commit message --- 2015/05/01/2015-05-01-Swift-ru-men/index.html | 5 +- 2015/05/02/2015-05-02-singleton/index.html | 5 +- .../2015-05-03-kvc-he-kvoshen-ru/index.html | 5 +- .../index.html | 5 +- .../05/2015-05-05-runtime-gai-shu/index.html | 5 +- .../index.html | 5 +- .../index.html | 5 +- .../index.html | 5 +- .../2016-11-15-Swift3.0-jie-shao/index.html | 15 +- categories/iOS/index.html | 310 ------------------ css/style.css | 28 ++ 11 files changed, 60 insertions(+), 333 deletions(-) delete mode 100644 categories/iOS/index.html diff --git a/2015/05/01/2015-05-01-Swift-ru-men/index.html b/2015/05/01/2015-05-01-Swift-ru-men/index.html index a626034..de918b6 100644 --- a/2015/05/01/2015-05-01-Swift-ru-men/index.html +++ b/2015/05/01/2015-05-01-Swift-ru-men/index.html @@ -110,8 +110,9 @@

            - - + + +

            特色

            • 苹果宣称 Swift 的特点是:快速、现代、安全、互动,而且明显优于 Objective-C 语言
            • 可以使用现有的 CocoaCocoa Touch 框架
            • diff --git a/2015/05/02/2015-05-02-singleton/index.html b/2015/05/02/2015-05-02-singleton/index.html index 77196fa..343f7be 100644 --- a/2015/05/02/2015-05-02-singleton/index.html +++ b/2015/05/02/2015-05-02-singleton/index.html @@ -93,8 +93,9 @@

              - - + + +

              单例在整个工程中,就相当于一个全局变量,就是不论在哪里需要用到这个类的实例变量,都可以通过单例方法来取得,而且一旦你创建了一个单例类,不论你在多少个界面中初始化调用了这个单例方法取得对象,它们所有的对象都是指向的同一块内存存储空间(即单例类保证了该类的实力对象是唯一存在的一个).

              单例模式的作用

                diff --git a/2015/05/03/2015-05-03-kvc-he-kvoshen-ru/index.html b/2015/05/03/2015-05-03-kvc-he-kvoshen-ru/index.html index bf1fbb2..137a632 100644 --- a/2015/05/03/2015-05-03-kvc-he-kvoshen-ru/index.html +++ b/2015/05/03/2015-05-03-kvc-he-kvoshen-ru/index.html @@ -93,8 +93,9 @@

                - - + + +

                KVC 和 KVO深入

                KVC概述

                1.什么是KVC?

                KVC即NSKeyValueCoding,键/值编码,一个非正式的Protocol,以字符串的形式向对象发送消息,而不是通过调用存取方法,直接或通过实例变量访问的机制。

                diff --git a/2015/05/04/2015-05-04-runtime-dui-xiang-mo-xing/index.html b/2015/05/04/2015-05-04-runtime-dui-xiang-mo-xing/index.html index 3583749..cbe1d20 100644 --- a/2015/05/04/2015-05-04-runtime-dui-xiang-mo-xing/index.html +++ b/2015/05/04/2015-05-04-runtime-dui-xiang-mo-xing/index.html @@ -96,8 +96,9 @@

                - - + + +

                Objective-C语言是一门动态语言,它将很多静态语言在编译和链接时期做的事放到了运行时来处理。这种动态语言的优势在于:我们写代码时更具灵活性,如我们可以把消息转发给我们想要的对象,或者随意交换一个方法的实现等。

                这种特性意味着Objective-C不仅需要一个编译器,还需要一个运行时系统来执行编译的代码。对于Objective-C来说,这个运行时系统就像一个操作系统一样:它让所有的工作可以正常的运行。这个运行时系统即Objc Runtime。Objc Runtime其实是一个Runtime库,它基本上是用C和汇编写的,这个库使得C语言有了面向对象的能力。

                diff --git a/2015/05/05/2015-05-05-runtime-gai-shu/index.html b/2015/05/05/2015-05-05-runtime-gai-shu/index.html index 278857f..c26df52 100644 --- a/2015/05/05/2015-05-05-runtime-gai-shu/index.html +++ b/2015/05/05/2015-05-05-runtime-gai-shu/index.html @@ -93,8 +93,9 @@

                - - + + +

                Runtime常用方法和一些应用

                Runtime方法列表

                1
                2
                3
                4
                5
                6
                7
                8
                9
                10
                11
                12
                13
                14
                15
                16
                17
                18
                19
                20
                21
                22
                23
                24
                25
                26
                27
                28
                29
                30
                31
                32
                33
                34
                35
                36
                37
                38
                39
                40
                # class
                class_getInstanceMethod -> Method class_getInstanceMethod(Class cls, SEL name);// 返回给定类的指定的实例方法
                class_addMethod -> BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types);// 通过方法名SEL+原来的IMP实现给类添加新方法
                class_copyPropertyList -> objc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount) // 获取类的属性列表
                # method
                method_getTypeEncoding -> const char *method_getTypeEncoding(Method m);// Returns a string describing a method's parameter and return types.
                method_getImplementation -> IMP method_getImplementation(Method m);//获取Method中的IMP
                method_exchangeImplementations -> method_exchangeImplementations(Method m1, Method m2); //Returns a string describing a method's parameter and return types.
                method_setImplementation -> IMP method_setImplementation(Method m, IMP imp); // Sets the implementation of a method.
                # 关联对象
                objc_setAssociatedObject -> objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy);//Sets an associated value for a given object using a given key and association policy.
                objc_getAssociatedObject -> id objc_getAssociatedObject(id object, const void *key);// Returns the value associated with a given object for a given key.
                objc_removeAssociatedObjects -> objc_removeAssociatedObjects(id object);// 注意:Removes all associations for a given object.
                # 类
                object_isClass -> BOOL object_isClass(id obj);//Returns whether an object is a class object.
                object_getClass -> Class object_getClass(id obj);//Returns the class of an object.
                object_getClassName -> const char *object_getClassName(id obj);//Returns the class name of a given object.
                object_setClass -> Class object_setClass(id obj, Class cls);//Sets the class of an object.
                objc_getMetaClass -> Class objc_getMetaClass(const char *name);// 原类
                # 实例变量
                object_getIvar -> id object_getIvar(id obj, Ivar ivar);//Reads the value of an instance variable in an object.
                object_setIvar -> object_setIvar(id obj, Ivar ivar, id value);//Sets the value of an instance variable in an object.
                // Changes the value of an 实例变量 of a 实例
                object_getInstanceVariable -> Ivar object_getInstanceVariable(id obj, const char *name, void **outValue)
                object_setInstanceVariable -> Ivar object_setInstanceVariable(id obj, const char *name, void *value);
                # 属性
                property_getName -> const char *property_getName(objc_property_t property) // 传入上面的数组(指针)获取每个属性的名称
                property_getAttributes -> const char *property_getAttributes(objc_property_t property) // 返回属性的名称和@encode类型字符串
                # 发送消息
                objc_msgSend -> objc_msgSend(id obj, SEL name);
                diff --git a/2015/05/06/2015-05-06-objective-c-runtime-san-xiao-xi-chuan-di/index.html b/2015/05/06/2015-05-06-objective-c-runtime-san-xiao-xi-chuan-di/index.html index 1b37a9e..480da73 100644 --- a/2015/05/06/2015-05-06-objective-c-runtime-san-xiao-xi-chuan-di/index.html +++ b/2015/05/06/2015-05-06-objective-c-runtime-san-xiao-xi-chuan-di/index.html @@ -93,8 +93,9 @@

                - - + + +

                Objective-C Runtime的消息传递

                ###Objective-C – 消息传递
                Objective-C 扩展了 C 语言,并加入了面向对象特性和 Smalltalk 式的消息传递机制。而这个扩展的核心是一个用 C 和 编译语言 写的 Runtime 库。它是 Objective-C 面向对象和动态机制的基石.

                Objective-C 是一个动态语言,这意味着它不仅需要一个编译器,也需要一个运行时系统来动态得创建类和对象、进行消息传递和转发。理解 Objective-C 的 Runtime 机制可以帮我们更好的了解这个语言,适当的时候还能对语言进行扩展,从系统层面解决项目中的一些设计或技术问题。了解 Runtime ,要先了解它的核心 - 消息传递(Messaging)。

                diff --git a/2015/05/07/2015-05-07-objective-c-runtime-si-dong-tai-fang-fa-jue-yi-dynamic-method-resolution/index.html b/2015/05/07/2015-05-07-objective-c-runtime-si-dong-tai-fang-fa-jue-yi-dynamic-method-resolution/index.html index f0d35ab..16779e1 100644 --- a/2015/05/07/2015-05-07-objective-c-runtime-si-dong-tai-fang-fa-jue-yi-dynamic-method-resolution/index.html +++ b/2015/05/07/2015-05-07-objective-c-runtime-si-dong-tai-fang-fa-jue-yi-dynamic-method-resolution/index.html @@ -93,8 +93,9 @@

                - - + + +

                Objective-C Runtime之动态方法决议

                动态方法决议/动态方法解析(Dynamic Method Resolution)

                diff --git a/2015/05/15/2015-05-15-sdwebimageyuan-ma-jie-xi/index.html b/2015/05/15/2015-05-15-sdwebimageyuan-ma-jie-xi/index.html index caef481..54a432d 100644 --- a/2015/05/15/2015-05-15-sdwebimageyuan-ma-jie-xi/index.html +++ b/2015/05/15/2015-05-15-sdwebimageyuan-ma-jie-xi/index.html @@ -93,8 +93,9 @@

                - - + + +

                SDWebImage源码解析

                1
                2
                3
                4
                5
                6
                7
                8
                9
                10
                11
                12
                13
                14
                15
                16
                17
                18
                19
                20
                21
                22
                23
                24
                25
                26
                27
                28
                29
                30
                31
                32
                33
                34
                35
                36
                37
                38
                39
                40
                41
                42
                43
                44
                45
                46
                47
                48
                49
                50
                51
                52
                53
                54
                55
                56
                57
                58
                59
                60
                61
                62
                63
                64
                65
                66
                67
                68
                69
                70
                71
                72
                73
                74
                75
                76
                77
                78
                79
                80
                81
                82
                83
                84
                85
                86
                87
                88
                89
                90
                91
                92
                93
                94
                95
                96
                97
                98
                99
                100
                101
                102
                103
                104
                105
                106
                107
                108
                109
                110
                111
                112
                113
                114
                115
                116
                117
                118
                119
                120
                121
                122
                123
                124
                125
                126
                127
                128
                129
                130
                131
                132
                133
                134
                135
                136
                137
                138
                139
                140
                141
                142
                143
                144
                145
                146
                147
                148
                149
                150
                151
                152
                153
                154
                155
                156
                157
                158
                159
                160
                161
                162
                163
                164
                165
                166
                167
                168
                169
                170
                171
                172
                173
                174
                175
                176
                177
                178
                179
                180
                181
                182
                183
                184
                185
                186
                187
                188
                189
                190
                191
                192
                193
                194
                195
                196
                197
                198
                199
                200
                201
                202
                203
                204
                205
                206
                207
                208
                209
                210
                211
                212
                213
                214
                215
                216
                217
                218
                219
                220
                221
                222
                223
                224
                225
                226
                227
                228
                229
                230
                231
                232
                233
                234
                235
                236
                237
                238
                239
                240
                241
                242
                243
                244
                245
                246
                247
                248
                249
                250
                251
                252
                253
                254
                255
                256
                257
                258
                259
                260
                261
                262
                263
                264
                265
                266
                267
                268
                269
                270
                271
                272
                273
                274
                275
                276
                277
                278
                279
                280
                281
                282
                283
                284
                285
                286
                287
                288
                289
                290
                291
                292
                293
                294
                295
                296
                297
                298
                299
                300
                301
                302
                303
                304
                305
                306
                307
                308
                309
                310
                311
                312
                313
                314
                315
                316
                317
                318
                319
                320
                321
                322
                323
                324
                325
                326
                327
                328
                329
                330
                331
                332
                333
                334
                335
                336
                337
                338
                339
                340
                341
                342
                343
                344
                345
                346
                347
                348
                349
                350
                351
                352
                353
                354
                355
                356
                357
                358
                359
                360
                361
                362
                363
                364
                365
                366
                367
                368
                369
                370
                371
                372
                373
                374
                375
                376
                377
                378
                379
                380
                381
                382
                383
                /*
                * This file is part of the SDWebImage package.
                * (c) Olivier Poitrey <rs@dailymotion.com>
                *
                * For the full copyright and license information, please view the LICENSE
                * file that was distributed with this source code.
                */
                #import "SDWebImageCompat.h"
                #import "SDWebImageOperation.h"
                #import "SDWebImageDownloader.h"
                #import "SDImageCache.h"
                typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) {
                /**
                * By default, when a URL fail to be downloaded, the URL is blacklisted so the library won't keep trying.
                * This flag disable this blacklisting.
                */
                /**
                *默认情况下,如果一个url在下载的时候失败了,那么这个url会被加入黑名单并且library不会尝试再次下载,这个flag会阻止library把失败的url加入黑名单(简单来说如果选择了这个flag,那么即使某个url下载失败了,sdwebimage还是会尝试再次下载他.)
                */
                SDWebImageRetryFailed = 1 << 0,
                /**
                * By default, image downloads are started during UI interactions, this flags disable this feature,
                * leading to delayed download on UIScrollView deceleration for instance.
                */
                /**
                *默认情况下,图片会在交互发生的时候下载(例如你滑动tableview的时候),这个flag会禁止这个特性,导致的结果就是在scrollview减速的时候
                *才会开始下载(也就是你滑动的时候scrollview不下载,你手从屏幕上移走,scrollview开始减速的时候才会开始下载图片)
                */
                SDWebImageLowPriority = 1 << 1,
                /**
                * This flag disables on-disk caching
                */
                /*
                *这个flag禁止磁盘缓存,只有内存缓存
                */
                SDWebImageCacheMemoryOnly = 1 << 2,
                /**
                * This flag enables progressive download, the image is displayed progressively during download as a browser would do.
                * By default, the image is only displayed once completely downloaded.
                */
                /*
                *这个flag会在图片下载的时候就显示(就像你用浏览器浏览网页的时候那种图片下载,一截一截的显示(待确认))
                *
                */
                SDWebImageProgressiveDownload = 1 << 3,
                /**
                * Even if the image is cached, respect the HTTP response cache control, and refresh the image from remote location if needed.
                * The disk caching will be handled by NSURLCache instead of SDWebImage leading to slight performance degradation.
                * This option helps deal with images changing behind the same request URL, e.g. Facebook graph api profile pics.
                * If a cached image is refreshed, the completion block is called once with the cached image and again with the final image.
                *
                * Use this flag only if you can't make your URLs static with embeded cache busting parameter.
                */
                /*
                *这个选项的意思看的不是很懂,大意是即使一个图片缓存了,还是会重新请求.并且缓存侧略依据NSURLCache而不是SDWebImage.
                *
                */
                SDWebImageRefreshCached = 1 << 4,
                /**
                * In iOS 4+, continue the download of the image if the app goes to background. This is achieved by asking the system for
                * extra time in background to let the request finish. If the background task expires the operation will be cancelled.
                */
                /*
                *启动后台下载,加入你进入一个页面,有一张图片正在下载这时候你让app进入后台,图片还是会继续下载(这个估计要开backgroundfetch才有用)
                */
                SDWebImageContinueInBackground = 1 << 5,
                /**
                * Handles cookies stored in NSHTTPCookieStore by setting
                * NSMutableURLRequest.HTTPShouldHandleCookies = YES;
                */
                /*
                *可以控制存在NSHTTPCookieStore的cookies.(我没用过,等用过的人过来解释一下)
                */
                SDWebImageHandleCookies = 1 << 6,
                /**
                * Enable to allow untrusted SSL ceriticates.
                * Useful for testing purposes. Use with caution in production.
                */
                /*
                *允许不安全的SSL证书,在正式环境中慎用
                */
                SDWebImageAllowInvalidSSLCertificates = 1 << 7,
                /**
                * By default, image are loaded in the order they were queued. This flag move them to
                * the front of the queue and is loaded immediately instead of waiting for the current queue to be loaded (which
                * could take a while).
                */
                /*
                *默认情况下,image在装载的时候是按照他们在队列中的顺序装载的(就是先进先出).这个flag会把他们移动到队列的前端,并且立刻装载
                *而不是等到当前队列装载的时候再装载.
                */
                SDWebImageHighPriority = 1 << 8,
                /**
                * By default, placeholder images are loaded while the image is loading. This flag will delay the loading
                * of the placeholder image until after the image has finished loading.
                */
                /*
                *默认情况下,占位图会在图片下载的时候显示.这个flag开启会延迟占位图显示的时间,等到图片下载完成之后才会显示占位图.(等图片显示完了我干嘛还显示占位图?或许是我理解错了?)
                */
                SDWebImageDelayPlaceholder = 1 << 9,
                /**
                * We usually don't call transformDownloadedImage delegate method on animated images,
                * as most transformation code would mangle it.
                * Use this flag to transform them anyway.
                */
                /*
                *是否transform图片(没用过,还要再看,但是据我估计,是否是图片有可能方向不对需要调整方向,例如采用iPhone拍摄的照片如果不纠正方向,那么图片是向左旋转90度的.可能很多人不知道iPhone的摄像头并不是竖直的,而是向左偏了90度.具体请google.)
                */
                SDWebImageTransformAnimatedImage = 1 << 10,
                };
                typedef void(^SDWebImageCompletionBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL);
                typedef void(^SDWebImageCompletionWithFinishedBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL);
                typedef NSString *(^SDWebImageCacheKeyFilterBlock)(NSURL *url);
                @class SDWebImageManager;
                @protocol SDWebImageManagerDelegate <NSObject>
                @optional
                /**
                * Controls which image should be downloaded when the image is not found in the cache.
                *
                * @param imageManager The current `SDWebImageManager`
                * @param imageURL The url of the image to be downloaded
                *
                * @return Return NO to prevent the downloading of the image on cache misses. If not implemented, YES is implied.
                */
                /*
                *主要作用是当缓存里没有发现某张图片的缓存时,是否选择下载这张图片(默认是yes),可以选择no,那么sdwebimage在缓存中没有找到这张图片的时候不会选择下载
                */
                - (BOOL)imageManager:(SDWebImageManager *)imageManager shouldDownloadImageForURL:(NSURL *)imageURL;
                /**
                * Allows to transform the image immediately after it has been downloaded and just before to cache it on disk and memory.
                * NOTE: This method is called from a global queue in order to not to block the main thread.
                *
                * @param imageManager The current `SDWebImageManager`
                * @param image The image to transform
                * @param imageURL The url of the image to transform
                *
                * @return The transformed image object.
                */
                /**
                *在图片下载完成并且还没有加入磁盘缓存或者内存缓存的时候就transform这个图片.这个方法是在异步线程执行的,防治阻塞主线程.
                *至于为什么在异步执行很简单,对一张图片纠正方向(也就是transform)是很耗资源的,一张2M大小的图片纠正方向你可以用instrument测试一下耗时.
                *很恐怖
                */
                - (UIImage *)imageManager:(SDWebImageManager *)imageManager transformDownloadedImage:(UIImage *)image withURL:(NSURL *)imageURL;
                @end
                /**
                * The SDWebImageManager is the class behind the UIImageView+WebCache category and likes.
                * It ties the asynchronous downloader (SDWebImageDownloader) with the image cache store (SDImageCache).
                * You can use this class directly to benefit from web image downloading with caching in another context than
                * a UIView.
                *
                * Here is a simple example of how to use SDWebImageManager:
                *
                * @code
                SDWebImageManager *manager = [SDWebImageManager sharedManager];
                [manager downloadImageWithURL:imageURL
                options:0
                progress:nil
                completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
                if (image) {
                // do something with image
                }
                }];
                * @endcode
                */
                /*
                *这一段是阐述SDWebImageManager是干嘛的.其实UIImageView+WebCache这个category背后执行操作的就是这个SDWebImageManager.他会绑定一个下载器也就是SDWebImageDownloader和一个缓存SDImageCache.后面的大意应该是讲你可以直接使用一个其他上下文环境的SDWebImageManager,而不是仅仅限于一个UIView.
                */
                @interface SDWebImageManager : NSObject
                @property (weak, nonatomic) id <SDWebImageManagerDelegate> delegate;
                /**
                *如同上文所说,一个SDWebImageManager会绑定一个imageCache和一个下载器.
                */
                @property (strong, nonatomic, readonly) SDImageCache *imageCache;
                @property (strong, nonatomic, readonly) SDWebImageDownloader *imageDownloader;
                /**
                * The cache filter is a block used each time SDWebImageManager need to convert an URL into a cache key. This can
                * be used to remove dynamic part of an image URL.
                *
                * The following example sets a filter in the application delegate that will remove any query-string from the
                * URL before to use it as a cache key:
                *
                * @code
                [[SDWebImageManager sharedManager] setCacheKeyFilter:^(NSURL *url) {
                url = [[NSURL alloc] initWithScheme:url.scheme host:url.host path:url.path];
                return [url absoluteString];
                }];
                * @endcode
                */
                /*
                * 这个cacheKeyFilter是干嘛的呢?很简单.1他是一个block.2.这个block的作用就是生成一个image的key.因为sdwebimage的缓存原理你可以当成是一个字典,每一个字典的value就是一张image,那么这个value对应的key是什么呢?就是cacheKeyFilter根据某个规则对这个图片的url做一些操作生成的.上面的示例就显示了怎么利用这个block把image的url重新组合生成一个key.以后当sdwebimage检测到你
                */
                @property (nonatomic, copy) SDWebImageCacheKeyFilterBlock cacheKeyFilter;
                /**
                * Returns global SDWebImageManager instance.
                *
                * @return SDWebImageManager shared instance
                */
                /*
                *这个不用我解释了吧,生成一个SDWebImagemanager的单例.
                */
                + (SDWebImageManager *)sharedManager;
                /**
                * Downloads the image at the given URL if not present in cache or return the cached version otherwise.
                * 从给定的URL中下载一个之前没有被缓存的Image.
                *
                * @param url The URL to the image
                * @param options A mask to specify options to use for this request
                * @param progressBlock A block called while image is downloading
                * @param completedBlock A block called when operation has been completed.
                *
                * This parameter is required.
                *
                * This block has no return value and takes the requested UIImage as first parameter.
                * In case of error the image parameter is nil and the second parameter may contain an NSError.
                *
                * The third parameter is an `SDImageCacheType` enum indicating if the image was retrived from the local cache
                * or from the memory cache or from the network.
                *
                * The last parameter is set to NO when the SDWebImageProgressiveDownload option is used and the image is
                * downloading. This block is thus called repetidly with a partial image. When image is fully downloaded, the
                * block is called a last time with the full image and the last parameter set to YES.
                *
                * @return Returns an NSObject conforming to SDWebImageOperation. Should be an instance of SDWebImageDownloaderOperation
                */
                /*
                * 这个方法主要就是SDWebImage下载图片的方法了.
                * 第一个参数是必须要的,就是image的url
                * 第二个参数就是我们上面的Options,你可以定制化各种各样的操作.详情参上.
                * 第三个参数是一个回调block,用于图片在下载过程中的回调.(英文注释应该是有问题的.)
                * 第四个参数是一个下载完成的回调.会在图片下载完成后回调.
                * 返回值是一个NSObject类,并且这个NSObject类是conforming一个协议这个协议叫做SDWebImageOperation,这个协议很简单,就是一个cancel掉operation的协议.
                */
                - (id <SDWebImageOperation>)downloadImageWithURL:(NSURL *)url
                options:(SDWebImageOptions)options
                progress:(SDWebImageDownloaderProgressBlock)progressBlock
                completed:(SDWebImageCompletionWithFinishedBlock)completedBlock;
                /**
                * Saves image to cache for given URL
                *
                * @param image The image to cache
                * @param url The URL to the image
                *
                */
                /*
                * 将图片存入cache的方法,类似于字典的setValue: forKey:
                */
                - (void)saveImageToCache:(UIImage *)image forURL:(NSURL *)url;
                /**
                * Cancel all current opreations
                */
                /*
                *取消掉当前所有的下载图片的operation
                */
                - (void)cancelAll;
                /**
                * Check one or more operations running
                */
                /*
                * check一下是否有一个或者多个operation正在执行(简单来说就是check是否有图片在下载)
                */
                - (BOOL)isRunning;
                /**
                * Check if image has already been cached
                *
                * @param url image url
                *
                * @return if the image was already cached
                */
                /*
                * 通过一个image的url是否已经存在,如果存在返回yes,否则返回no
                */
                - (BOOL)cachedImageExistsForURL:(NSURL *)url;
                /**
                * Check if image has already been cached on disk only
                *
                * @param url image url
                *
                * @return if the image was already cached (disk only)
                */
                /*
                * 检测一个image是否已经被缓存到磁盘(是否存且仅存在disk里).
                */
                - (BOOL)diskImageExistsForURL:(NSURL *)url;
                /**
                * Async check if image has already been cached
                *
                * @param url image url
                * @param completionBlock the block to be executed when the check is finished
                *
                * @note the completion block is always executed on the main queue
                */
                /*
                * 如果检测到图片已经被缓存,那么执行回调block.这个block会永远执行在主线程.也就是你可以在这个回调block里更新ui.
                */
                - (void)cachedImageExistsForURL:(NSURL *)url
                completion:(SDWebImageCheckCacheCompletionBlock)completionBlock;
                /**
                * Async check if image has already been cached on disk only
                *
                * @param url image url
                * @param completionBlock the block to be executed when the check is finished
                *
                * @note the completion block is always executed on the main queue
                */
                /*
                * 如果检测到图片已经被缓存在磁盘(存且仅存在disk),那么执行回调block.这个block会永远执行在主线程.也就是你可以在这个回调block里更新ui.
                */
                - (void)diskImageExistsForURL:(NSURL *)url
                completion:(SDWebImageCheckCacheCompletionBlock)completionBlock;
                /**
                *Return the cache key for a given URL
                */
                /*
                * 通过image的url返回image存在缓存里的key.有人会问了,为什么不直接把图片的url当做image的key来使用呢?而是非要对url做一些处理才能当做key.我的解释是,我也不太清楚.可能为了防止重复吧.
                */
                - (NSString *)cacheKeyForURL:(NSURL *)url;
                @end
                #pragma mark - Deprecated
                typedef void(^SDWebImageCompletedBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType) __deprecated_msg("Block type deprecated. Use `SDWebImageCompletionBlock`");
                typedef void(^SDWebImageCompletedWithFinishedBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished) __deprecated_msg("Block type deprecated. Use `SDWebImageCompletionWithFinishedBlock`");
                // 已被废弃
                @interface SDWebImageManager (Deprecated)
                /**
                * Downloads the image at the given URL if not present in cache or return the cached version otherwise.
                *
                * @deprecated This method has been deprecated. Use `downloadImageWithURL:options:progress:completed:`
                */
                - (id <SDWebImageOperation>)downloadWithURL:(NSURL *)url
                options:(SDWebImageOptions)options
                progress:(SDWebImageDownloaderProgressBlock)progressBlock
                completed:(SDWebImageCompletedWithFinishedBlock)completedBlock __deprecated_msg("Method deprecated. Use `downloadImageWithURL:options:progress:completed:`");
                @end
                1
                2
                3
                4
                5
                6
                7
                8
                9
                10
                11
                12
                13
                14
                15
                16
                17
                18
                19
                20
                21
                22
                23
                24
                25
                26
                27
                28
                29
                30
                31
                32
                33
                34
                35
                36
                37
                38
                39
                40
                41
                42
                43
                44
                45
                46
                47
                48
                49
                50
                51
                52
                53
                54
                55
                56
                57
                58
                59
                60
                61
                62
                63
                64
                65
                66
                67
                68
                69
                70
                71
                72
                73
                74
                75
                76
                77
                78
                79
                80
                81
                82
                83
                84
                85
                86
                87
                88
                89
                90
                91
                92
                93
                94
                95
                96
                97
                98
                99
                100
                101
                102
                103
                104
                105
                106
                107
                108
                109
                110
                111
                112
                113
                114
                115
                116
                117
                118
                119
                120
                121
                122
                123
                124
                125
                126
                127
                128
                129
                130
                131
                132
                133
                134
                135
                136
                137
                138
                139
                140
                141
                142
                143
                144
                145
                146
                147
                148
                149
                150
                151
                152
                153
                154
                155
                156
                157
                158
                159
                160
                161
                162
                163
                164
                165
                166
                167
                168
                169
                170
                171
                172
                173
                174
                175
                176
                177
                178
                179
                180
                181
                182
                183
                184
                185
                186
                187
                188
                189
                190
                191
                192
                193
                194
                195
                196
                197
                198
                199
                200
                201
                202
                203
                204
                205
                206
                207
                208
                209
                210
                211
                212
                213
                214
                215
                216
                217
                218
                219
                220
                221
                222
                223
                224
                225
                226
                227
                228
                229
                230
                231
                232
                233
                234
                235
                236
                237
                238
                239
                240
                241
                242
                243
                244
                245
                246
                247
                248
                249
                250
                251
                252
                253
                254
                255
                256
                257
                258
                259
                260
                261
                262
                263
                264
                265
                266
                267
                268
                269
                270
                271
                272
                273
                274
                275
                276
                277
                278
                279
                280
                281
                282
                283
                284
                285
                286
                287
                288
                289
                290
                291
                292
                293
                294
                295
                296
                297
                298
                299
                300
                301
                302
                303
                304
                305
                306
                307
                308
                309
                310
                311
                312
                313
                314
                315
                316
                317
                318
                319
                320
                321
                322
                323
                324
                325
                326
                327
                328
                329
                330
                331
                332
                333
                334
                335
                336
                337
                338
                339
                340
                341
                342
                343
                344
                345
                346
                347
                348
                349
                350
                351
                352
                353
                354
                355
                356
                357
                358
                359
                360
                361
                362
                363
                364
                365
                366
                367
                368
                369
                370
                371
                372
                373
                374
                375
                376
                377
                378
                379
                380
                381
                382
                383
                384
                385
                386
                387
                388
                389
                390
                #import <Foundation/Foundation.h>
                /*
                * This file is part of the SDWebImage package.
                *
                * For the full copyright and license information, please view the LICENSE
                * file that was distributed with this source code.
                */
                #import "SDWebImageManager.h"
                #import <objc/message.h>
                // 内部类.
                @interface SDWebImageCombinedOperation : NSObject <SDWebImageOperation>
                @property (assign, nonatomic, getter = isCancelled) BOOL cancelled;
                @property (copy, nonatomic) SDWebImageNoParamsBlock cancelBlock;
                @property (strong, nonatomic) NSOperation *cacheOperation;
                @end
                @interface SDWebImageManager ()
                @property (strong, nonatomic, readwrite) SDImageCache *imageCache;
                @property (strong, nonatomic, readwrite) SDWebImageDownloader *imageDownloader;
                @property (strong, nonatomic) NSMutableSet *failedURLs;
                @property (strong, nonatomic) NSMutableArray *runningOperations;
                @end
                @implementation SDWebImageManager
                // 利用disptach_once 特性生成一个单例,用烂了的方法.不赘述.
                + (id)sharedManager {
                static dispatch_once_t once;
                static id instance;
                dispatch_once(&once, ^{
                instance = [self new];
                });
                return instance;
                }
                // 初始化方法.
                // 1.获得一个SDImageCache的单例.2.获取一个SDWebImageDownloader的单例.3.新建一个MutableSet来存储下载失败的url.
                // 4.新建一个用来存储下载operation的可变数组.
                // 为什么不用MutableArray储存下载失败的URL?
                // 因为NSSet类有一个特性,就是Hash.实际上NSSet是一个哈希表,哈希表比数组优秀的地方是什么呢?就是查找速度快.查找同样一个元素,哈希表只需要通过key
                // 即可取到,而数组至少需要遍历依次.因为SDWebImage里有关失败URL的业务需求是,一个失败的URL只需要储存一次.这样的话Set自然比Array更合适.
                - (id)init {
                if ((self = [super init])) {
                _imageCache = [self createCache];
                _imageDownloader = [SDWebImageDownloader sharedDownloader];
                _failedURLs = [NSMutableSet new];
                _runningOperations = [NSMutableArray new];
                }
                return self;
                }
                // 获取一个cache的单例
                - (SDImageCache *)createCache {
                return [SDImageCache sharedImageCache];
                }
                // 利用Image的URL生成一个缓存时需要的key.
                // 这里有两种情况,第一种是如果检测到cacheKeyFilter不为空时,利用cacheKeyFilter来处理URL生成一个key.
                // 如果为空,那么直接返回URL的string内容,当做key.
                - (NSString *)cacheKeyForURL:(NSURL *)url {
                if (self.cacheKeyFilter) {
                return self.cacheKeyFilter(url);
                }
                else {
                return [url absoluteString];
                }
                }
                // 检测一张图片是否已被缓存.
                // 首先检测内存缓存是否存在这张图片,如果已有,直接返回yes.
                // 如果内存缓存里没有这张图片,那么调用diskImageExistsWithKey这个方法去硬盘缓存里找
                - (BOOL)cachedImageExistsForURL:(NSURL *)url {
                NSString *key = [self cacheKeyForURL:url];
                if ([self.imageCache imageFromMemoryCacheForKey:key] != nil) return YES;
                return [self.imageCache diskImageExistsWithKey:key];
                }
                // 检测硬盘里是否缓存了图片
                - (BOOL)diskImageExistsForURL:(NSURL *)url {
                NSString *key = [self cacheKeyForURL:url];
                return [self.imageCache diskImageExistsWithKey:key];
                }
                // 首先生成一个用来cache 住Image的key(利用key的url生成)
                // 然后检测内存缓存里是否已经有这张图片
                // 如果已经被缓存,那么再主线程里回调block
                // 如果没有检测到,那么调用diskImageExistsWithKey,这个方法会在异步线程里,将图片存到硬盘,当然在存图之前也会检测是否已在硬盘缓存图片.
                - (void)cachedImageExistsForURL:(NSURL *)url
                completion:(SDWebImageCheckCacheCompletionBlock)completionBlock {
                NSString *key = [self cacheKeyForURL:url];
                BOOL isInMemoryCache = ([self.imageCache imageFromMemoryCacheForKey:key] != nil);
                if (isInMemoryCache) {
                // making sure we call the completion block on the main queue
                dispatch_async(dispatch_get_main_queue(), ^{
                if (completionBlock) {
                completionBlock(YES);
                }
                });
                return;
                }
                [self.imageCache diskImageExistsWithKey:key completion:^(BOOL isInDiskCache) {
                // the completion block of checkDiskCacheForImageWithKey:completion: is always called on the main queue, no need to further dispatch
                if (completionBlock) {
                completionBlock(isInDiskCache);
                }
                }];
                }
                //将图片存入硬盘
                - (void)diskImageExistsForURL:(NSURL *)url
                completion:(SDWebImageCheckCacheCompletionBlock)completionBlock {
                NSString *key = [self cacheKeyForURL:url];
                [self.imageCache diskImageExistsWithKey:key completion:^(BOOL isInDiskCache) {
                // the completion block of checkDiskCacheForImageWithKey:completion: is always called on the main queue, no need to further dispatch
                if (completionBlock) {
                completionBlock(isInDiskCache);
                }
                }];
                }
                // 通过url建立一个operation用来下载图片.
                - (id <SDWebImageOperation>)downloadImageWithURL:(NSURL *)url
                options:(SDWebImageOptions)options
                progress:(SDWebImageDownloaderProgressBlock)progressBlock
                completed:(SDWebImageCompletionWithFinishedBlock)completedBlock {
                // Invoking this method without a completedBlock is pointless
                NSAssert(completedBlock != nil, @"If you mean to prefetch the image, use -[SDWebImagePrefetcher prefetchURLs] instead");
                // Very common mistake is to send the URL using NSString object instead of NSURL. For some strange reason, XCode won't
                // throw any warning for this type mismatch. Here we failsafe this error by allowing URLs to be passed as NSString.
                if ([url isKindOfClass:NSString.class]) {
                url = [NSURL URLWithString:(NSString *)url];
                }
                // Prevents app crashing on argument type error like sending NSNull instead of NSURL
                if (![url isKindOfClass:NSURL.class]) {
                url = nil;
                }
                __block SDWebImageCombinedOperation *operation = [SDWebImageCombinedOperation new];
                __weak SDWebImageCombinedOperation *weakOperation = operation;
                BOOL isFailedUrl = NO;
                // 创建一个互斥锁防止现在有别的线程修改failedURLs.
                // 判断这个url是否是fail过的.如果url failed过的那么isFailedUrl就是true
                @synchronized (self.failedURLs) {
                isFailedUrl = [self.failedURLs containsObject:url];
                }
                // 如果url不存在那么直接返回一个block,如果url存在.那么继续进行判断.
                // options与SDWebImageRetryFailed这个option进行按位与操作.判断用户的options里是否有retry这个option.
                // 如果用户的options里没有retry这个选项并且isFaileUrl 是true.那么就回调一个error的block.
                if (!url || (!(options & SDWebImageRetryFailed) && isFailedUrl)) {
                dispatch_main_sync_safe(^{
                NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorFileDoesNotExist userInfo:nil];
                completedBlock(nil, error, SDImageCacheTypeNone, YES, url);
                });
                return operation;
                }
                // 创建一个互斥锁防止现在有别的线程修改runningOperations.
                @synchronized (self.runningOperations) {
                [self.runningOperations addObject:operation];
                }
                NSString *key = [self cacheKeyForURL:url];
                // cacheOperation应该是一个用来下载图片并且缓存的operation
                operation.cacheOperation = [self.imageCache queryDiskCacheForKey:key done:^(UIImage *image, SDImageCacheType cacheType) {
                // 判断operation这时候有没有执行cancel操作,如果cancel掉了就把这个operation从我们的operation数组里remove掉然后return
                if (operation.isCancelled) {
                @synchronized (self.runningOperations) {
                [self.runningOperations removeObject:operation];
                }
                return;
                }
                if ((!image || options & SDWebImageRefreshCached) && (![self.delegate respondsToSelector:@selector(imageManager:shouldDownloadImageForURL:)] || [self.delegate imageManager:self shouldDownloadImageForURL:url])) {
                if (image && options & SDWebImageRefreshCached) {
                dispatch_main_sync_safe(^{
                // If image was found in the cache bug SDWebImageRefreshCached is provided, notify about the cached image
                // AND try to re-download it in order to let a chance to NSURLCache to refresh it from server.
                completedBlock(image, nil, cacheType, YES, url);
                });
                }
                // download if no image or requested to refresh anyway, and download allowed by delegate
                // 下面都是判断我们的options里包含哪些SDWebImageOptions,然后给我们的downloaderOptions相应的添加对应的SDWebImageDownloaderOptions. downloaderOptions |= SDWebImageDownloaderLowPriority这种表达式的意思等同于
                // downloaderOptions = downloaderOptions | SDWebImageDownloaderLowPriority
                SDWebImageDownloaderOptions downloaderOptions = 0;
                if (options & SDWebImageLowPriority) downloaderOptions |= SDWebImageDownloaderLowPriority;
                if (options & SDWebImageProgressiveDownload) downloaderOptions |= SDWebImageDownloaderProgressiveDownload;
                if (options & SDWebImageRefreshCached) downloaderOptions |= SDWebImageDownloaderUseNSURLCache;
                if (options & SDWebImageContinueInBackground) downloaderOptions |= SDWebImageDownloaderContinueInBackground;
                if (options & SDWebImageHandleCookies) downloaderOptions |= SDWebImageDownloaderHandleCookies;
                if (options & SDWebImageAllowInvalidSSLCertificates) downloaderOptions |= SDWebImageDownloaderAllowInvalidSSLCertificates;
                if (options & SDWebImageHighPriority) downloaderOptions |= SDWebImageDownloaderHighPriority;
                if (image && options & SDWebImageRefreshCached) {
                // force progressive off if image already cached but forced refreshing
                downloaderOptions &= ~SDWebImageDownloaderProgressiveDownload;
                // ignore image read from NSURLCache if image if cached but force refreshing
                downloaderOptions |= SDWebImageDownloaderIgnoreCachedResponse;
                }
                // 调用imageDownloader去下载image并且返回执行这个request的download的operation
                id <SDWebImageOperation> subOperation = [self.imageDownloader downloadImageWithURL:url options:downloaderOptions progress:progressBlock completed:^(UIImage *downloadedImage, NSData *data, NSError *error, BOOL finished) {
                if (weakOperation.isCancelled) {
                // Do nothing if the operation was cancelled
                // See #699 for more details
                // if we would call the completedBlock, there could be a race condition between this block and another completedBlock for the same object, so if this one is called second, we will overwrite the new data
                }
                else if (error) {
                dispatch_main_sync_safe(^{
                if (!weakOperation.isCancelled) {
                completedBlock(nil, error, SDImageCacheTypeNone, finished, url);
                }
                });
                if (error.code != NSURLErrorNotConnectedToInternet && error.code != NSURLErrorCancelled && error.code != NSURLErrorTimedOut) {
                @synchronized (self.failedURLs) {
                [self.failedURLs addObject:url];
                }
                }
                }
                else {
                if ((options & SDWebImageRetryFailed)) {
                @synchronized (self.failedURLs) {
                [self.failedURLs removeObject:url];
                }
                }
                BOOL cacheOnDisk = !(options & SDWebImageCacheMemoryOnly);
                if (options & SDWebImageRefreshCached && image && !downloadedImage) {
                // Image refresh hit the NSURLCache cache, do not call the completion block
                }
                else if (downloadedImage && (!downloadedImage.images || (options & SDWebImageTransformAnimatedImage)) && [self.delegate respondsToSelector:@selector(imageManager:transformDownloadedImage:withURL:)]) {
                dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
                UIImage *transformedImage = [self.delegate imageManager:self transformDownloadedImage:downloadedImage withURL:url];
                if (transformedImage && finished) {
                BOOL imageWasTransformed = ![transformedImage isEqual:downloadedImage];
                [self.imageCache storeImage:transformedImage recalculateFromImage:imageWasTransformed imageData:data forKey:key toDisk:cacheOnDisk];
                }
                dispatch_main_sync_safe(^{
                if (!weakOperation.isCancelled) {
                completedBlock(transformedImage, nil, SDImageCacheTypeNone, finished, url);
                }
                });
                });
                }
                else {
                if (downloadedImage && finished) {
                [self.imageCache storeImage:downloadedImage recalculateFromImage:NO imageData:data forKey:key toDisk:cacheOnDisk];
                }
                dispatch_main_sync_safe(^{
                if (!weakOperation.isCancelled) {
                completedBlock(downloadedImage, nil, SDImageCacheTypeNone, finished, url);
                }
                });
                }
                }
                if (finished) {
                @synchronized (self.runningOperations) {
                [self.runningOperations removeObject:operation];
                }
                }
                }];
                operation.cancelBlock = ^{
                [subOperation cancel];
                @synchronized (self.runningOperations) {
                [self.runningOperations removeObject:weakOperation];
                }
                };
                }
                else if (image) {
                dispatch_main_sync_safe(^{
                if (!weakOperation.isCancelled) {
                completedBlock(image, nil, cacheType, YES, url);
                }
                });
                @synchronized (self.runningOperations) {
                [self.runningOperations removeObject:operation];
                }
                }
                else {
                // Image not in cache and download disallowed by delegate
                dispatch_main_sync_safe(^{
                if (!weakOperation.isCancelled) {
                completedBlock(nil, nil, SDImageCacheTypeNone, YES, url);
                }
                });
                @synchronized (self.runningOperations) {
                [self.runningOperations removeObject:operation];
                }
                }
                }];
                return operation;
                }
                - (void)saveImageToCache:(UIImage *)image forURL:(NSURL *)url {
                if (image && url) {
                NSString *key = [self cacheKeyForURL:url];
                [self.imageCache storeImage:image forKey:key toDisk:YES];
                }
                }
                // cancel掉所有正在执行的operation
                - (void)cancelAll {
                @synchronized (self.runningOperations) {
                NSArray *copiedOperations = [self.runningOperations copy];
                [copiedOperations makeObjectsPerformSelector:@selector(cancel)];
                [self.runningOperations removeObjectsInArray:copiedOperations];
                }
                }
                // 判断是否有正在运行的operation
                - (BOOL)isRunning {
                return self.runningOperations.count > 0;
                }
                @end
                @implementation SDWebImageCombinedOperation
                - (void)setCancelBlock:(SDWebImageNoParamsBlock)cancelBlock {
                // check if the operation is already cancelled, then we just call the cancelBlock
                if (self.isCancelled) {
                if (cancelBlock) {
                cancelBlock();
                }
                _cancelBlock = nil; // don't forget to nil the cancelBlock, otherwise we will get crashes
                } else {
                _cancelBlock = [cancelBlock copy];
                }
                }
                - (void)cancel {
                self.cancelled = YES;
                if (self.cacheOperation) {
                [self.cacheOperation cancel];
                self.cacheOperation = nil;
                }
                if (self.cancelBlock) {
                self.cancelBlock();
                // TODO: this is a temporary fix to #809.
                // Until we can figure the exact cause of the crash, going with the ivar instead of the setter
                // self.cancelBlock = nil;
                _cancelBlock = nil;
                }
                }
                @end
                @implementation SDWebImageManager (Deprecated)
                // deprecated method, uses the non deprecated method
                // adapter for the completion block
                - (id <SDWebImageOperation>)downloadWithURL:(NSURL *)url options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletedWithFinishedBlock)completedBlock {
                return [self downloadImageWithURL:url
                options:options
                progress:progressBlock
                completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
                if (completedBlock) {
                completedBlock(image, error, cacheType, finished);
                }
                }];
                }
                @end
                diff --git a/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html b/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html index 6c37a07..6684060 100644 --- a/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html +++ b/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html @@ -93,13 +93,14 @@

                - - -
                - 文章目录 -
                1. 1. Any AnyObject NSObject
                2. 2. 条件判断
                  1. 2.1. 1. if的使用
                  2. 2.2. 2. 三目运算符
                  3. 2.3. 3. guard
                  4. 2.4. 4. switch的用法
                    1. 2.4.1. 1. switch与基本数据
                    2. 2.4.2. 2. switch与区间
                    3. 2.4.3. 3. switch与枚举
                    4. 2.4.4. 4. switch与元组
                3. 3. 循环
                  1. 3.1. 1. for循环
                  2. 3.2. 2. while循环
                    1. 3.2.1. 1. while循环
                    2. 3.2.2. 2. repeat~while循环
                4. 4. 字符串处理
                5. 5. 数组
                6. 6. 字典
                7. 7. 元组
                8. 8. 可选类型
                  1. 8.1. 2. 可选类型 (才能赋值为nil)
                  2. 8.2. 3. 四种方式使用可选类型的值
                    1. 8.2.1. 1. 判断 + 直接解包
                    2. 8.2.2. 2. 可选绑定
                    3. 8.2.3. 3. guard守护
                    4. 8.2.4. 4. 空合运算符
                9. 9. 类型转换
                10. 10. 函数
                  1. 10.1. 1. 函数的四种类型
                    1. 10.1.1. 1. 无参数,无返回值
                    2. 10.1.2. 2. 无参数,有返回值
                    3. 10.1.3. 3. 有参数,无返回值
                    4. 10.1.4. 4. 有参数,有返回值
                  2. 10.2. 函数其他注意
                    1. 10.2.1. 1. 省略第一个外部参数的名字
                    2. 10.2.2. 2. 设置参数默认值
                    3. 10.2.3. 3. 设置可变参数
                    4. 10.2.4. 4. 修改内部参数的值
                    5. 10.2.5. 5. 设置参数为地址传递
                    6. 10.2.6. 6. 函数嵌套
                    7. 10.2.7. 7. 函数的类型
                    8. 10.2.8. 8. 区分不同函数
                11. 11. 枚举
                12. 12. 结构体
                  1. 12.1. 1. 结构体基本使用
                  2. 12.2. 2. 结构体扩充构造函数
                13. 13.
                  1. 13.1. 1. 类的声明初始化
                  2. 13.2. 2. 类的属性和方法
                  3. 13.3. 3. 类的继承之KVC使用
                  4. 13.4. 4. 类的循环引用
                  5. 13.5. 5. 结构体和类的区别
                  6. 13.6. 6. OC中使用Swift的类和结构体
                  7. 13.7. 7. Swift中调用OC
                14. 14. 三大特性
                15. 15. 可选链
                16. 16. 协议
                  1. 16.1. 1.协议的基本使用
                  2. 16.2. 2. 协议中使用代理
                  3. 16.3. 3. 协议中的可选
                17. 17. 闭包
                  1. 17.1. 1.闭包的基本使用
                  2. 17.2. 2. 尾随闭包和逃逸闭包
                  3. 17.3. 3. 闭包的循环引用(4中解决方式)
                18. 18. 懒加载
                19. 19. 注释
                20. 20. 访问权限
                  1. 20.1. 访问修饰符
                21. 21. 方法抛出异常
                22. 22. Playground
                  1. 22.1. 1. Playground异步执行
                  2. 22.2. 2. MarkDown语法
                  3. 22.3. 3. TimeLine使用
                  4. 22.4. 4. Playground的Sources目录
                -
                - + + +
                + 文章目录 +
                1. 1. Any AnyObject NSObject
                2. 2. 条件判断
                  1. 2.1. 1. if的使用
                  2. 2.2. 2. 三目运算符
                  3. 2.3. 3. guard
                  4. 2.4. 4. switch的用法
                    1. 2.4.1. 1. switch与基本数据
                    2. 2.4.2. 2. switch与区间
                    3. 2.4.3. 3. switch与枚举
                    4. 2.4.4. 4. switch与元组
                3. 3. 循环
                  1. 3.1. 1. for循环
                  2. 3.2. 2. while循环
                    1. 3.2.1. 1. while循环
                    2. 3.2.2. 2. repeat~while循环
                4. 4. 字符串处理
                5. 5. 数组
                6. 6. 字典
                7. 7. 元组
                8. 8. 可选类型
                  1. 8.1. 2. 可选类型 (才能赋值为nil)
                  2. 8.2. 3. 四种方式使用可选类型的值
                    1. 8.2.1. 1. 判断 + 直接解包
                    2. 8.2.2. 2. 可选绑定
                    3. 8.2.3. 3. guard守护
                    4. 8.2.4. 4. 空合运算符
                9. 9. 类型转换
                10. 10. 函数
                  1. 10.1. 1. 函数的四种类型
                    1. 10.1.1. 1. 无参数,无返回值
                    2. 10.1.2. 2. 无参数,有返回值
                    3. 10.1.3. 3. 有参数,无返回值
                    4. 10.1.4. 4. 有参数,有返回值
                  2. 10.2. 函数其他注意
                    1. 10.2.1. 1. 省略第一个外部参数的名字
                    2. 10.2.2. 2. 设置参数默认值
                    3. 10.2.3. 3. 设置可变参数
                    4. 10.2.4. 4. 修改内部参数的值
                    5. 10.2.5. 5. 设置参数为地址传递
                    6. 10.2.6. 6. 函数嵌套
                    7. 10.2.7. 7. 函数的类型
                    8. 10.2.8. 8. 区分不同函数
                11. 11. 枚举
                12. 12. 结构体
                  1. 12.1. 1. 结构体基本使用
                  2. 12.2. 2. 结构体扩充构造函数
                13. 13.
                  1. 13.1. 1. 类的声明初始化
                  2. 13.2. 2. 类的属性和方法
                  3. 13.3. 3. 类的继承之KVC使用
                  4. 13.4. 4. 类的循环引用
                  5. 13.5. 5. 结构体和类的区别
                  6. 13.6. 6. OC中使用Swift的类和结构体
                  7. 13.7. 7. Swift中调用OC
                14. 14. 三大特性
                15. 15. 可选链
                16. 16. 协议
                  1. 16.1. 1.协议的基本使用
                  2. 16.2. 2. 协议中使用代理
                  3. 16.3. 3. 协议中的可选
                17. 17. 闭包
                  1. 17.1. 1.闭包的基本使用
                  2. 17.2. 2. 尾随闭包和逃逸闭包
                  3. 17.3. 3. 闭包的循环引用(4中解决方式)
                18. 18. 懒加载
                19. 19. 注释
                20. 20. 访问权限
                  1. 20.1. 访问修饰符
                21. 21. 方法抛出异常
                22. 22. Playground
                  1. 22.1. 1. Playground异步执行
                  2. 22.2. 2. MarkDown语法
                  3. 22.3. 3. TimeLine使用
                  4. 22.4. 4. Playground的Sources目录
                +
                + +

                总结一些 Swift3.0学习笔记

                Any AnyObject NSObject

                Int Double String struct都是结构体

                diff --git a/categories/iOS/index.html b/categories/iOS/index.html deleted file mode 100644 index 66bc9e3..0000000 --- a/categories/iOS/index.html +++ /dev/null @@ -1,310 +0,0 @@ - - - - - - Category: iOS | CoderShmily's Blog - - - - - - - - - - - - - - - - - - - - - - - - - -
                -
                - -
                -
                - - - - - - -
                -
                - 2015 -
                -
                - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                - - -
                - - - -
                -
                - -
                - -
                -
                -
                - - - - - - - - - - - - -
                - - \ No newline at end of file diff --git a/css/style.css b/css/style.css index dd01e88..e260d28 100644 --- a/css/style.css +++ b/css/style.css @@ -9,6 +9,34 @@ body:after { body:after { clear: both; } +.toc-article { + background: #eee; + padding: 1em; + position: relative; + left: 2em; +} +.toc-article .toc-title { + padding-bottom: 0.8em; + font-weight: bold; +} +#toc { + line-height: 1.1em; + font-size: 0.8em; + float: right; +} +#toc .toc { + padding: 0; +} +#toc li, +.toc li { + list-style-type: none; +} +#toc ol { + margin: 0; +} +#toc .toc-child { + padding-left: 1.5em; +} html, body, div, From a89d923d02ba44b262c6e410d70f16cc75deac7c Mon Sep 17 00:00:00 2001 From: CoderShmily Date: Tue, 4 Apr 2017 11:00:57 +0800 Subject: [PATCH 013/148] Customize commit message --- categories/iOS/index.html | 310 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 310 insertions(+) create mode 100644 categories/iOS/index.html diff --git a/categories/iOS/index.html b/categories/iOS/index.html new file mode 100644 index 0000000..66bc9e3 --- /dev/null +++ b/categories/iOS/index.html @@ -0,0 +1,310 @@ + + + + + + Category: iOS | CoderShmily's Blog + + + + + + + + + + + + + + + + + + + + + + + + + +
                +
                + +
                +
                + + + + + + +
                +
                + 2015 +
                +
                + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                + + +
                + + + +
                +
                + +
                + +
                +
                +
                + + + + + + + + + + + + +
                + + \ No newline at end of file From de3b1c14b0cb1db22b799fcd8f09cc0dff5929a4 Mon Sep 17 00:00:00 2001 From: CoderShmily Date: Tue, 4 Apr 2017 11:01:20 +0800 Subject: [PATCH 014/148] Customize commit message --- categories/iOS/index.html | 310 -------------------------------------- 1 file changed, 310 deletions(-) delete mode 100644 categories/iOS/index.html diff --git a/categories/iOS/index.html b/categories/iOS/index.html deleted file mode 100644 index 66bc9e3..0000000 --- a/categories/iOS/index.html +++ /dev/null @@ -1,310 +0,0 @@ - - - - - - Category: iOS | CoderShmily's Blog - - - - - - - - - - - - - - - - - - - - - - - - - -
                -
                - -
                -
                - - - - - - -
                -
                - 2015 -
                -
                - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                - - -
                - - - -
                -
                - -
                - -
                -
                -
                - - - - - - - - - - - - -
                - - \ No newline at end of file From 8f230691436a518e0b0f6cce3ac70a7a2aedeb65 Mon Sep 17 00:00:00 2001 From: CoderShmily Date: Tue, 4 Apr 2017 11:03:44 +0800 Subject: [PATCH 015/148] Customize commit message --- 2015/05/01/2015-05-01-Swift-ru-men/index.html | 4 +- 2015/05/02/2015-05-02-singleton/index.html | 4 +- .../2015-05-03-kvc-he-kvoshen-ru/index.html | 4 +- .../index.html | 4 +- .../05/2015-05-05-runtime-gai-shu/index.html | 4 +- .../index.html | 4 +- .../index.html | 4 +- .../index.html | 4 +- .../2016-11-15-Swift3.0-jie-shao/index.html | 14 +- categories/iOS/index.html | 310 ++++++++++++++++++ 10 files changed, 333 insertions(+), 23 deletions(-) create mode 100644 categories/iOS/index.html diff --git a/2015/05/01/2015-05-01-Swift-ru-men/index.html b/2015/05/01/2015-05-01-Swift-ru-men/index.html index de918b6..cf822ab 100644 --- a/2015/05/01/2015-05-01-Swift-ru-men/index.html +++ b/2015/05/01/2015-05-01-Swift-ru-men/index.html @@ -110,8 +110,8 @@

                - - + +

                特色

                • 苹果宣称 Swift 的特点是:快速、现代、安全、互动,而且明显优于 Objective-C 语言
                • diff --git a/2015/05/02/2015-05-02-singleton/index.html b/2015/05/02/2015-05-02-singleton/index.html index 343f7be..1473d15 100644 --- a/2015/05/02/2015-05-02-singleton/index.html +++ b/2015/05/02/2015-05-02-singleton/index.html @@ -93,8 +93,8 @@

                  - - + +

                  单例在整个工程中,就相当于一个全局变量,就是不论在哪里需要用到这个类的实例变量,都可以通过单例方法来取得,而且一旦你创建了一个单例类,不论你在多少个界面中初始化调用了这个单例方法取得对象,它们所有的对象都是指向的同一块内存存储空间(即单例类保证了该类的实力对象是唯一存在的一个).

                  diff --git a/2015/05/03/2015-05-03-kvc-he-kvoshen-ru/index.html b/2015/05/03/2015-05-03-kvc-he-kvoshen-ru/index.html index 137a632..63ed5a6 100644 --- a/2015/05/03/2015-05-03-kvc-he-kvoshen-ru/index.html +++ b/2015/05/03/2015-05-03-kvc-he-kvoshen-ru/index.html @@ -93,8 +93,8 @@

                  - - + +

                  KVC 和 KVO深入

                  diff --git a/2015/05/04/2015-05-04-runtime-dui-xiang-mo-xing/index.html b/2015/05/04/2015-05-04-runtime-dui-xiang-mo-xing/index.html index cbe1d20..f6623cb 100644 --- a/2015/05/04/2015-05-04-runtime-dui-xiang-mo-xing/index.html +++ b/2015/05/04/2015-05-04-runtime-dui-xiang-mo-xing/index.html @@ -96,8 +96,8 @@

                  - - + +

                  Objective-C语言是一门动态语言,它将很多静态语言在编译和链接时期做的事放到了运行时来处理。这种动态语言的优势在于:我们写代码时更具灵活性,如我们可以把消息转发给我们想要的对象,或者随意交换一个方法的实现等。

                  这种特性意味着Objective-C不仅需要一个编译器,还需要一个运行时系统来执行编译的代码。对于Objective-C来说,这个运行时系统就像一个操作系统一样:它让所有的工作可以正常的运行。这个运行时系统即Objc Runtime。Objc Runtime其实是一个Runtime库,它基本上是用C和汇编写的,这个库使得C语言有了面向对象的能力。

                  diff --git a/2015/05/05/2015-05-05-runtime-gai-shu/index.html b/2015/05/05/2015-05-05-runtime-gai-shu/index.html index c26df52..a655101 100644 --- a/2015/05/05/2015-05-05-runtime-gai-shu/index.html +++ b/2015/05/05/2015-05-05-runtime-gai-shu/index.html @@ -93,8 +93,8 @@

                  - - + +

                  Runtime常用方法和一些应用

                  diff --git a/2015/05/06/2015-05-06-objective-c-runtime-san-xiao-xi-chuan-di/index.html b/2015/05/06/2015-05-06-objective-c-runtime-san-xiao-xi-chuan-di/index.html index 480da73..5e44b25 100644 --- a/2015/05/06/2015-05-06-objective-c-runtime-san-xiao-xi-chuan-di/index.html +++ b/2015/05/06/2015-05-06-objective-c-runtime-san-xiao-xi-chuan-di/index.html @@ -93,8 +93,8 @@

                  - - + +

                  Objective-C Runtime的消息传递

                  ###Objective-C – 消息传递
                  Objective-C 扩展了 C 语言,并加入了面向对象特性和 Smalltalk 式的消息传递机制。而这个扩展的核心是一个用 C 和 编译语言 写的 Runtime 库。它是 Objective-C 面向对象和动态机制的基石.

                  diff --git a/2015/05/07/2015-05-07-objective-c-runtime-si-dong-tai-fang-fa-jue-yi-dynamic-method-resolution/index.html b/2015/05/07/2015-05-07-objective-c-runtime-si-dong-tai-fang-fa-jue-yi-dynamic-method-resolution/index.html index 16779e1..50bc889 100644 --- a/2015/05/07/2015-05-07-objective-c-runtime-si-dong-tai-fang-fa-jue-yi-dynamic-method-resolution/index.html +++ b/2015/05/07/2015-05-07-objective-c-runtime-si-dong-tai-fang-fa-jue-yi-dynamic-method-resolution/index.html @@ -93,8 +93,8 @@

                  - - + +

                  Objective-C Runtime之动态方法决议

                  diff --git a/2015/05/15/2015-05-15-sdwebimageyuan-ma-jie-xi/index.html b/2015/05/15/2015-05-15-sdwebimageyuan-ma-jie-xi/index.html index 54a432d..fd29ae0 100644 --- a/2015/05/15/2015-05-15-sdwebimageyuan-ma-jie-xi/index.html +++ b/2015/05/15/2015-05-15-sdwebimageyuan-ma-jie-xi/index.html @@ -93,8 +93,8 @@

                  - - + +

                  SDWebImage源码解析

                  1
                  2
                  3
                  4
                  5
                  6
                  7
                  8
                  9
                  10
                  11
                  12
                  13
                  14
                  15
                  16
                  17
                  18
                  19
                  20
                  21
                  22
                  23
                  24
                  25
                  26
                  27
                  28
                  29
                  30
                  31
                  32
                  33
                  34
                  35
                  36
                  37
                  38
                  39
                  40
                  41
                  42
                  43
                  44
                  45
                  46
                  47
                  48
                  49
                  50
                  51
                  52
                  53
                  54
                  55
                  56
                  57
                  58
                  59
                  60
                  61
                  62
                  63
                  64
                  65
                  66
                  67
                  68
                  69
                  70
                  71
                  72
                  73
                  74
                  75
                  76
                  77
                  78
                  79
                  80
                  81
                  82
                  83
                  84
                  85
                  86
                  87
                  88
                  89
                  90
                  91
                  92
                  93
                  94
                  95
                  96
                  97
                  98
                  99
                  100
                  101
                  102
                  103
                  104
                  105
                  106
                  107
                  108
                  109
                  110
                  111
                  112
                  113
                  114
                  115
                  116
                  117
                  118
                  119
                  120
                  121
                  122
                  123
                  124
                  125
                  126
                  127
                  128
                  129
                  130
                  131
                  132
                  133
                  134
                  135
                  136
                  137
                  138
                  139
                  140
                  141
                  142
                  143
                  144
                  145
                  146
                  147
                  148
                  149
                  150
                  151
                  152
                  153
                  154
                  155
                  156
                  157
                  158
                  159
                  160
                  161
                  162
                  163
                  164
                  165
                  166
                  167
                  168
                  169
                  170
                  171
                  172
                  173
                  174
                  175
                  176
                  177
                  178
                  179
                  180
                  181
                  182
                  183
                  184
                  185
                  186
                  187
                  188
                  189
                  190
                  191
                  192
                  193
                  194
                  195
                  196
                  197
                  198
                  199
                  200
                  201
                  202
                  203
                  204
                  205
                  206
                  207
                  208
                  209
                  210
                  211
                  212
                  213
                  214
                  215
                  216
                  217
                  218
                  219
                  220
                  221
                  222
                  223
                  224
                  225
                  226
                  227
                  228
                  229
                  230
                  231
                  232
                  233
                  234
                  235
                  236
                  237
                  238
                  239
                  240
                  241
                  242
                  243
                  244
                  245
                  246
                  247
                  248
                  249
                  250
                  251
                  252
                  253
                  254
                  255
                  256
                  257
                  258
                  259
                  260
                  261
                  262
                  263
                  264
                  265
                  266
                  267
                  268
                  269
                  270
                  271
                  272
                  273
                  274
                  275
                  276
                  277
                  278
                  279
                  280
                  281
                  282
                  283
                  284
                  285
                  286
                  287
                  288
                  289
                  290
                  291
                  292
                  293
                  294
                  295
                  296
                  297
                  298
                  299
                  300
                  301
                  302
                  303
                  304
                  305
                  306
                  307
                  308
                  309
                  310
                  311
                  312
                  313
                  314
                  315
                  316
                  317
                  318
                  319
                  320
                  321
                  322
                  323
                  324
                  325
                  326
                  327
                  328
                  329
                  330
                  331
                  332
                  333
                  334
                  335
                  336
                  337
                  338
                  339
                  340
                  341
                  342
                  343
                  344
                  345
                  346
                  347
                  348
                  349
                  350
                  351
                  352
                  353
                  354
                  355
                  356
                  357
                  358
                  359
                  360
                  361
                  362
                  363
                  364
                  365
                  366
                  367
                  368
                  369
                  370
                  371
                  372
                  373
                  374
                  375
                  376
                  377
                  378
                  379
                  380
                  381
                  382
                  383
                  /*
                  * This file is part of the SDWebImage package.
                  * (c) Olivier Poitrey <rs@dailymotion.com>
                  *
                  * For the full copyright and license information, please view the LICENSE
                  * file that was distributed with this source code.
                  */
                  #import "SDWebImageCompat.h"
                  #import "SDWebImageOperation.h"
                  #import "SDWebImageDownloader.h"
                  #import "SDImageCache.h"
                  typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) {
                  /**
                  * By default, when a URL fail to be downloaded, the URL is blacklisted so the library won't keep trying.
                  * This flag disable this blacklisting.
                  */
                  /**
                  *默认情况下,如果一个url在下载的时候失败了,那么这个url会被加入黑名单并且library不会尝试再次下载,这个flag会阻止library把失败的url加入黑名单(简单来说如果选择了这个flag,那么即使某个url下载失败了,sdwebimage还是会尝试再次下载他.)
                  */
                  SDWebImageRetryFailed = 1 << 0,
                  /**
                  * By default, image downloads are started during UI interactions, this flags disable this feature,
                  * leading to delayed download on UIScrollView deceleration for instance.
                  */
                  /**
                  *默认情况下,图片会在交互发生的时候下载(例如你滑动tableview的时候),这个flag会禁止这个特性,导致的结果就是在scrollview减速的时候
                  *才会开始下载(也就是你滑动的时候scrollview不下载,你手从屏幕上移走,scrollview开始减速的时候才会开始下载图片)
                  */
                  SDWebImageLowPriority = 1 << 1,
                  /**
                  * This flag disables on-disk caching
                  */
                  /*
                  *这个flag禁止磁盘缓存,只有内存缓存
                  */
                  SDWebImageCacheMemoryOnly = 1 << 2,
                  /**
                  * This flag enables progressive download, the image is displayed progressively during download as a browser would do.
                  * By default, the image is only displayed once completely downloaded.
                  */
                  /*
                  *这个flag会在图片下载的时候就显示(就像你用浏览器浏览网页的时候那种图片下载,一截一截的显示(待确认))
                  *
                  */
                  SDWebImageProgressiveDownload = 1 << 3,
                  /**
                  * Even if the image is cached, respect the HTTP response cache control, and refresh the image from remote location if needed.
                  * The disk caching will be handled by NSURLCache instead of SDWebImage leading to slight performance degradation.
                  * This option helps deal with images changing behind the same request URL, e.g. Facebook graph api profile pics.
                  * If a cached image is refreshed, the completion block is called once with the cached image and again with the final image.
                  *
                  * Use this flag only if you can't make your URLs static with embeded cache busting parameter.
                  */
                  /*
                  *这个选项的意思看的不是很懂,大意是即使一个图片缓存了,还是会重新请求.并且缓存侧略依据NSURLCache而不是SDWebImage.
                  *
                  */
                  SDWebImageRefreshCached = 1 << 4,
                  /**
                  * In iOS 4+, continue the download of the image if the app goes to background. This is achieved by asking the system for
                  * extra time in background to let the request finish. If the background task expires the operation will be cancelled.
                  */
                  /*
                  *启动后台下载,加入你进入一个页面,有一张图片正在下载这时候你让app进入后台,图片还是会继续下载(这个估计要开backgroundfetch才有用)
                  */
                  SDWebImageContinueInBackground = 1 << 5,
                  /**
                  * Handles cookies stored in NSHTTPCookieStore by setting
                  * NSMutableURLRequest.HTTPShouldHandleCookies = YES;
                  */
                  /*
                  *可以控制存在NSHTTPCookieStore的cookies.(我没用过,等用过的人过来解释一下)
                  */
                  SDWebImageHandleCookies = 1 << 6,
                  /**
                  * Enable to allow untrusted SSL ceriticates.
                  * Useful for testing purposes. Use with caution in production.
                  */
                  /*
                  *允许不安全的SSL证书,在正式环境中慎用
                  */
                  SDWebImageAllowInvalidSSLCertificates = 1 << 7,
                  /**
                  * By default, image are loaded in the order they were queued. This flag move them to
                  * the front of the queue and is loaded immediately instead of waiting for the current queue to be loaded (which
                  * could take a while).
                  */
                  /*
                  *默认情况下,image在装载的时候是按照他们在队列中的顺序装载的(就是先进先出).这个flag会把他们移动到队列的前端,并且立刻装载
                  *而不是等到当前队列装载的时候再装载.
                  */
                  SDWebImageHighPriority = 1 << 8,
                  /**
                  * By default, placeholder images are loaded while the image is loading. This flag will delay the loading
                  * of the placeholder image until after the image has finished loading.
                  */
                  /*
                  *默认情况下,占位图会在图片下载的时候显示.这个flag开启会延迟占位图显示的时间,等到图片下载完成之后才会显示占位图.(等图片显示完了我干嘛还显示占位图?或许是我理解错了?)
                  */
                  SDWebImageDelayPlaceholder = 1 << 9,
                  /**
                  * We usually don't call transformDownloadedImage delegate method on animated images,
                  * as most transformation code would mangle it.
                  * Use this flag to transform them anyway.
                  */
                  /*
                  *是否transform图片(没用过,还要再看,但是据我估计,是否是图片有可能方向不对需要调整方向,例如采用iPhone拍摄的照片如果不纠正方向,那么图片是向左旋转90度的.可能很多人不知道iPhone的摄像头并不是竖直的,而是向左偏了90度.具体请google.)
                  */
                  SDWebImageTransformAnimatedImage = 1 << 10,
                  };
                  typedef void(^SDWebImageCompletionBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL);
                  typedef void(^SDWebImageCompletionWithFinishedBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL);
                  typedef NSString *(^SDWebImageCacheKeyFilterBlock)(NSURL *url);
                  @class SDWebImageManager;
                  @protocol SDWebImageManagerDelegate <NSObject>
                  @optional
                  /**
                  * Controls which image should be downloaded when the image is not found in the cache.
                  *
                  * @param imageManager The current `SDWebImageManager`
                  * @param imageURL The url of the image to be downloaded
                  *
                  * @return Return NO to prevent the downloading of the image on cache misses. If not implemented, YES is implied.
                  */
                  /*
                  *主要作用是当缓存里没有发现某张图片的缓存时,是否选择下载这张图片(默认是yes),可以选择no,那么sdwebimage在缓存中没有找到这张图片的时候不会选择下载
                  */
                  - (BOOL)imageManager:(SDWebImageManager *)imageManager shouldDownloadImageForURL:(NSURL *)imageURL;
                  /**
                  * Allows to transform the image immediately after it has been downloaded and just before to cache it on disk and memory.
                  * NOTE: This method is called from a global queue in order to not to block the main thread.
                  *
                  * @param imageManager The current `SDWebImageManager`
                  * @param image The image to transform
                  * @param imageURL The url of the image to transform
                  *
                  * @return The transformed image object.
                  */
                  /**
                  *在图片下载完成并且还没有加入磁盘缓存或者内存缓存的时候就transform这个图片.这个方法是在异步线程执行的,防治阻塞主线程.
                  *至于为什么在异步执行很简单,对一张图片纠正方向(也就是transform)是很耗资源的,一张2M大小的图片纠正方向你可以用instrument测试一下耗时.
                  *很恐怖
                  */
                  - (UIImage *)imageManager:(SDWebImageManager *)imageManager transformDownloadedImage:(UIImage *)image withURL:(NSURL *)imageURL;
                  @end
                  /**
                  * The SDWebImageManager is the class behind the UIImageView+WebCache category and likes.
                  * It ties the asynchronous downloader (SDWebImageDownloader) with the image cache store (SDImageCache).
                  * You can use this class directly to benefit from web image downloading with caching in another context than
                  * a UIView.
                  *
                  * Here is a simple example of how to use SDWebImageManager:
                  *
                  * @code
                  SDWebImageManager *manager = [SDWebImageManager sharedManager];
                  [manager downloadImageWithURL:imageURL
                  options:0
                  progress:nil
                  completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
                  if (image) {
                  // do something with image
                  }
                  }];
                  * @endcode
                  */
                  /*
                  *这一段是阐述SDWebImageManager是干嘛的.其实UIImageView+WebCache这个category背后执行操作的就是这个SDWebImageManager.他会绑定一个下载器也就是SDWebImageDownloader和一个缓存SDImageCache.后面的大意应该是讲你可以直接使用一个其他上下文环境的SDWebImageManager,而不是仅仅限于一个UIView.
                  */
                  @interface SDWebImageManager : NSObject
                  @property (weak, nonatomic) id <SDWebImageManagerDelegate> delegate;
                  /**
                  *如同上文所说,一个SDWebImageManager会绑定一个imageCache和一个下载器.
                  */
                  @property (strong, nonatomic, readonly) SDImageCache *imageCache;
                  @property (strong, nonatomic, readonly) SDWebImageDownloader *imageDownloader;
                  /**
                  * The cache filter is a block used each time SDWebImageManager need to convert an URL into a cache key. This can
                  * be used to remove dynamic part of an image URL.
                  *
                  * The following example sets a filter in the application delegate that will remove any query-string from the
                  * URL before to use it as a cache key:
                  *
                  * @code
                  [[SDWebImageManager sharedManager] setCacheKeyFilter:^(NSURL *url) {
                  url = [[NSURL alloc] initWithScheme:url.scheme host:url.host path:url.path];
                  return [url absoluteString];
                  }];
                  * @endcode
                  */
                  /*
                  * 这个cacheKeyFilter是干嘛的呢?很简单.1他是一个block.2.这个block的作用就是生成一个image的key.因为sdwebimage的缓存原理你可以当成是一个字典,每一个字典的value就是一张image,那么这个value对应的key是什么呢?就是cacheKeyFilter根据某个规则对这个图片的url做一些操作生成的.上面的示例就显示了怎么利用这个block把image的url重新组合生成一个key.以后当sdwebimage检测到你
                  */
                  @property (nonatomic, copy) SDWebImageCacheKeyFilterBlock cacheKeyFilter;
                  /**
                  * Returns global SDWebImageManager instance.
                  *
                  * @return SDWebImageManager shared instance
                  */
                  /*
                  *这个不用我解释了吧,生成一个SDWebImagemanager的单例.
                  */
                  + (SDWebImageManager *)sharedManager;
                  /**
                  * Downloads the image at the given URL if not present in cache or return the cached version otherwise.
                  * 从给定的URL中下载一个之前没有被缓存的Image.
                  *
                  * @param url The URL to the image
                  * @param options A mask to specify options to use for this request
                  * @param progressBlock A block called while image is downloading
                  * @param completedBlock A block called when operation has been completed.
                  *
                  * This parameter is required.
                  *
                  * This block has no return value and takes the requested UIImage as first parameter.
                  * In case of error the image parameter is nil and the second parameter may contain an NSError.
                  *
                  * The third parameter is an `SDImageCacheType` enum indicating if the image was retrived from the local cache
                  * or from the memory cache or from the network.
                  *
                  * The last parameter is set to NO when the SDWebImageProgressiveDownload option is used and the image is
                  * downloading. This block is thus called repetidly with a partial image. When image is fully downloaded, the
                  * block is called a last time with the full image and the last parameter set to YES.
                  *
                  * @return Returns an NSObject conforming to SDWebImageOperation. Should be an instance of SDWebImageDownloaderOperation
                  */
                  /*
                  * 这个方法主要就是SDWebImage下载图片的方法了.
                  * 第一个参数是必须要的,就是image的url
                  * 第二个参数就是我们上面的Options,你可以定制化各种各样的操作.详情参上.
                  * 第三个参数是一个回调block,用于图片在下载过程中的回调.(英文注释应该是有问题的.)
                  * 第四个参数是一个下载完成的回调.会在图片下载完成后回调.
                  * 返回值是一个NSObject类,并且这个NSObject类是conforming一个协议这个协议叫做SDWebImageOperation,这个协议很简单,就是一个cancel掉operation的协议.
                  */
                  - (id <SDWebImageOperation>)downloadImageWithURL:(NSURL *)url
                  options:(SDWebImageOptions)options
                  progress:(SDWebImageDownloaderProgressBlock)progressBlock
                  completed:(SDWebImageCompletionWithFinishedBlock)completedBlock;
                  /**
                  * Saves image to cache for given URL
                  *
                  * @param image The image to cache
                  * @param url The URL to the image
                  *
                  */
                  /*
                  * 将图片存入cache的方法,类似于字典的setValue: forKey:
                  */
                  - (void)saveImageToCache:(UIImage *)image forURL:(NSURL *)url;
                  /**
                  * Cancel all current opreations
                  */
                  /*
                  *取消掉当前所有的下载图片的operation
                  */
                  - (void)cancelAll;
                  /**
                  * Check one or more operations running
                  */
                  /*
                  * check一下是否有一个或者多个operation正在执行(简单来说就是check是否有图片在下载)
                  */
                  - (BOOL)isRunning;
                  /**
                  * Check if image has already been cached
                  *
                  * @param url image url
                  *
                  * @return if the image was already cached
                  */
                  /*
                  * 通过一个image的url是否已经存在,如果存在返回yes,否则返回no
                  */
                  - (BOOL)cachedImageExistsForURL:(NSURL *)url;
                  /**
                  * Check if image has already been cached on disk only
                  *
                  * @param url image url
                  *
                  * @return if the image was already cached (disk only)
                  */
                  /*
                  * 检测一个image是否已经被缓存到磁盘(是否存且仅存在disk里).
                  */
                  - (BOOL)diskImageExistsForURL:(NSURL *)url;
                  /**
                  * Async check if image has already been cached
                  *
                  * @param url image url
                  * @param completionBlock the block to be executed when the check is finished
                  *
                  * @note the completion block is always executed on the main queue
                  */
                  /*
                  * 如果检测到图片已经被缓存,那么执行回调block.这个block会永远执行在主线程.也就是你可以在这个回调block里更新ui.
                  */
                  - (void)cachedImageExistsForURL:(NSURL *)url
                  completion:(SDWebImageCheckCacheCompletionBlock)completionBlock;
                  /**
                  * Async check if image has already been cached on disk only
                  *
                  * @param url image url
                  * @param completionBlock the block to be executed when the check is finished
                  *
                  * @note the completion block is always executed on the main queue
                  */
                  /*
                  * 如果检测到图片已经被缓存在磁盘(存且仅存在disk),那么执行回调block.这个block会永远执行在主线程.也就是你可以在这个回调block里更新ui.
                  */
                  - (void)diskImageExistsForURL:(NSURL *)url
                  completion:(SDWebImageCheckCacheCompletionBlock)completionBlock;
                  /**
                  *Return the cache key for a given URL
                  */
                  /*
                  * 通过image的url返回image存在缓存里的key.有人会问了,为什么不直接把图片的url当做image的key来使用呢?而是非要对url做一些处理才能当做key.我的解释是,我也不太清楚.可能为了防止重复吧.
                  */
                  - (NSString *)cacheKeyForURL:(NSURL *)url;
                  @end
                  #pragma mark - Deprecated
                  typedef void(^SDWebImageCompletedBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType) __deprecated_msg("Block type deprecated. Use `SDWebImageCompletionBlock`");
                  typedef void(^SDWebImageCompletedWithFinishedBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished) __deprecated_msg("Block type deprecated. Use `SDWebImageCompletionWithFinishedBlock`");
                  // 已被废弃
                  @interface SDWebImageManager (Deprecated)
                  /**
                  * Downloads the image at the given URL if not present in cache or return the cached version otherwise.
                  *
                  * @deprecated This method has been deprecated. Use `downloadImageWithURL:options:progress:completed:`
                  */
                  - (id <SDWebImageOperation>)downloadWithURL:(NSURL *)url
                  options:(SDWebImageOptions)options
                  progress:(SDWebImageDownloaderProgressBlock)progressBlock
                  completed:(SDWebImageCompletedWithFinishedBlock)completedBlock __deprecated_msg("Method deprecated. Use `downloadImageWithURL:options:progress:completed:`");
                  @end
                  diff --git a/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html b/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html index 6684060..6c778b1 100644 --- a/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html +++ b/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html @@ -93,13 +93,13 @@

                  - - -
                  - 文章目录 -
                  1. 1. Any AnyObject NSObject
                  2. 2. 条件判断
                    1. 2.1. 1. if的使用
                    2. 2.2. 2. 三目运算符
                    3. 2.3. 3. guard
                    4. 2.4. 4. switch的用法
                      1. 2.4.1. 1. switch与基本数据
                      2. 2.4.2. 2. switch与区间
                      3. 2.4.3. 3. switch与枚举
                      4. 2.4.4. 4. switch与元组
                  3. 3. 循环
                    1. 3.1. 1. for循环
                    2. 3.2. 2. while循环
                      1. 3.2.1. 1. while循环
                      2. 3.2.2. 2. repeat~while循环
                  4. 4. 字符串处理
                  5. 5. 数组
                  6. 6. 字典
                  7. 7. 元组
                  8. 8. 可选类型
                    1. 8.1. 2. 可选类型 (才能赋值为nil)
                    2. 8.2. 3. 四种方式使用可选类型的值
                      1. 8.2.1. 1. 判断 + 直接解包
                      2. 8.2.2. 2. 可选绑定
                      3. 8.2.3. 3. guard守护
                      4. 8.2.4. 4. 空合运算符
                  9. 9. 类型转换
                  10. 10. 函数
                    1. 10.1. 1. 函数的四种类型
                      1. 10.1.1. 1. 无参数,无返回值
                      2. 10.1.2. 2. 无参数,有返回值
                      3. 10.1.3. 3. 有参数,无返回值
                      4. 10.1.4. 4. 有参数,有返回值
                    2. 10.2. 函数其他注意
                      1. 10.2.1. 1. 省略第一个外部参数的名字
                      2. 10.2.2. 2. 设置参数默认值
                      3. 10.2.3. 3. 设置可变参数
                      4. 10.2.4. 4. 修改内部参数的值
                      5. 10.2.5. 5. 设置参数为地址传递
                      6. 10.2.6. 6. 函数嵌套
                      7. 10.2.7. 7. 函数的类型
                      8. 10.2.8. 8. 区分不同函数
                  11. 11. 枚举
                  12. 12. 结构体
                    1. 12.1. 1. 结构体基本使用
                    2. 12.2. 2. 结构体扩充构造函数
                  13. 13.
                    1. 13.1. 1. 类的声明初始化
                    2. 13.2. 2. 类的属性和方法
                    3. 13.3. 3. 类的继承之KVC使用
                    4. 13.4. 4. 类的循环引用
                    5. 13.5. 5. 结构体和类的区别
                    6. 13.6. 6. OC中使用Swift的类和结构体
                    7. 13.7. 7. Swift中调用OC
                  14. 14. 三大特性
                  15. 15. 可选链
                  16. 16. 协议
                    1. 16.1. 1.协议的基本使用
                    2. 16.2. 2. 协议中使用代理
                    3. 16.3. 3. 协议中的可选
                  17. 17. 闭包
                    1. 17.1. 1.闭包的基本使用
                    2. 17.2. 2. 尾随闭包和逃逸闭包
                    3. 17.3. 3. 闭包的循环引用(4中解决方式)
                  18. 18. 懒加载
                  19. 19. 注释
                  20. 20. 访问权限
                    1. 20.1. 访问修饰符
                  21. 21. 方法抛出异常
                  22. 22. Playground
                    1. 22.1. 1. Playground异步执行
                    2. 22.2. 2. MarkDown语法
                    3. 22.3. 3. TimeLine使用
                    4. 22.4. 4. Playground的Sources目录
                  -
                  - + + +
                  + 文章目录 +
                  1. 1. Any AnyObject NSObject
                  2. 2. 条件判断
                    1. 2.1. 1. if的使用
                    2. 2.2. 2. 三目运算符
                    3. 2.3. 3. guard
                    4. 2.4. 4. switch的用法
                      1. 2.4.1. 1. switch与基本数据
                      2. 2.4.2. 2. switch与区间
                      3. 2.4.3. 3. switch与枚举
                      4. 2.4.4. 4. switch与元组
                  3. 3. 循环
                    1. 3.1. 1. for循环
                    2. 3.2. 2. while循环
                      1. 3.2.1. 1. while循环
                      2. 3.2.2. 2. repeat~while循环
                  4. 4. 字符串处理
                  5. 5. 数组
                  6. 6. 字典
                  7. 7. 元组
                  8. 8. 可选类型
                    1. 8.1. 2. 可选类型 (才能赋值为nil)
                    2. 8.2. 3. 四种方式使用可选类型的值
                      1. 8.2.1. 1. 判断 + 直接解包
                      2. 8.2.2. 2. 可选绑定
                      3. 8.2.3. 3. guard守护
                      4. 8.2.4. 4. 空合运算符
                  9. 9. 类型转换
                  10. 10. 函数
                    1. 10.1. 1. 函数的四种类型
                      1. 10.1.1. 1. 无参数,无返回值
                      2. 10.1.2. 2. 无参数,有返回值
                      3. 10.1.3. 3. 有参数,无返回值
                      4. 10.1.4. 4. 有参数,有返回值
                    2. 10.2. 函数其他注意
                      1. 10.2.1. 1. 省略第一个外部参数的名字
                      2. 10.2.2. 2. 设置参数默认值
                      3. 10.2.3. 3. 设置可变参数
                      4. 10.2.4. 4. 修改内部参数的值
                      5. 10.2.5. 5. 设置参数为地址传递
                      6. 10.2.6. 6. 函数嵌套
                      7. 10.2.7. 7. 函数的类型
                      8. 10.2.8. 8. 区分不同函数
                  11. 11. 枚举
                  12. 12. 结构体
                    1. 12.1. 1. 结构体基本使用
                    2. 12.2. 2. 结构体扩充构造函数
                  13. 13.
                    1. 13.1. 1. 类的声明初始化
                    2. 13.2. 2. 类的属性和方法
                    3. 13.3. 3. 类的继承之KVC使用
                    4. 13.4. 4. 类的循环引用
                    5. 13.5. 5. 结构体和类的区别
                    6. 13.6. 6. OC中使用Swift的类和结构体
                    7. 13.7. 7. Swift中调用OC
                  14. 14. 三大特性
                  15. 15. 可选链
                  16. 16. 协议
                    1. 16.1. 1.协议的基本使用
                    2. 16.2. 2. 协议中使用代理
                    3. 16.3. 3. 协议中的可选
                  17. 17. 闭包
                    1. 17.1. 1.闭包的基本使用
                    2. 17.2. 2. 尾随闭包和逃逸闭包
                    3. 17.3. 3. 闭包的循环引用(4中解决方式)
                  18. 18. 懒加载
                  19. 19. 注释
                  20. 20. 访问权限
                    1. 20.1. 访问修饰符
                  21. 21. 方法抛出异常
                  22. 22. Playground
                    1. 22.1. 1. Playground异步执行
                    2. 22.2. 2. MarkDown语法
                    3. 22.3. 3. TimeLine使用
                    4. 22.4. 4. Playground的Sources目录
                  +
                  +

                  总结一些 Swift3.0学习笔记

                  diff --git a/categories/iOS/index.html b/categories/iOS/index.html new file mode 100644 index 0000000..66bc9e3 --- /dev/null +++ b/categories/iOS/index.html @@ -0,0 +1,310 @@ + + + + + + Category: iOS | CoderShmily's Blog + + + + + + + + + + + + + + + + + + + + + + + + + +
                  +
                  + +
                  +
                  + + + + + + +
                  +
                  + 2015 +
                  +
                  + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                  + + +
                  + + + +
                  +
                  + +
                  + +
                  +
                  +
                  + + + + + + + + + + + + +
                  + + \ No newline at end of file From a7cbaed6f59ffe9af41305e9de7838bb1236254d Mon Sep 17 00:00:00 2001 From: CoderShmily Date: Tue, 4 Apr 2017 11:05:57 +0800 Subject: [PATCH 016/148] Customize commit message --- categories/iOS/index.html | 310 -------- css/style.css | 1402 ------------------------------------- 2 files changed, 1712 deletions(-) delete mode 100644 categories/iOS/index.html diff --git a/categories/iOS/index.html b/categories/iOS/index.html deleted file mode 100644 index 66bc9e3..0000000 --- a/categories/iOS/index.html +++ /dev/null @@ -1,310 +0,0 @@ - - - - - - Category: iOS | CoderShmily's Blog - - - - - - - - - - - - - - - - - - - - - - - - - -
                  -
                  - -
                  -
                  - - - - - - -
                  -
                  - 2015 -
                  -
                  - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                  - - -
                  - - - -
                  -
                  - -
                  - -
                  -
                  -
                  - - - - - - - - - - - - -
                  - - \ No newline at end of file diff --git a/css/style.css b/css/style.css index e260d28..e69de29 100644 --- a/css/style.css +++ b/css/style.css @@ -1,1402 +0,0 @@ -body { - width: 100%; -} -body:before, -body:after { - content: ""; - display: table; -} -body:after { - clear: both; -} -.toc-article { - background: #eee; - padding: 1em; - position: relative; - left: 2em; -} -.toc-article .toc-title { - padding-bottom: 0.8em; - font-weight: bold; -} -#toc { - line-height: 1.1em; - font-size: 0.8em; - float: right; -} -#toc .toc { - padding: 0; -} -#toc li, -.toc li { - list-style-type: none; -} -#toc ol { - margin: 0; -} -#toc .toc-child { - padding-left: 1.5em; -} -html, -body, -div, -span, -applet, -object, -iframe, -h1, -h2, -h3, -h4, -h5, -h6, -p, -blockquote, -pre, -a, -abbr, -acronym, -address, -big, -cite, -code, -del, -dfn, -em, -img, -ins, -kbd, -q, -s, -samp, -small, -strike, -strong, -sub, -sup, -tt, -var, -dl, -dt, -dd, -ol, -ul, -li, -fieldset, -form, -label, -legend, -table, -caption, -tbody, -tfoot, -thead, -tr, -th, -td { - margin: 0; - padding: 0; - border: 0; - outline: 0; - font-weight: inherit; - font-style: inherit; - font-family: inherit; - font-size: 100%; - vertical-align: baseline; -} -body { - line-height: 1; - color: #000; - background: #fff; -} -ol, -ul { - list-style: none; -} -table { - border-collapse: separate; - border-spacing: 0; - vertical-align: middle; -} -caption, -th, -td { - text-align: left; - font-weight: normal; - vertical-align: middle; -} -a img { - border: none; -} -input, -button { - margin: 0; - padding: 0; -} -input::-moz-focus-inner, -button::-moz-focus-inner { - border: 0; - padding: 0; -} -@font-face { - font-family: FontAwesome; - font-style: normal; - font-weight: normal; - src: url("fonts/fontawesome-webfont.eot?v=#4.0.3"); - src: url("fonts/fontawesome-webfont.eot?#iefix&v=#4.0.3") format("embedded-opentype"), url("fonts/fontawesome-webfont.woff?v=#4.0.3") format("woff"), url("fonts/fontawesome-webfont.ttf?v=#4.0.3") format("truetype"), url("fonts/fontawesome-webfont.svg#fontawesomeregular?v=#4.0.3") format("svg"); -} -html, -body, -#container { - height: 100%; -} -body { - background: #eee; - font: 14px "Helvetica Neue", Helvetica, Arial, sans-serif; - -webkit-text-size-adjust: 100%; -} -.outer { - max-width: 1220px; - margin: 0 auto; - padding: 0 20px; -} -.outer:before, -.outer:after { - content: ""; - display: table; -} -.outer:after { - clear: both; -} -.inner { - display: inline; - float: left; - width: 98.33333333333333%; - margin: 0 0.833333333333333%; -} -.left, -.alignleft { - float: left; -} -.right, -.alignright { - float: right; -} -.clear { - clear: both; -} -#container { - position: relative; -} -.mobile-nav-on { - overflow: hidden; -} -#wrap { - height: 100%; - width: 100%; - position: absolute; - top: 0; - left: 0; - -webkit-transition: 0.2s ease-out; - -moz-transition: 0.2s ease-out; - -ms-transition: 0.2s ease-out; - transition: 0.2s ease-out; - z-index: 1; - background: #eee; -} -.mobile-nav-on #wrap { - left: 280px; -} -@media screen and (min-width: 768px) { - #main { - display: inline; - float: left; - width: 73.33333333333333%; - margin: 0 0.833333333333333%; - } -} -.article-date, -.article-category-link, -.archive-year, -.widget-title { - text-decoration: none; - text-transform: uppercase; - letter-spacing: 2px; - color: #999; - margin-bottom: 1em; - margin-left: 5px; - line-height: 1em; - text-shadow: 0 1px #fff; - font-weight: bold; -} -.article-inner, -.archive-article-inner { - background: #fff; - -webkit-box-shadow: 1px 2px 3px #ddd; - box-shadow: 1px 2px 3px #ddd; - border: 1px solid #ddd; - border-radius: 3px; -} -.article-entry h1, -.widget h1 { - font-size: 2em; -} -.article-entry h2, -.widget h2 { - font-size: 1.5em; -} -.article-entry h3, -.widget h3 { - font-size: 1.3em; -} -.article-entry h4, -.widget h4 { - font-size: 1.2em; -} -.article-entry h5, -.widget h5 { - font-size: 1em; -} -.article-entry h6, -.widget h6 { - font-size: 1em; - color: #999; -} -.article-entry hr, -.widget hr { - border: 1px dashed #ddd; -} -.article-entry strong, -.widget strong { - font-weight: bold; -} -.article-entry em, -.widget em, -.article-entry cite, -.widget cite { - font-style: italic; -} -.article-entry sup, -.widget sup, -.article-entry sub, -.widget sub { - font-size: 0.75em; - line-height: 0; - position: relative; - vertical-align: baseline; -} -.article-entry sup, -.widget sup { - top: -0.5em; -} -.article-entry sub, -.widget sub { - bottom: -0.2em; -} -.article-entry small, -.widget small { - font-size: 0.85em; -} -.article-entry acronym, -.widget acronym, -.article-entry abbr, -.widget abbr { - border-bottom: 1px dotted; -} -.article-entry ul, -.widget ul, -.article-entry ol, -.widget ol, -.article-entry dl, -.widget dl { - margin: 0 20px; - line-height: 1.6em; -} -.article-entry ul ul, -.widget ul ul, -.article-entry ol ul, -.widget ol ul, -.article-entry ul ol, -.widget ul ol, -.article-entry ol ol, -.widget ol ol { - margin-top: 0; - margin-bottom: 0; -} -.article-entry ul, -.widget ul { - list-style: disc; -} -.article-entry ol, -.widget ol { - list-style: decimal; -} -.article-entry dt, -.widget dt { - font-weight: bold; -} -#header { - height: 300px; - position: relative; - border-bottom: 1px solid #ddd; -} -#header:before, -#header:after { - content: ""; - position: absolute; - left: 0; - right: 0; - height: 40px; -} -#header:before { - top: 0; - background: -webkit-linear-gradient(rgba(0,0,0,0.2), transparent); - background: -moz-linear-gradient(rgba(0,0,0,0.2), transparent); - background: -ms-linear-gradient(rgba(0,0,0,0.2), transparent); - background: linear-gradient(rgba(0,0,0,0.2), transparent); -} -#header:after { - bottom: 0; - background: -webkit-linear-gradient(transparent, rgba(0,0,0,0.2)); - background: -moz-linear-gradient(transparent, rgba(0,0,0,0.2)); - background: -ms-linear-gradient(transparent, rgba(0,0,0,0.2)); - background: linear-gradient(transparent, rgba(0,0,0,0.2)); -} -#header-outer { - height: 100%; - position: relative; -} -#header-inner { - position: relative; - overflow: hidden; -} -#banner { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - background: url("images/banner.jpg") center #000; - -webkit-background-size: cover; - -moz-background-size: cover; - background-size: cover; - z-index: -1; -} -#header-title { - text-align: center; - height: 40px; - position: absolute; - top: 50%; - left: 0; - margin-top: -20px; -} -#logo, -#subtitle { - text-decoration: none; - color: #fff; - font-weight: 300; - text-shadow: 0 1px 4px rgba(0,0,0,0.3); -} -#logo { - font-size: 40px; - line-height: 40px; - letter-spacing: 2px; -} -#subtitle { - font-size: 16px; - line-height: 16px; - letter-spacing: 1px; -} -#subtitle-wrap { - margin-top: 16px; -} -#main-nav { - float: left; - margin-left: -15px; -} -.nav-icon, -.main-nav-link { - float: left; - color: #fff; - opacity: 0.6; - text-decoration: none; - text-shadow: 0 1px rgba(0,0,0,0.2); - -webkit-transition: opacity 0.2s; - -moz-transition: opacity 0.2s; - -ms-transition: opacity 0.2s; - transition: opacity 0.2s; - display: block; - padding: 20px 15px; -} -.nav-icon:hover, -.main-nav-link:hover { - opacity: 1; -} -.nav-icon { - font-family: FontAwesome; - text-align: center; - font-size: 14px; - width: 14px; - height: 14px; - padding: 20px 15px; - position: relative; - cursor: pointer; -} -.main-nav-link { - font-weight: 300; - letter-spacing: 1px; -} -@media screen and (max-width: 479px) { - .main-nav-link { - display: none; - } -} -#main-nav-toggle { - display: none; -} -#main-nav-toggle:before { - content: "\f0c9"; -} -@media screen and (max-width: 479px) { - #main-nav-toggle { - display: block; - } -} -#sub-nav { - float: right; - margin-right: -15px; -} -#nav-rss-link:before { - content: "\f09e"; -} -#nav-search-btn:before { - content: "\f002"; -} -#search-form-wrap { - position: absolute; - top: 15px; - width: 150px; - height: 30px; - right: -150px; - opacity: 0; - -webkit-transition: 0.2s ease-out; - -moz-transition: 0.2s ease-out; - -ms-transition: 0.2s ease-out; - transition: 0.2s ease-out; -} -#search-form-wrap.on { - opacity: 1; - right: 0; -} -@media screen and (max-width: 479px) { - #search-form-wrap { - width: 100%; - right: -100%; - } -} -.search-form { - position: absolute; - top: 0; - left: 0; - right: 0; - background: #fff; - padding: 5px 15px; - border-radius: 15px; - -webkit-box-shadow: 0 0 10px rgba(0,0,0,0.3); - box-shadow: 0 0 10px rgba(0,0,0,0.3); -} -.search-form-input { - border: none; - background: none; - color: #555; - width: 100%; - font: 13px "Helvetica Neue", Helvetica, Arial, sans-serif; - outline: none; -} -.search-form-input::-webkit-search-results-decoration, -.search-form-input::-webkit-search-cancel-button { - -webkit-appearance: none; -} -.search-form-submit { - position: absolute; - top: 50%; - right: 10px; - margin-top: -7px; - font: 13px FontAwesome; - border: none; - background: none; - color: #bbb; - cursor: pointer; -} -.search-form-submit:hover, -.search-form-submit:focus { - color: #777; -} -.article { - margin: 50px 0; -} -.article-inner { - overflow: hidden; -} -.article-meta:before, -.article-meta:after { - content: ""; - display: table; -} -.article-meta:after { - clear: both; -} -.article-date { - float: left; -} -.article-category { - float: left; - line-height: 1em; - color: #ccc; - text-shadow: 0 1px #fff; - margin-left: 8px; -} -.article-category:before { - content: "\2022"; -} -.article-category-link { - margin: 0 12px 1em; -} -.article-header { - padding: 20px 20px 0; -} -.article-title { - text-decoration: none; - font-size: 2em; - font-weight: bold; - color: #555; - line-height: 1.1em; - -webkit-transition: color 0.2s; - -moz-transition: color 0.2s; - -ms-transition: color 0.2s; - transition: color 0.2s; -} -a.article-title:hover { - color: #258fb8; -} -.article-entry { - color: #555; - padding: 0 20px; -} -.article-entry:before, -.article-entry:after { - content: ""; - display: table; -} -.article-entry:after { - clear: both; -} -.article-entry p, -.article-entry table { - line-height: 1.6em; - margin: 1.6em 0; -} -.article-entry h1, -.article-entry h2, -.article-entry h3, -.article-entry h4, -.article-entry h5, -.article-entry h6 { - font-weight: bold; -} -.article-entry h1, -.article-entry h2, -.article-entry h3, -.article-entry h4, -.article-entry h5, -.article-entry h6 { - line-height: 1.1em; - margin: 1.1em 0; -} -.article-entry a { - color: #258fb8; - text-decoration: none; -} -.article-entry a:hover { - text-decoration: underline; -} -.article-entry ul, -.article-entry ol, -.article-entry dl { - margin-top: 1.6em; - margin-bottom: 1.6em; -} -.article-entry img, -.article-entry video { - max-width: 100%; - height: auto; - display: block; - margin: auto; -} -.article-entry iframe { - border: none; -} -.article-entry table { - width: 100%; - border-collapse: collapse; - border-spacing: 0; -} -.article-entry th { - font-weight: bold; - border-bottom: 3px solid #ddd; - padding-bottom: 0.5em; -} -.article-entry td { - border-bottom: 1px solid #ddd; - padding: 10px 0; -} -.article-entry blockquote { - font-family: Georgia, "Times New Roman", serif; - font-size: 1.4em; - margin: 1.6em 20px; - text-align: center; -} -.article-entry blockquote footer { - font-size: 14px; - margin: 1.6em 0; - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; -} -.article-entry blockquote footer cite:before { - content: "—"; - padding: 0 0.5em; -} -.article-entry .pullquote { - text-align: left; - width: 45%; - margin: 0; -} -.article-entry .pullquote.left { - margin-left: 0.5em; - margin-right: 1em; -} -.article-entry .pullquote.right { - margin-right: 0.5em; - margin-left: 1em; -} -.article-entry .caption { - color: #999; - display: block; - font-size: 0.9em; - margin-top: 0.5em; - position: relative; - text-align: center; -} -.article-entry .video-container { - position: relative; - padding-top: 56.25%; - height: 0; - overflow: hidden; -} -.article-entry .video-container iframe, -.article-entry .video-container object, -.article-entry .video-container embed { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - margin-top: 0; -} -.article-more-link a { - display: inline-block; - line-height: 1em; - padding: 6px 15px; - border-radius: 15px; - background: #eee; - color: #999; - text-shadow: 0 1px #fff; - text-decoration: none; -} -.article-more-link a:hover { - background: #258fb8; - color: #fff; - text-decoration: none; - text-shadow: 0 1px #1e7293; -} -.article-footer { - font-size: 0.85em; - line-height: 1.6em; - border-top: 1px solid #ddd; - padding-top: 1.6em; - margin: 0 20px 20px; -} -.article-footer:before, -.article-footer:after { - content: ""; - display: table; -} -.article-footer:after { - clear: both; -} -.article-footer a { - color: #999; - text-decoration: none; -} -.article-footer a:hover { - color: #555; -} -.article-tag-list-item { - float: left; - margin-right: 10px; -} -.article-tag-list-link:before { - content: "#"; -} -.article-comment-link { - float: right; -} -.article-comment-link:before { - content: "\f075"; - font-family: FontAwesome; - padding-right: 8px; -} -.article-share-link { - cursor: pointer; - float: right; - margin-left: 20px; -} -.article-share-link:before { - content: "\f064"; - font-family: FontAwesome; - padding-right: 6px; -} -#article-nav { - position: relative; -} -#article-nav:before, -#article-nav:after { - content: ""; - display: table; -} -#article-nav:after { - clear: both; -} -@media screen and (min-width: 768px) { - #article-nav { - margin: 50px 0; - } - #article-nav:before { - width: 8px; - height: 8px; - position: absolute; - top: 50%; - left: 50%; - margin-top: -4px; - margin-left: -4px; - content: ""; - border-radius: 50%; - background: #ddd; - -webkit-box-shadow: 0 1px 2px #fff; - box-shadow: 0 1px 2px #fff; - } -} -.article-nav-link-wrap { - text-decoration: none; - text-shadow: 0 1px #fff; - color: #999; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - margin-top: 50px; - text-align: center; - display: block; -} -.article-nav-link-wrap:hover { - color: #555; -} -@media screen and (min-width: 768px) { - .article-nav-link-wrap { - width: 50%; - margin-top: 0; - } -} -@media screen and (min-width: 768px) { - #article-nav-newer { - float: left; - text-align: right; - padding-right: 20px; - } -} -@media screen and (min-width: 768px) { - #article-nav-older { - float: right; - text-align: left; - padding-left: 20px; - } -} -.article-nav-caption { - text-transform: uppercase; - letter-spacing: 2px; - color: #ddd; - line-height: 1em; - font-weight: bold; -} -#article-nav-newer .article-nav-caption { - margin-right: -2px; -} -.article-nav-title { - font-size: 0.85em; - line-height: 1.6em; - margin-top: 0.5em; -} -.article-share-box { - position: absolute; - display: none; - background: #fff; - -webkit-box-shadow: 1px 2px 10px rgba(0,0,0,0.2); - box-shadow: 1px 2px 10px rgba(0,0,0,0.2); - border-radius: 3px; - margin-left: -145px; - overflow: hidden; - z-index: 1; -} -.article-share-box.on { - display: block; -} -.article-share-input { - width: 100%; - background: none; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - font: 14px "Helvetica Neue", Helvetica, Arial, sans-serif; - padding: 0 15px; - color: #555; - outline: none; - border: 1px solid #ddd; - border-radius: 3px 3px 0 0; - height: 36px; - line-height: 36px; -} -.article-share-links { - background: #eee; -} -.article-share-links:before, -.article-share-links:after { - content: ""; - display: table; -} -.article-share-links:after { - clear: both; -} -.article-share-twitter, -.article-share-facebook, -.article-share-pinterest, -.article-share-google { - width: 50px; - height: 36px; - display: block; - float: left; - position: relative; - color: #999; - text-shadow: 0 1px #fff; -} -.article-share-twitter:before, -.article-share-facebook:before, -.article-share-pinterest:before, -.article-share-google:before { - font-size: 20px; - font-family: FontAwesome; - width: 20px; - height: 20px; - position: absolute; - top: 50%; - left: 50%; - margin-top: -10px; - margin-left: -10px; - text-align: center; -} -.article-share-twitter:hover, -.article-share-facebook:hover, -.article-share-pinterest:hover, -.article-share-google:hover { - color: #fff; -} -.article-share-twitter:before { - content: "\f099"; -} -.article-share-twitter:hover { - background: #00aced; - text-shadow: 0 1px #008abe; -} -.article-share-facebook:before { - content: "\f09a"; -} -.article-share-facebook:hover { - background: #3b5998; - text-shadow: 0 1px #2f477a; -} -.article-share-pinterest:before { - content: "\f0d2"; -} -.article-share-pinterest:hover { - background: #cb2027; - text-shadow: 0 1px #a21a1f; -} -.article-share-google:before { - content: "\f0d5"; -} -.article-share-google:hover { - background: #dd4b39; - text-shadow: 0 1px #be3221; -} -.article-gallery { - background: #000; - position: relative; -} -.article-gallery-photos { - position: relative; - overflow: hidden; -} -.article-gallery-img { - display: none; - max-width: 100%; -} -.article-gallery-img:first-child { - display: block; -} -.article-gallery-img.loaded { - position: absolute; - display: block; -} -.article-gallery-img img { - display: block; - max-width: 100%; - margin: 0 auto; -} -#comments { - background: #fff; - -webkit-box-shadow: 1px 2px 3px #ddd; - box-shadow: 1px 2px 3px #ddd; - padding: 20px; - border: 1px solid #ddd; - border-radius: 3px; - margin: 50px 0; -} -#comments a { - color: #258fb8; -} -.archives-wrap { - margin: 50px 0; -} -.archives:before, -.archives:after { - content: ""; - display: table; -} -.archives:after { - clear: both; -} -.archive-year-wrap { - margin-bottom: 1em; -} -.archives { - -webkit-column-gap: 10px; - -moz-column-gap: 10px; - column-gap: 10px; -} -@media screen and (min-width: 480px) and (max-width: 767px) { - .archives { - -webkit-column-count: 2; - -moz-column-count: 2; - column-count: 2; - } -} -@media screen and (min-width: 768px) { - .archives { - -webkit-column-count: 3; - -moz-column-count: 3; - column-count: 3; - } -} -.archive-article { - -webkit-column-break-inside: avoid; - page-break-inside: avoid; - overflow: hidden; - break-inside: avoid-column; -} -.archive-article-inner { - padding: 10px; - margin-bottom: 15px; -} -.archive-article-title { - text-decoration: none; - font-weight: bold; - color: #555; - -webkit-transition: color 0.2s; - -moz-transition: color 0.2s; - -ms-transition: color 0.2s; - transition: color 0.2s; - line-height: 1.6em; -} -.archive-article-title:hover { - color: #258fb8; -} -.archive-article-footer { - margin-top: 1em; -} -.archive-article-date { - color: #999; - text-decoration: none; - font-size: 0.85em; - line-height: 1em; - margin-bottom: 0.5em; - display: block; -} -#page-nav { - margin: 50px auto; - background: #fff; - -webkit-box-shadow: 1px 2px 3px #ddd; - box-shadow: 1px 2px 3px #ddd; - border: 1px solid #ddd; - border-radius: 3px; - text-align: center; - color: #999; - overflow: hidden; -} -#page-nav:before, -#page-nav:after { - content: ""; - display: table; -} -#page-nav:after { - clear: both; -} -#page-nav a, -#page-nav span { - padding: 10px 20px; - line-height: 1; - height: 2ex; -} -#page-nav a { - color: #999; - text-decoration: none; -} -#page-nav a:hover { - background: #999; - color: #fff; -} -#page-nav .prev { - float: left; -} -#page-nav .next { - float: right; -} -#page-nav .page-number { - display: inline-block; -} -@media screen and (max-width: 479px) { - #page-nav .page-number { - display: none; - } -} -#page-nav .current { - color: #555; - font-weight: bold; -} -#page-nav .space { - color: #ddd; -} -#footer { - background: #262a30; - padding: 50px 0; - border-top: 1px solid #ddd; - color: #999; -} -#footer a { - color: #258fb8; - text-decoration: none; -} -#footer a:hover { - text-decoration: underline; -} -#footer-info { - line-height: 1.6em; - font-size: 0.85em; -} -.article-entry pre, -.article-entry .highlight { - background: #2d2d2d; - margin: 0 -20px; - padding: 15px 20px; - border-style: solid; - border-color: #ddd; - border-width: 1px 0; - overflow: auto; - color: #ccc; - line-height: 22.400000000000002px; -} -.article-entry .highlight .gutter pre, -.article-entry .gist .gist-file .gist-data .line-numbers { - color: #666; - font-size: 0.85em; -} -.article-entry pre, -.article-entry code { - font-family: "Source Code Pro", Consolas, Monaco, Menlo, Consolas, monospace; -} -.article-entry code { - background: #eee; - text-shadow: 0 1px #fff; - padding: 0 0.3em; -} -.article-entry pre code { - background: none; - text-shadow: none; - padding: 0; -} -.article-entry .highlight pre { - border: none; - margin: 0; - padding: 0; -} -.article-entry .highlight table { - margin: 0; - width: auto; -} -.article-entry .highlight td { - border: none; - padding: 0; -} -.article-entry .highlight figcaption { - font-size: 0.85em; - color: #999; - line-height: 1em; - margin-bottom: 1em; -} -.article-entry .highlight figcaption:before, -.article-entry .highlight figcaption:after { - content: ""; - display: table; -} -.article-entry .highlight figcaption:after { - clear: both; -} -.article-entry .highlight figcaption a { - float: right; -} -.article-entry .highlight .gutter pre { - text-align: right; - padding-right: 20px; -} -.article-entry .highlight .line { - height: 22.400000000000002px; -} -.article-entry .highlight .line.marked { - background: #515151; -} -.article-entry .gist { - margin: 0 -20px; - border-style: solid; - border-color: #ddd; - border-width: 1px 0; - background: #2d2d2d; - padding: 15px 20px 15px 0; -} -.article-entry .gist .gist-file { - border: none; - font-family: "Source Code Pro", Consolas, Monaco, Menlo, Consolas, monospace; - margin: 0; -} -.article-entry .gist .gist-file .gist-data { - background: none; - border: none; -} -.article-entry .gist .gist-file .gist-data .line-numbers { - background: none; - border: none; - padding: 0 20px 0 0; -} -.article-entry .gist .gist-file .gist-data .line-data { - padding: 0 !important; -} -.article-entry .gist .gist-file .highlight { - margin: 0; - padding: 0; - border: none; -} -.article-entry .gist .gist-file .gist-meta { - background: #2d2d2d; - color: #999; - font: 0.85em "Helvetica Neue", Helvetica, Arial, sans-serif; - text-shadow: 0 0; - padding: 0; - margin-top: 1em; - margin-left: 20px; -} -.article-entry .gist .gist-file .gist-meta a { - color: #258fb8; - font-weight: normal; -} -.article-entry .gist .gist-file .gist-meta a:hover { - text-decoration: underline; -} -pre .comment, -pre .title { - color: #999; -} -pre .variable, -pre .attribute, -pre .tag, -pre .regexp, -pre .ruby .constant, -pre .xml .tag .title, -pre .xml .pi, -pre .xml .doctype, -pre .html .doctype, -pre .css .id, -pre .css .class, -pre .css .pseudo { - color: #f2777a; -} -pre .number, -pre .preprocessor, -pre .built_in, -pre .literal, -pre .params, -pre .constant { - color: #f99157; -} -pre .class, -pre .ruby .class .title, -pre .css .rules .attribute { - color: #9c9; -} -pre .string, -pre .value, -pre .inheritance, -pre .header, -pre .ruby .symbol, -pre .xml .cdata { - color: #9c9; -} -pre .css .hexcolor { - color: #6cc; -} -pre .function, -pre .python .decorator, -pre .python .title, -pre .ruby .function .title, -pre .ruby .title .keyword, -pre .perl .sub, -pre .javascript .title, -pre .coffeescript .title { - color: #69c; -} -pre .keyword, -pre .javascript .function { - color: #c9c; -} -@media screen and (max-width: 479px) { - #mobile-nav { - position: absolute; - top: 0; - left: 0; - width: 280px; - height: 100%; - background: #191919; - border-right: 1px solid #fff; - } -} -@media screen and (max-width: 479px) { - .mobile-nav-link { - display: block; - color: #999; - text-decoration: none; - padding: 15px 20px; - font-weight: bold; - } - .mobile-nav-link:hover { - color: #fff; - } -} -@media screen and (min-width: 768px) { - #sidebar { - display: inline; - float: left; - width: 23.333333333333332%; - margin: 0 0.833333333333333%; - } -} -.widget-wrap { - margin: 50px 0; -} -.widget { - color: #777; - text-shadow: 0 1px #fff; - background: #ddd; - -webkit-box-shadow: 0 -1px 4px #ccc inset; - box-shadow: 0 -1px 4px #ccc inset; - border: 1px solid #ccc; - padding: 15px; - border-radius: 3px; -} -.widget a { - color: #258fb8; - text-decoration: none; -} -.widget a:hover { - text-decoration: underline; -} -.widget ul ul, -.widget ol ul, -.widget dl ul, -.widget ul ol, -.widget ol ol, -.widget dl ol, -.widget ul dl, -.widget ol dl, -.widget dl dl { - margin-left: 15px; - list-style: disc; -} -.widget { - line-height: 1.6em; - word-wrap: break-word; - font-size: 0.9em; -} -.widget ul, -.widget ol { - list-style: none; - margin: 0; -} -.widget ul ul, -.widget ol ul, -.widget ul ol, -.widget ol ol { - margin: 0 20px; -} -.widget ul ul, -.widget ol ul { - list-style: disc; -} -.widget ul ol, -.widget ol ol { - list-style: decimal; -} -.category-list-count, -.tag-list-count, -.archive-list-count { - padding-left: 5px; - color: #999; - font-size: 0.85em; -} -.category-list-count:before, -.tag-list-count:before, -.archive-list-count:before { - content: "("; -} -.category-list-count:after, -.tag-list-count:after, -.archive-list-count:after { - content: ")"; -} -.tagcloud a { - margin-right: 5px; - display: inline-block; -} From 5c41f478f024109037a38a8e7208a529bb9fd72d Mon Sep 17 00:00:00 2001 From: CoderShmily Date: Tue, 4 Apr 2017 11:06:37 +0800 Subject: [PATCH 017/148] Customize commit message --- categories/iOS/index.html | 310 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 310 insertions(+) create mode 100644 categories/iOS/index.html diff --git a/categories/iOS/index.html b/categories/iOS/index.html new file mode 100644 index 0000000..66bc9e3 --- /dev/null +++ b/categories/iOS/index.html @@ -0,0 +1,310 @@ + + + + + + Category: iOS | CoderShmily's Blog + + + + + + + + + + + + + + + + + + + + + + + + + +
                  +
                  + +
                  +
                  + + + + + + +
                  +
                  + 2015 +
                  +
                  + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                  + + +
                  + + + +
                  +
                  + +
                  + +
                  +
                  +
                  + + + + + + + + + + + + +
                  + + \ No newline at end of file From 4cbfb7f0aff07bd3567eb76df5e85bdeff9a7841 Mon Sep 17 00:00:00 2001 From: CoderShmily Date: Tue, 4 Apr 2017 11:09:47 +0800 Subject: [PATCH 018/148] Customize commit message --- 2015/05/01/2015-05-01-Swift-ru-men/index.html | 2 - 2015/05/02/2015-05-02-singleton/index.html | 2 - .../2015-05-03-kvc-he-kvoshen-ru/index.html | 2 - .../index.html | 2 - .../05/2015-05-05-runtime-gai-shu/index.html | 2 - .../index.html | 2 - .../index.html | 2 - .../index.html | 2 - .../2016-11-15-Swift3.0-jie-shao/index.html | 7 - categories/iOS/index.html | 310 ------------------ 10 files changed, 333 deletions(-) delete mode 100644 categories/iOS/index.html diff --git a/2015/05/01/2015-05-01-Swift-ru-men/index.html b/2015/05/01/2015-05-01-Swift-ru-men/index.html index cf822ab..4b620e7 100644 --- a/2015/05/01/2015-05-01-Swift-ru-men/index.html +++ b/2015/05/01/2015-05-01-Swift-ru-men/index.html @@ -110,8 +110,6 @@

                  - -

                  特色

                  • 苹果宣称 Swift 的特点是:快速、现代、安全、互动,而且明显优于 Objective-C 语言
                  • diff --git a/2015/05/02/2015-05-02-singleton/index.html b/2015/05/02/2015-05-02-singleton/index.html index 1473d15..60861ff 100644 --- a/2015/05/02/2015-05-02-singleton/index.html +++ b/2015/05/02/2015-05-02-singleton/index.html @@ -93,8 +93,6 @@

                    - -

                    单例在整个工程中,就相当于一个全局变量,就是不论在哪里需要用到这个类的实例变量,都可以通过单例方法来取得,而且一旦你创建了一个单例类,不论你在多少个界面中初始化调用了这个单例方法取得对象,它们所有的对象都是指向的同一块内存存储空间(即单例类保证了该类的实力对象是唯一存在的一个).

                    diff --git a/2015/05/03/2015-05-03-kvc-he-kvoshen-ru/index.html b/2015/05/03/2015-05-03-kvc-he-kvoshen-ru/index.html index 63ed5a6..ef75a31 100644 --- a/2015/05/03/2015-05-03-kvc-he-kvoshen-ru/index.html +++ b/2015/05/03/2015-05-03-kvc-he-kvoshen-ru/index.html @@ -93,8 +93,6 @@

                    - -

                    KVC 和 KVO深入

                    diff --git a/2015/05/04/2015-05-04-runtime-dui-xiang-mo-xing/index.html b/2015/05/04/2015-05-04-runtime-dui-xiang-mo-xing/index.html index f6623cb..50e72c3 100644 --- a/2015/05/04/2015-05-04-runtime-dui-xiang-mo-xing/index.html +++ b/2015/05/04/2015-05-04-runtime-dui-xiang-mo-xing/index.html @@ -96,8 +96,6 @@

                    - -

                    Objective-C语言是一门动态语言,它将很多静态语言在编译和链接时期做的事放到了运行时来处理。这种动态语言的优势在于:我们写代码时更具灵活性,如我们可以把消息转发给我们想要的对象,或者随意交换一个方法的实现等。

                    这种特性意味着Objective-C不仅需要一个编译器,还需要一个运行时系统来执行编译的代码。对于Objective-C来说,这个运行时系统就像一个操作系统一样:它让所有的工作可以正常的运行。这个运行时系统即Objc Runtime。Objc Runtime其实是一个Runtime库,它基本上是用C和汇编写的,这个库使得C语言有了面向对象的能力。

                    diff --git a/2015/05/05/2015-05-05-runtime-gai-shu/index.html b/2015/05/05/2015-05-05-runtime-gai-shu/index.html index a655101..7625bf0 100644 --- a/2015/05/05/2015-05-05-runtime-gai-shu/index.html +++ b/2015/05/05/2015-05-05-runtime-gai-shu/index.html @@ -93,8 +93,6 @@

                    - -

                    Runtime常用方法和一些应用

                    diff --git a/2015/05/06/2015-05-06-objective-c-runtime-san-xiao-xi-chuan-di/index.html b/2015/05/06/2015-05-06-objective-c-runtime-san-xiao-xi-chuan-di/index.html index 5e44b25..3cb6222 100644 --- a/2015/05/06/2015-05-06-objective-c-runtime-san-xiao-xi-chuan-di/index.html +++ b/2015/05/06/2015-05-06-objective-c-runtime-san-xiao-xi-chuan-di/index.html @@ -93,8 +93,6 @@

                    - -

                    Objective-C Runtime的消息传递

                    ###Objective-C – 消息传递
                    Objective-C 扩展了 C 语言,并加入了面向对象特性和 Smalltalk 式的消息传递机制。而这个扩展的核心是一个用 C 和 编译语言 写的 Runtime 库。它是 Objective-C 面向对象和动态机制的基石.

                    diff --git a/2015/05/07/2015-05-07-objective-c-runtime-si-dong-tai-fang-fa-jue-yi-dynamic-method-resolution/index.html b/2015/05/07/2015-05-07-objective-c-runtime-si-dong-tai-fang-fa-jue-yi-dynamic-method-resolution/index.html index 50bc889..ce200b3 100644 --- a/2015/05/07/2015-05-07-objective-c-runtime-si-dong-tai-fang-fa-jue-yi-dynamic-method-resolution/index.html +++ b/2015/05/07/2015-05-07-objective-c-runtime-si-dong-tai-fang-fa-jue-yi-dynamic-method-resolution/index.html @@ -93,8 +93,6 @@

                    - -

                    Objective-C Runtime之动态方法决议

                    diff --git a/2015/05/15/2015-05-15-sdwebimageyuan-ma-jie-xi/index.html b/2015/05/15/2015-05-15-sdwebimageyuan-ma-jie-xi/index.html index fd29ae0..e813bcd 100644 --- a/2015/05/15/2015-05-15-sdwebimageyuan-ma-jie-xi/index.html +++ b/2015/05/15/2015-05-15-sdwebimageyuan-ma-jie-xi/index.html @@ -93,8 +93,6 @@

                    - -

                    SDWebImage源码解析

                    1
                    2
                    3
                    4
                    5
                    6
                    7
                    8
                    9
                    10
                    11
                    12
                    13
                    14
                    15
                    16
                    17
                    18
                    19
                    20
                    21
                    22
                    23
                    24
                    25
                    26
                    27
                    28
                    29
                    30
                    31
                    32
                    33
                    34
                    35
                    36
                    37
                    38
                    39
                    40
                    41
                    42
                    43
                    44
                    45
                    46
                    47
                    48
                    49
                    50
                    51
                    52
                    53
                    54
                    55
                    56
                    57
                    58
                    59
                    60
                    61
                    62
                    63
                    64
                    65
                    66
                    67
                    68
                    69
                    70
                    71
                    72
                    73
                    74
                    75
                    76
                    77
                    78
                    79
                    80
                    81
                    82
                    83
                    84
                    85
                    86
                    87
                    88
                    89
                    90
                    91
                    92
                    93
                    94
                    95
                    96
                    97
                    98
                    99
                    100
                    101
                    102
                    103
                    104
                    105
                    106
                    107
                    108
                    109
                    110
                    111
                    112
                    113
                    114
                    115
                    116
                    117
                    118
                    119
                    120
                    121
                    122
                    123
                    124
                    125
                    126
                    127
                    128
                    129
                    130
                    131
                    132
                    133
                    134
                    135
                    136
                    137
                    138
                    139
                    140
                    141
                    142
                    143
                    144
                    145
                    146
                    147
                    148
                    149
                    150
                    151
                    152
                    153
                    154
                    155
                    156
                    157
                    158
                    159
                    160
                    161
                    162
                    163
                    164
                    165
                    166
                    167
                    168
                    169
                    170
                    171
                    172
                    173
                    174
                    175
                    176
                    177
                    178
                    179
                    180
                    181
                    182
                    183
                    184
                    185
                    186
                    187
                    188
                    189
                    190
                    191
                    192
                    193
                    194
                    195
                    196
                    197
                    198
                    199
                    200
                    201
                    202
                    203
                    204
                    205
                    206
                    207
                    208
                    209
                    210
                    211
                    212
                    213
                    214
                    215
                    216
                    217
                    218
                    219
                    220
                    221
                    222
                    223
                    224
                    225
                    226
                    227
                    228
                    229
                    230
                    231
                    232
                    233
                    234
                    235
                    236
                    237
                    238
                    239
                    240
                    241
                    242
                    243
                    244
                    245
                    246
                    247
                    248
                    249
                    250
                    251
                    252
                    253
                    254
                    255
                    256
                    257
                    258
                    259
                    260
                    261
                    262
                    263
                    264
                    265
                    266
                    267
                    268
                    269
                    270
                    271
                    272
                    273
                    274
                    275
                    276
                    277
                    278
                    279
                    280
                    281
                    282
                    283
                    284
                    285
                    286
                    287
                    288
                    289
                    290
                    291
                    292
                    293
                    294
                    295
                    296
                    297
                    298
                    299
                    300
                    301
                    302
                    303
                    304
                    305
                    306
                    307
                    308
                    309
                    310
                    311
                    312
                    313
                    314
                    315
                    316
                    317
                    318
                    319
                    320
                    321
                    322
                    323
                    324
                    325
                    326
                    327
                    328
                    329
                    330
                    331
                    332
                    333
                    334
                    335
                    336
                    337
                    338
                    339
                    340
                    341
                    342
                    343
                    344
                    345
                    346
                    347
                    348
                    349
                    350
                    351
                    352
                    353
                    354
                    355
                    356
                    357
                    358
                    359
                    360
                    361
                    362
                    363
                    364
                    365
                    366
                    367
                    368
                    369
                    370
                    371
                    372
                    373
                    374
                    375
                    376
                    377
                    378
                    379
                    380
                    381
                    382
                    383
                    /*
                    * This file is part of the SDWebImage package.
                    * (c) Olivier Poitrey <rs@dailymotion.com>
                    *
                    * For the full copyright and license information, please view the LICENSE
                    * file that was distributed with this source code.
                    */
                    #import "SDWebImageCompat.h"
                    #import "SDWebImageOperation.h"
                    #import "SDWebImageDownloader.h"
                    #import "SDImageCache.h"
                    typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) {
                    /**
                    * By default, when a URL fail to be downloaded, the URL is blacklisted so the library won't keep trying.
                    * This flag disable this blacklisting.
                    */
                    /**
                    *默认情况下,如果一个url在下载的时候失败了,那么这个url会被加入黑名单并且library不会尝试再次下载,这个flag会阻止library把失败的url加入黑名单(简单来说如果选择了这个flag,那么即使某个url下载失败了,sdwebimage还是会尝试再次下载他.)
                    */
                    SDWebImageRetryFailed = 1 << 0,
                    /**
                    * By default, image downloads are started during UI interactions, this flags disable this feature,
                    * leading to delayed download on UIScrollView deceleration for instance.
                    */
                    /**
                    *默认情况下,图片会在交互发生的时候下载(例如你滑动tableview的时候),这个flag会禁止这个特性,导致的结果就是在scrollview减速的时候
                    *才会开始下载(也就是你滑动的时候scrollview不下载,你手从屏幕上移走,scrollview开始减速的时候才会开始下载图片)
                    */
                    SDWebImageLowPriority = 1 << 1,
                    /**
                    * This flag disables on-disk caching
                    */
                    /*
                    *这个flag禁止磁盘缓存,只有内存缓存
                    */
                    SDWebImageCacheMemoryOnly = 1 << 2,
                    /**
                    * This flag enables progressive download, the image is displayed progressively during download as a browser would do.
                    * By default, the image is only displayed once completely downloaded.
                    */
                    /*
                    *这个flag会在图片下载的时候就显示(就像你用浏览器浏览网页的时候那种图片下载,一截一截的显示(待确认))
                    *
                    */
                    SDWebImageProgressiveDownload = 1 << 3,
                    /**
                    * Even if the image is cached, respect the HTTP response cache control, and refresh the image from remote location if needed.
                    * The disk caching will be handled by NSURLCache instead of SDWebImage leading to slight performance degradation.
                    * This option helps deal with images changing behind the same request URL, e.g. Facebook graph api profile pics.
                    * If a cached image is refreshed, the completion block is called once with the cached image and again with the final image.
                    *
                    * Use this flag only if you can't make your URLs static with embeded cache busting parameter.
                    */
                    /*
                    *这个选项的意思看的不是很懂,大意是即使一个图片缓存了,还是会重新请求.并且缓存侧略依据NSURLCache而不是SDWebImage.
                    *
                    */
                    SDWebImageRefreshCached = 1 << 4,
                    /**
                    * In iOS 4+, continue the download of the image if the app goes to background. This is achieved by asking the system for
                    * extra time in background to let the request finish. If the background task expires the operation will be cancelled.
                    */
                    /*
                    *启动后台下载,加入你进入一个页面,有一张图片正在下载这时候你让app进入后台,图片还是会继续下载(这个估计要开backgroundfetch才有用)
                    */
                    SDWebImageContinueInBackground = 1 << 5,
                    /**
                    * Handles cookies stored in NSHTTPCookieStore by setting
                    * NSMutableURLRequest.HTTPShouldHandleCookies = YES;
                    */
                    /*
                    *可以控制存在NSHTTPCookieStore的cookies.(我没用过,等用过的人过来解释一下)
                    */
                    SDWebImageHandleCookies = 1 << 6,
                    /**
                    * Enable to allow untrusted SSL ceriticates.
                    * Useful for testing purposes. Use with caution in production.
                    */
                    /*
                    *允许不安全的SSL证书,在正式环境中慎用
                    */
                    SDWebImageAllowInvalidSSLCertificates = 1 << 7,
                    /**
                    * By default, image are loaded in the order they were queued. This flag move them to
                    * the front of the queue and is loaded immediately instead of waiting for the current queue to be loaded (which
                    * could take a while).
                    */
                    /*
                    *默认情况下,image在装载的时候是按照他们在队列中的顺序装载的(就是先进先出).这个flag会把他们移动到队列的前端,并且立刻装载
                    *而不是等到当前队列装载的时候再装载.
                    */
                    SDWebImageHighPriority = 1 << 8,
                    /**
                    * By default, placeholder images are loaded while the image is loading. This flag will delay the loading
                    * of the placeholder image until after the image has finished loading.
                    */
                    /*
                    *默认情况下,占位图会在图片下载的时候显示.这个flag开启会延迟占位图显示的时间,等到图片下载完成之后才会显示占位图.(等图片显示完了我干嘛还显示占位图?或许是我理解错了?)
                    */
                    SDWebImageDelayPlaceholder = 1 << 9,
                    /**
                    * We usually don't call transformDownloadedImage delegate method on animated images,
                    * as most transformation code would mangle it.
                    * Use this flag to transform them anyway.
                    */
                    /*
                    *是否transform图片(没用过,还要再看,但是据我估计,是否是图片有可能方向不对需要调整方向,例如采用iPhone拍摄的照片如果不纠正方向,那么图片是向左旋转90度的.可能很多人不知道iPhone的摄像头并不是竖直的,而是向左偏了90度.具体请google.)
                    */
                    SDWebImageTransformAnimatedImage = 1 << 10,
                    };
                    typedef void(^SDWebImageCompletionBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL);
                    typedef void(^SDWebImageCompletionWithFinishedBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL);
                    typedef NSString *(^SDWebImageCacheKeyFilterBlock)(NSURL *url);
                    @class SDWebImageManager;
                    @protocol SDWebImageManagerDelegate <NSObject>
                    @optional
                    /**
                    * Controls which image should be downloaded when the image is not found in the cache.
                    *
                    * @param imageManager The current `SDWebImageManager`
                    * @param imageURL The url of the image to be downloaded
                    *
                    * @return Return NO to prevent the downloading of the image on cache misses. If not implemented, YES is implied.
                    */
                    /*
                    *主要作用是当缓存里没有发现某张图片的缓存时,是否选择下载这张图片(默认是yes),可以选择no,那么sdwebimage在缓存中没有找到这张图片的时候不会选择下载
                    */
                    - (BOOL)imageManager:(SDWebImageManager *)imageManager shouldDownloadImageForURL:(NSURL *)imageURL;
                    /**
                    * Allows to transform the image immediately after it has been downloaded and just before to cache it on disk and memory.
                    * NOTE: This method is called from a global queue in order to not to block the main thread.
                    *
                    * @param imageManager The current `SDWebImageManager`
                    * @param image The image to transform
                    * @param imageURL The url of the image to transform
                    *
                    * @return The transformed image object.
                    */
                    /**
                    *在图片下载完成并且还没有加入磁盘缓存或者内存缓存的时候就transform这个图片.这个方法是在异步线程执行的,防治阻塞主线程.
                    *至于为什么在异步执行很简单,对一张图片纠正方向(也就是transform)是很耗资源的,一张2M大小的图片纠正方向你可以用instrument测试一下耗时.
                    *很恐怖
                    */
                    - (UIImage *)imageManager:(SDWebImageManager *)imageManager transformDownloadedImage:(UIImage *)image withURL:(NSURL *)imageURL;
                    @end
                    /**
                    * The SDWebImageManager is the class behind the UIImageView+WebCache category and likes.
                    * It ties the asynchronous downloader (SDWebImageDownloader) with the image cache store (SDImageCache).
                    * You can use this class directly to benefit from web image downloading with caching in another context than
                    * a UIView.
                    *
                    * Here is a simple example of how to use SDWebImageManager:
                    *
                    * @code
                    SDWebImageManager *manager = [SDWebImageManager sharedManager];
                    [manager downloadImageWithURL:imageURL
                    options:0
                    progress:nil
                    completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
                    if (image) {
                    // do something with image
                    }
                    }];
                    * @endcode
                    */
                    /*
                    *这一段是阐述SDWebImageManager是干嘛的.其实UIImageView+WebCache这个category背后执行操作的就是这个SDWebImageManager.他会绑定一个下载器也就是SDWebImageDownloader和一个缓存SDImageCache.后面的大意应该是讲你可以直接使用一个其他上下文环境的SDWebImageManager,而不是仅仅限于一个UIView.
                    */
                    @interface SDWebImageManager : NSObject
                    @property (weak, nonatomic) id <SDWebImageManagerDelegate> delegate;
                    /**
                    *如同上文所说,一个SDWebImageManager会绑定一个imageCache和一个下载器.
                    */
                    @property (strong, nonatomic, readonly) SDImageCache *imageCache;
                    @property (strong, nonatomic, readonly) SDWebImageDownloader *imageDownloader;
                    /**
                    * The cache filter is a block used each time SDWebImageManager need to convert an URL into a cache key. This can
                    * be used to remove dynamic part of an image URL.
                    *
                    * The following example sets a filter in the application delegate that will remove any query-string from the
                    * URL before to use it as a cache key:
                    *
                    * @code
                    [[SDWebImageManager sharedManager] setCacheKeyFilter:^(NSURL *url) {
                    url = [[NSURL alloc] initWithScheme:url.scheme host:url.host path:url.path];
                    return [url absoluteString];
                    }];
                    * @endcode
                    */
                    /*
                    * 这个cacheKeyFilter是干嘛的呢?很简单.1他是一个block.2.这个block的作用就是生成一个image的key.因为sdwebimage的缓存原理你可以当成是一个字典,每一个字典的value就是一张image,那么这个value对应的key是什么呢?就是cacheKeyFilter根据某个规则对这个图片的url做一些操作生成的.上面的示例就显示了怎么利用这个block把image的url重新组合生成一个key.以后当sdwebimage检测到你
                    */
                    @property (nonatomic, copy) SDWebImageCacheKeyFilterBlock cacheKeyFilter;
                    /**
                    * Returns global SDWebImageManager instance.
                    *
                    * @return SDWebImageManager shared instance
                    */
                    /*
                    *这个不用我解释了吧,生成一个SDWebImagemanager的单例.
                    */
                    + (SDWebImageManager *)sharedManager;
                    /**
                    * Downloads the image at the given URL if not present in cache or return the cached version otherwise.
                    * 从给定的URL中下载一个之前没有被缓存的Image.
                    *
                    * @param url The URL to the image
                    * @param options A mask to specify options to use for this request
                    * @param progressBlock A block called while image is downloading
                    * @param completedBlock A block called when operation has been completed.
                    *
                    * This parameter is required.
                    *
                    * This block has no return value and takes the requested UIImage as first parameter.
                    * In case of error the image parameter is nil and the second parameter may contain an NSError.
                    *
                    * The third parameter is an `SDImageCacheType` enum indicating if the image was retrived from the local cache
                    * or from the memory cache or from the network.
                    *
                    * The last parameter is set to NO when the SDWebImageProgressiveDownload option is used and the image is
                    * downloading. This block is thus called repetidly with a partial image. When image is fully downloaded, the
                    * block is called a last time with the full image and the last parameter set to YES.
                    *
                    * @return Returns an NSObject conforming to SDWebImageOperation. Should be an instance of SDWebImageDownloaderOperation
                    */
                    /*
                    * 这个方法主要就是SDWebImage下载图片的方法了.
                    * 第一个参数是必须要的,就是image的url
                    * 第二个参数就是我们上面的Options,你可以定制化各种各样的操作.详情参上.
                    * 第三个参数是一个回调block,用于图片在下载过程中的回调.(英文注释应该是有问题的.)
                    * 第四个参数是一个下载完成的回调.会在图片下载完成后回调.
                    * 返回值是一个NSObject类,并且这个NSObject类是conforming一个协议这个协议叫做SDWebImageOperation,这个协议很简单,就是一个cancel掉operation的协议.
                    */
                    - (id <SDWebImageOperation>)downloadImageWithURL:(NSURL *)url
                    options:(SDWebImageOptions)options
                    progress:(SDWebImageDownloaderProgressBlock)progressBlock
                    completed:(SDWebImageCompletionWithFinishedBlock)completedBlock;
                    /**
                    * Saves image to cache for given URL
                    *
                    * @param image The image to cache
                    * @param url The URL to the image
                    *
                    */
                    /*
                    * 将图片存入cache的方法,类似于字典的setValue: forKey:
                    */
                    - (void)saveImageToCache:(UIImage *)image forURL:(NSURL *)url;
                    /**
                    * Cancel all current opreations
                    */
                    /*
                    *取消掉当前所有的下载图片的operation
                    */
                    - (void)cancelAll;
                    /**
                    * Check one or more operations running
                    */
                    /*
                    * check一下是否有一个或者多个operation正在执行(简单来说就是check是否有图片在下载)
                    */
                    - (BOOL)isRunning;
                    /**
                    * Check if image has already been cached
                    *
                    * @param url image url
                    *
                    * @return if the image was already cached
                    */
                    /*
                    * 通过一个image的url是否已经存在,如果存在返回yes,否则返回no
                    */
                    - (BOOL)cachedImageExistsForURL:(NSURL *)url;
                    /**
                    * Check if image has already been cached on disk only
                    *
                    * @param url image url
                    *
                    * @return if the image was already cached (disk only)
                    */
                    /*
                    * 检测一个image是否已经被缓存到磁盘(是否存且仅存在disk里).
                    */
                    - (BOOL)diskImageExistsForURL:(NSURL *)url;
                    /**
                    * Async check if image has already been cached
                    *
                    * @param url image url
                    * @param completionBlock the block to be executed when the check is finished
                    *
                    * @note the completion block is always executed on the main queue
                    */
                    /*
                    * 如果检测到图片已经被缓存,那么执行回调block.这个block会永远执行在主线程.也就是你可以在这个回调block里更新ui.
                    */
                    - (void)cachedImageExistsForURL:(NSURL *)url
                    completion:(SDWebImageCheckCacheCompletionBlock)completionBlock;
                    /**
                    * Async check if image has already been cached on disk only
                    *
                    * @param url image url
                    * @param completionBlock the block to be executed when the check is finished
                    *
                    * @note the completion block is always executed on the main queue
                    */
                    /*
                    * 如果检测到图片已经被缓存在磁盘(存且仅存在disk),那么执行回调block.这个block会永远执行在主线程.也就是你可以在这个回调block里更新ui.
                    */
                    - (void)diskImageExistsForURL:(NSURL *)url
                    completion:(SDWebImageCheckCacheCompletionBlock)completionBlock;
                    /**
                    *Return the cache key for a given URL
                    */
                    /*
                    * 通过image的url返回image存在缓存里的key.有人会问了,为什么不直接把图片的url当做image的key来使用呢?而是非要对url做一些处理才能当做key.我的解释是,我也不太清楚.可能为了防止重复吧.
                    */
                    - (NSString *)cacheKeyForURL:(NSURL *)url;
                    @end
                    #pragma mark - Deprecated
                    typedef void(^SDWebImageCompletedBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType) __deprecated_msg("Block type deprecated. Use `SDWebImageCompletionBlock`");
                    typedef void(^SDWebImageCompletedWithFinishedBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished) __deprecated_msg("Block type deprecated. Use `SDWebImageCompletionWithFinishedBlock`");
                    // 已被废弃
                    @interface SDWebImageManager (Deprecated)
                    /**
                    * Downloads the image at the given URL if not present in cache or return the cached version otherwise.
                    *
                    * @deprecated This method has been deprecated. Use `downloadImageWithURL:options:progress:completed:`
                    */
                    - (id <SDWebImageOperation>)downloadWithURL:(NSURL *)url
                    options:(SDWebImageOptions)options
                    progress:(SDWebImageDownloaderProgressBlock)progressBlock
                    completed:(SDWebImageCompletedWithFinishedBlock)completedBlock __deprecated_msg("Method deprecated. Use `downloadImageWithURL:options:progress:completed:`");
                    @end
                    diff --git a/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html b/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html index 6c778b1..b4386ae 100644 --- a/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html +++ b/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html @@ -93,13 +93,6 @@

                    - - -
                    - 文章目录 -
                    1. 1. Any AnyObject NSObject
                    2. 2. 条件判断
                      1. 2.1. 1. if的使用
                      2. 2.2. 2. 三目运算符
                      3. 2.3. 3. guard
                      4. 2.4. 4. switch的用法
                        1. 2.4.1. 1. switch与基本数据
                        2. 2.4.2. 2. switch与区间
                        3. 2.4.3. 3. switch与枚举
                        4. 2.4.4. 4. switch与元组
                    3. 3. 循环
                      1. 3.1. 1. for循环
                      2. 3.2. 2. while循环
                        1. 3.2.1. 1. while循环
                        2. 3.2.2. 2. repeat~while循环
                    4. 4. 字符串处理
                    5. 5. 数组
                    6. 6. 字典
                    7. 7. 元组
                    8. 8. 可选类型
                      1. 8.1. 2. 可选类型 (才能赋值为nil)
                      2. 8.2. 3. 四种方式使用可选类型的值
                        1. 8.2.1. 1. 判断 + 直接解包
                        2. 8.2.2. 2. 可选绑定
                        3. 8.2.3. 3. guard守护
                        4. 8.2.4. 4. 空合运算符
                    9. 9. 类型转换
                    10. 10. 函数
                      1. 10.1. 1. 函数的四种类型
                        1. 10.1.1. 1. 无参数,无返回值
                        2. 10.1.2. 2. 无参数,有返回值
                        3. 10.1.3. 3. 有参数,无返回值
                        4. 10.1.4. 4. 有参数,有返回值
                      2. 10.2. 函数其他注意
                        1. 10.2.1. 1. 省略第一个外部参数的名字
                        2. 10.2.2. 2. 设置参数默认值
                        3. 10.2.3. 3. 设置可变参数
                        4. 10.2.4. 4. 修改内部参数的值
                        5. 10.2.5. 5. 设置参数为地址传递
                        6. 10.2.6. 6. 函数嵌套
                        7. 10.2.7. 7. 函数的类型
                        8. 10.2.8. 8. 区分不同函数
                    11. 11. 枚举
                    12. 12. 结构体
                      1. 12.1. 1. 结构体基本使用
                      2. 12.2. 2. 结构体扩充构造函数
                    13. 13.
                      1. 13.1. 1. 类的声明初始化
                      2. 13.2. 2. 类的属性和方法
                      3. 13.3. 3. 类的继承之KVC使用
                      4. 13.4. 4. 类的循环引用
                      5. 13.5. 5. 结构体和类的区别
                      6. 13.6. 6. OC中使用Swift的类和结构体
                      7. 13.7. 7. Swift中调用OC
                    14. 14. 三大特性
                    15. 15. 可选链
                    16. 16. 协议
                      1. 16.1. 1.协议的基本使用
                      2. 16.2. 2. 协议中使用代理
                      3. 16.3. 3. 协议中的可选
                    17. 17. 闭包
                      1. 17.1. 1.闭包的基本使用
                      2. 17.2. 2. 尾随闭包和逃逸闭包
                      3. 17.3. 3. 闭包的循环引用(4中解决方式)
                    18. 18. 懒加载
                    19. 19. 注释
                    20. 20. 访问权限
                      1. 20.1. 访问修饰符
                    21. 21. 方法抛出异常
                    22. 22. Playground
                      1. 22.1. 1. Playground异步执行
                      2. 22.2. 2. MarkDown语法
                      3. 22.3. 3. TimeLine使用
                      4. 22.4. 4. Playground的Sources目录
                    -
                    -

                    总结一些 Swift3.0学习笔记

                    diff --git a/categories/iOS/index.html b/categories/iOS/index.html deleted file mode 100644 index 66bc9e3..0000000 --- a/categories/iOS/index.html +++ /dev/null @@ -1,310 +0,0 @@ - - - - - - Category: iOS | CoderShmily's Blog - - - - - - - - - - - - - - - - - - - - - - - - - -
                    -
                    - -
                    -
                    - - - - - - -
                    -
                    - 2015 -
                    -
                    - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    - - -
                    - - - -
                    -
                    - -
                    - -
                    -
                    -
                    - - - - - - - - - - - - -
                    - - \ No newline at end of file From 3b286e20386cbbcc96d47b382a2ad8acee124796 Mon Sep 17 00:00:00 2001 From: CoderShmily Date: Tue, 4 Apr 2017 11:12:47 +0800 Subject: [PATCH 019/148] Customize commit message --- 2015/05/01/2015-05-01-Swift-ru-men/index.html | 378 +-- 2015/05/02/2015-05-02-singleton/index.html | 390 ++-- .../2015-05-03-kvc-he-kvoshen-ru/index.html | 386 ++-- .../index.html | 386 ++-- .../05/2015-05-05-runtime-gai-shu/index.html | 386 ++-- .../index.html | 386 ++-- .../index.html | 386 ++-- .../index.html | 390 ++-- .../2016-11-15-Swift3.0-jie-shao/index.html | 370 +-- archives/2015/05/index.html | 505 ++--- archives/2015/index.html | 505 ++--- archives/2016/11/index.html | 324 +-- archives/2016/index.html | 324 +-- archives/index.html | 471 ++-- categories/Swift/index.html | 348 ++- categories/iOS/index.html | 268 +++ css/aloha.css | 278 +++ css/aloha.less | 2 + css/fonts/FontAwesome.otf | Bin 62856 -> 0 bytes css/fonts/fontawesome-webfont.eot | Bin 38205 -> 0 bytes css/fonts/fontawesome-webfont.ttf | Bin 80652 -> 0 bytes css/fonts/fontawesome-webfont.woff | Bin 44432 -> 0 bytes css/images/banner.jpg | Bin 224710 -> 0 bytes css/semantic-ui/2.2.4/semantic.min.css | 11 + .../themes/default/assets/fonts/icons.eot | Bin 0 -> 60767 bytes .../themes/default/assets/fonts/icons.svg} | 225 +- .../themes/default/assets/fonts/icons.ttf | Bin 0 -> 122092 bytes .../themes/default/assets/fonts/icons.woff | Bin 0 -> 71508 bytes .../themes/default/assets/fonts/icons.woff2 | Bin 0 -> 56780 bytes css/style.css | 0 fancybox/blank.gif | Bin 43 -> 0 bytes fancybox/fancybox_loading.gif | Bin 6567 -> 0 bytes fancybox/fancybox_loading@2x.gif | Bin 13984 -> 0 bytes fancybox/fancybox_overlay.png | Bin 1003 -> 0 bytes fancybox/fancybox_sprite.png | Bin 1362 -> 0 bytes fancybox/fancybox_sprite@2x.png | Bin 6553 -> 0 bytes fancybox/helpers/fancybox_buttons.png | Bin 1080 -> 0 bytes fancybox/helpers/jquery.fancybox-buttons.css | 97 - fancybox/helpers/jquery.fancybox-buttons.js | 122 - fancybox/helpers/jquery.fancybox-media.js | 199 -- fancybox/helpers/jquery.fancybox-thumbs.css | 55 - fancybox/helpers/jquery.fancybox-thumbs.js | 165 -- fancybox/jquery.fancybox.css | 273 --- fancybox/jquery.fancybox.js | 2017 ----------------- fancybox/jquery.fancybox.pack.js | 46 - favicon.ico | Bin 0 -> 67646 bytes images/algolia_logo.svg | 21 + images/avatar.jpg | Bin 0 -> 244252 bytes images/scrolltop.png | Bin 0 -> 698 bytes index.html | 761 +++---- js/aloha-events.js | 14 + js/aloha.js | 3 + js/script.js | 137 -- js/semantic-ui-algolia.js | 88 + 54 files changed, 4152 insertions(+), 6565 deletions(-) create mode 100644 categories/iOS/index.html create mode 100644 css/aloha.css create mode 100644 css/aloha.less delete mode 100644 css/fonts/FontAwesome.otf delete mode 100644 css/fonts/fontawesome-webfont.eot delete mode 100644 css/fonts/fontawesome-webfont.ttf delete mode 100644 css/fonts/fontawesome-webfont.woff delete mode 100644 css/images/banner.jpg create mode 100644 css/semantic-ui/2.2.4/semantic.min.css create mode 100644 css/semantic-ui/2.2.4/themes/default/assets/fonts/icons.eot rename css/{fonts/fontawesome-webfont.svg => semantic-ui/2.2.4/themes/default/assets/fonts/icons.svg} (60%) create mode 100644 css/semantic-ui/2.2.4/themes/default/assets/fonts/icons.ttf create mode 100644 css/semantic-ui/2.2.4/themes/default/assets/fonts/icons.woff create mode 100644 css/semantic-ui/2.2.4/themes/default/assets/fonts/icons.woff2 delete mode 100644 css/style.css delete mode 100644 fancybox/blank.gif delete mode 100644 fancybox/fancybox_loading.gif delete mode 100644 fancybox/fancybox_loading@2x.gif delete mode 100644 fancybox/fancybox_overlay.png delete mode 100644 fancybox/fancybox_sprite.png delete mode 100644 fancybox/fancybox_sprite@2x.png delete mode 100644 fancybox/helpers/fancybox_buttons.png delete mode 100644 fancybox/helpers/jquery.fancybox-buttons.css delete mode 100644 fancybox/helpers/jquery.fancybox-buttons.js delete mode 100644 fancybox/helpers/jquery.fancybox-media.js delete mode 100644 fancybox/helpers/jquery.fancybox-thumbs.css delete mode 100644 fancybox/helpers/jquery.fancybox-thumbs.js delete mode 100644 fancybox/jquery.fancybox.css delete mode 100644 fancybox/jquery.fancybox.js delete mode 100644 fancybox/jquery.fancybox.pack.js create mode 100644 favicon.ico create mode 100644 images/algolia_logo.svg create mode 100644 images/avatar.jpg create mode 100644 images/scrolltop.png create mode 100644 js/aloha-events.js create mode 100644 js/aloha.js delete mode 100644 js/script.js create mode 100644 js/semantic-ui-algolia.js diff --git a/2015/05/01/2015-05-01-Swift-ru-men/index.html b/2015/05/01/2015-05-01-Swift-ru-men/index.html index 4b620e7..9e2c552 100644 --- a/2015/05/01/2015-05-01-Swift-ru-men/index.html +++ b/2015/05/01/2015-05-01-Swift-ru-men/index.html @@ -1,11 +1,15 @@ + + - - - - - Swift 入门 | CoderShmily's Blog - - + + + + + Swift 入门 | CoderShmily's Blog + + + - - - - - - - - - - - - + + - -
                    -
                    - -
                    -
                    - -
                    + -
                    - - -

                    - Swift 入门 -

                    - + + + 首页 + + + + + +
                    + +
                    + + + -
                    +
                    + + + + + -
                    +
                    + + - - -

            • 常量&变量
              1. 定义 OC 对象
              2. 变量类型
            • 逻辑分支
              1. 简单体验
              2. 三目
              3. 可选项
                1. 演练 1
                2. 演练 2
                3. 演练3
            • 循环
              1. OC风格的 for
              2. Swift风格的 for
              3. 特殊写法
            • 数组
              1. 数组中保存的对象类型
              2. 常见数组操作
            • 字符串
              1. 使用 String 的原因
              2. 遍历字符串
              3. 字符串拼接
              4. 格式化字符串
              5. String & Range 的结合
                1. 建议写法
            • 函数
              1. 简单演练
              2. 参数名的特殊处理
                1. 强制要求参数名
                2. 省略参数名
            • 闭包
              1. 闭包和OC中的Block差不多

      3. 懒加载
      4. 属性
      5. getter 和 setter
        1. 自定义 Person 类
        2. getter & setter
        3. didSet
        4. 计算型属性
        5. 构造函数
        6. 析构函数
        7. 重写description +
      + +

      + + +

      -

      +

      - - - -

    - +

+ - - - - - + + + + + + + + + + + + + + - - - \ No newline at end of file + diff --git a/2015/05/02/2015-05-02-singleton/index.html b/2015/05/02/2015-05-02-singleton/index.html index 60861ff..0f4c8ec 100644 --- a/2015/05/02/2015-05-02-singleton/index.html +++ b/2015/05/02/2015-05-02-singleton/index.html @@ -1,11 +1,15 @@ + + - - - - - 单例模式的ARC和MRC实现 | CoderShmily's Blog - - + + + + + + 单例模式的ARC和MRC实现 | CoderShmily's Blog + + + @@ -15,86 +19,128 @@ - - - - - - - - - - - - + + - -
-
- -
-
- -
+ -
- - -

- 单例模式的ARC和MRC实现 -

- - -
- -
- - -

单例在整个工程中,就相当于一个全局变量,就是不论在哪里需要用到这个类的实例变量,都可以通过单例方法来取得,而且一旦你创建了一个单例类,不论你在多少个界面中初始化调用了这个单例方法取得对象,它们所有的对象都是指向的同一块内存存储空间(即单例类保证了该类的实力对象是唯一存在的一个).

+ + + 首页 + + + + + +
+ +
+
+ + + +
+ + + +
+ +
+ +
+ + +

+ + 单例模式的ARC和MRC实现 +

+ + + +
+ +
+ +

单例在整个工程中,就相当于一个全局变量,就是不论在哪里需要用到这个类的实例变量,都可以通过单例方法来取得,而且一旦你创建了一个单例类,不论你在多少个界面中初始化调用了这个单例方法取得对象,它们所有的对象都是指向的同一块内存存储空间(即单例类保证了该类的实力对象是唯一存在的一个).

单例模式的作用

  1. 可以保证在程序运行过程,一个类只有一个实例,而且该实例易于供外界访问
  2. @@ -123,129 +169,109 @@

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // FileTools.h
    #import <Foundation/Foundation.h>
    #import "Single.h"
    @interface FileTools : NSObject
    //+ (instancetype)shareFileTools;
    interfaceSingle(FileTools);
    @end
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // FileTools.m
    #import "FileTools.h"
    @implementation FileTools
    implementationSingle(FileTools)
    @end
    - -

- -
- - - + +
+ + + + - -
+
+ + -
+ + -
+
+ + - - - -
+ - - - - - + + - - - - - + + + + + + + + + + + + + + - - - \ No newline at end of file + diff --git a/2015/05/03/2015-05-03-kvc-he-kvoshen-ru/index.html b/2015/05/03/2015-05-03-kvc-he-kvoshen-ru/index.html index ef75a31..502442d 100644 --- a/2015/05/03/2015-05-03-kvc-he-kvoshen-ru/index.html +++ b/2015/05/03/2015-05-03-kvc-he-kvoshen-ru/index.html @@ -1,11 +1,15 @@ + + - - - - - KVC 和 KVO深入 | CoderShmily's Blog - - + + + + + + KVC 和 KVO深入 | CoderShmily's Blog + + + @@ -15,86 +19,128 @@ - - - - - - - - - - - - + + - -
-
- -
-
- -
+ -
- - -

- KVC 和 KVO深入 -

- + + + 首页 + + + + + +
+ +
+
+ + + +
+ + + +
+ +
- +
+ + +

-
- - -

KVC 和 KVO深入

+ KVC 和 KVO深入 +

+ + + +
+ +
+ +

KVC 和 KVO深入

KVC概述

1.什么是KVC?

KVC即NSKeyValueCoding,键/值编码,一个非正式的Protocol,以字符串的形式向对象发送消息,而不是通过调用存取方法,直接或通过实例变量访问的机制。

valueForKey:首先查找以键-key或-isKey命名的getter方法。如果不存在getter方法(假如我们没有通过@synthesize提供存取方法),它将在对象内部查找名为_key或key的实例变量。
对于KVC,Cocoa自动放入和取出标量值(int,float和struct)放入NSNumber或NSValue中;当使用-setValue:ForKey:时,它自动将标量值从这些对象中取出。仅KVC具有这种自动包装功能,常规方法调用和属性语法不具备该功能。

@@ -161,129 +207,109 @@

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@implementation Sark
- (void)willChangeValueForKey:(NSString *)key
{
NSLog(@"%@", NSStringFromSelector(_cmd));
[super willChangeValueForKey:key];
}
- (void)didChangeValueForKey:(NSString *)key
{
NSLog(@"%@", NSStringFromSelector(_cmd));
[super didChangeValueForKey:key];
}
@end
- -

- -
- - - + +
+ + + + - -
+
+ + -
+ + -
+
+ + - - - -
+ - - - - - + + - - - - - + + + + + + + + + + + + + + - - - \ No newline at end of file + diff --git a/2015/05/04/2015-05-04-runtime-dui-xiang-mo-xing/index.html b/2015/05/04/2015-05-04-runtime-dui-xiang-mo-xing/index.html index 50e72c3..15e9b1b 100644 --- a/2015/05/04/2015-05-04-runtime-dui-xiang-mo-xing/index.html +++ b/2015/05/04/2015-05-04-runtime-dui-xiang-mo-xing/index.html @@ -1,11 +1,15 @@ + + - - - - - Objective-C Runtime(二) 对象模型 | CoderShmily's Blog - - + + + + + Objective-C Runtime(二) 对象模型 | CoderShmily's Blog + + + @@ -18,86 +22,128 @@ - - - - - - - - - - - - + + - -
-
- -
-
- -
+ -
- - -

- Objective-C Runtime(二) 对象模型 -

- + + + 首页 + + + + + +
+ +
+
+ + + +
+ + + +
+ +
- +
+ + +

-
- - -

Objective-C语言是一门动态语言,它将很多静态语言在编译和链接时期做的事放到了运行时来处理。这种动态语言的优势在于:我们写代码时更具灵活性,如我们可以把消息转发给我们想要的对象,或者随意交换一个方法的实现等。

+ Objective-C Runtime(二) 对象模型 +

+ + + +
+ +
+ +

Objective-C语言是一门动态语言,它将很多静态语言在编译和链接时期做的事放到了运行时来处理。这种动态语言的优势在于:我们写代码时更具灵活性,如我们可以把消息转发给我们想要的对象,或者随意交换一个方法的实现等。

这种特性意味着Objective-C不仅需要一个编译器,还需要一个运行时系统来执行编译的代码。对于Objective-C来说,这个运行时系统就像一个操作系统一样:它让所有的工作可以正常的运行。这个运行时系统即Objc Runtime。Objc Runtime其实是一个Runtime库,它基本上是用C和汇编写的,这个库使得C语言有了面向对象的能力。

Runtime库主要做下面几件事:

@@ -153,129 +199,109 @@

- Share - - - -

- - - + +
+ + + + - -
+
+ + -
+ + -
+
+ + - - - -
+ - - - - - + + - - - - - + + + + + + + + + + + + + + - - - \ No newline at end of file + diff --git a/2015/05/05/2015-05-05-runtime-gai-shu/index.html b/2015/05/05/2015-05-05-runtime-gai-shu/index.html index 7625bf0..37d2973 100644 --- a/2015/05/05/2015-05-05-runtime-gai-shu/index.html +++ b/2015/05/05/2015-05-05-runtime-gai-shu/index.html @@ -1,11 +1,15 @@ + + - - - - - Objective-C Runtime(一) 概述 | CoderShmily's Blog - - + + + + + + Objective-C Runtime(一) 概述 | CoderShmily's Blog + + + @@ -15,86 +19,128 @@ - - - - - - - - - - - - + + - -
-
- -
-
- -
+ -
- - -

- Objective-C Runtime(一) 概述 -

- + + + 首页 + + + + + +
+ +
+
+ + + +
+ + + +
+ +
- +
+ + +

-
- - -

Runtime常用方法和一些应用

+ Objective-C Runtime(一) 概述 +

+ + + +
+ +
+ +

Runtime常用方法和一些应用

Runtime方法列表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# class
class_getInstanceMethod -> Method class_getInstanceMethod(Class cls, SEL name);// 返回给定类的指定的实例方法
class_addMethod -> BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types);// 通过方法名SEL+原来的IMP实现给类添加新方法
class_copyPropertyList -> objc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount) // 获取类的属性列表
# method
method_getTypeEncoding -> const char *method_getTypeEncoding(Method m);// Returns a string describing a method's parameter and return types.
method_getImplementation -> IMP method_getImplementation(Method m);//获取Method中的IMP
method_exchangeImplementations -> method_exchangeImplementations(Method m1, Method m2); //Returns a string describing a method's parameter and return types.
method_setImplementation -> IMP method_setImplementation(Method m, IMP imp); // Sets the implementation of a method.
# 关联对象
objc_setAssociatedObject -> objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy);//Sets an associated value for a given object using a given key and association policy.
objc_getAssociatedObject -> id objc_getAssociatedObject(id object, const void *key);// Returns the value associated with a given object for a given key.
objc_removeAssociatedObjects -> objc_removeAssociatedObjects(id object);// 注意:Removes all associations for a given object.
# 类
object_isClass -> BOOL object_isClass(id obj);//Returns whether an object is a class object.
object_getClass -> Class object_getClass(id obj);//Returns the class of an object.
object_getClassName -> const char *object_getClassName(id obj);//Returns the class name of a given object.
object_setClass -> Class object_setClass(id obj, Class cls);//Sets the class of an object.
objc_getMetaClass -> Class objc_getMetaClass(const char *name);// 原类
# 实例变量
object_getIvar -> id object_getIvar(id obj, Ivar ivar);//Reads the value of an instance variable in an object.
object_setIvar -> object_setIvar(id obj, Ivar ivar, id value);//Sets the value of an instance variable in an object.
// Changes the value of an 实例变量 of a 实例
object_getInstanceVariable -> Ivar object_getInstanceVariable(id obj, const char *name, void **outValue)
object_setInstanceVariable -> Ivar object_setInstanceVariable(id obj, const char *name, void *value);
# 属性
property_getName -> const char *property_getName(objc_property_t property) // 传入上面的数组(指针)获取每个属性的名称
property_getAttributes -> const char *property_getAttributes(objc_property_t property) // 返回属性的名称和@encode类型字符串
# 发送消息
objc_msgSend -> objc_msgSend(id obj, SEL name);

获取列表(属性、方法、协议)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#import <objc/runtime.h>
unsigned int count;
//获取属性列表
objc_property_t *propertyList = class_copyPropertyList([self class], &count);
for (unsigned int i=0; i<count; i++) {
const char *propertyName = property_getName(propertyList[i]);
NSLog(@"property---->%@", [NSString stringWithUTF8String:propertyName]);
}
//获取方法列表
Method *methodList = class_copyMethodList([self class], &count);
for (unsigned int i; i<count; i++) {
Method method = methodList[i];
NSLog(@"method---->%@", NSStringFromSelector(method_getName(method)));
}
//获取成员变量列表
Ivar *ivarList = class_copyIvarList([self class], &count);
for (unsigned int i; i<count; i++) {
Ivar myIvar = ivarList[i];
const char *ivarName = ivar_getName(myIvar);
NSLog(@"Ivar---->%@", [NSString stringWithUTF8String:ivarName]);
}
//获取协议列表
__unsafe_unretained Protocol **protocolList = class_copyProtocolList([self class], &count);
for (unsigned int i; i<count; i++) {
Protocol *myProtocal = protocolList[i];
const char *protocolName = protocol_getName(myProtocal);
NSLog(@"protocol---->%@", [NSString stringWithUTF8String:protocolName]);
}
@@ -156,129 +202,109 @@
- Share - - - -
- - - + +
+ + + + - -
+
+ + -
+ + -
+
+ + - - - -
+ - - - - - + + - - - - - + + + + + + + + + + + + + + - - - \ No newline at end of file + diff --git a/2015/05/06/2015-05-06-objective-c-runtime-san-xiao-xi-chuan-di/index.html b/2015/05/06/2015-05-06-objective-c-runtime-san-xiao-xi-chuan-di/index.html index 3cb6222..dcac7be 100644 --- a/2015/05/06/2015-05-06-objective-c-runtime-san-xiao-xi-chuan-di/index.html +++ b/2015/05/06/2015-05-06-objective-c-runtime-san-xiao-xi-chuan-di/index.html @@ -1,11 +1,15 @@ + + - - - - - Objective-C Runtime(三) 消息传递 | CoderShmily's Blog - - + + + + + + Objective-C Runtime(三) 消息传递 | CoderShmily's Blog + + + @@ -15,86 +19,128 @@ - - - - - - - - - - - - + + - -
-
- -
-
- -
+ -
- - -

- Objective-C Runtime(三) 消息传递 -

- + + + 首页 + + + + + +
+ +
+
+ + + +
+ + + +
+ +
- +
+ + +

-
- - -

Objective-C Runtime的消息传递

+ Objective-C Runtime(三) 消息传递 +

+ + + +
+ +
+ +

Objective-C Runtime的消息传递

###Objective-C – 消息传递
Objective-C 扩展了 C 语言,并加入了面向对象特性和 Smalltalk 式的消息传递机制。而这个扩展的核心是一个用 C 和 编译语言 写的 Runtime 库。它是 Objective-C 面向对象和动态机制的基石.

Objective-C 是一个动态语言,这意味着它不仅需要一个编译器,也需要一个运行时系统来动态得创建类和对象、进行消息传递和转发。理解 Objective-C 的 Runtime 机制可以帮我们更好的了解这个语言,适当的时候还能对语言进行扩展,从系统层面解决项目中的一些设计或技术问题。了解 Runtime ,要先了解它的核心 - 消息传递(Messaging)。


@@ -138,129 +184,109 @@

- Share - - - -

- - - + +
+ + + + - -
+
+ + -
+ + -
+
+ + - - - -
+ - - - - - + + - - - - - + + + + + + + + + + + + + + - - - \ No newline at end of file + diff --git a/2015/05/07/2015-05-07-objective-c-runtime-si-dong-tai-fang-fa-jue-yi-dynamic-method-resolution/index.html b/2015/05/07/2015-05-07-objective-c-runtime-si-dong-tai-fang-fa-jue-yi-dynamic-method-resolution/index.html index ce200b3..a6412e6 100644 --- a/2015/05/07/2015-05-07-objective-c-runtime-si-dong-tai-fang-fa-jue-yi-dynamic-method-resolution/index.html +++ b/2015/05/07/2015-05-07-objective-c-runtime-si-dong-tai-fang-fa-jue-yi-dynamic-method-resolution/index.html @@ -1,11 +1,15 @@ + + - - - - - Objective-C Runtime(四) 动态方法决议 | CoderShmily's Blog - - + + + + + + Objective-C Runtime(四) 动态方法决议 | CoderShmily's Blog + + + @@ -15,86 +19,128 @@ - - - - - - - - - - - - + + - -
-
- -
-
- -
+ -
- - -

- Objective-C Runtime(四) 动态方法决议 -

- + + + 首页 + + + + + +
+ +
+
+ + + +
+ + + +
+ +
- +
+ + +

-
- - -

Objective-C Runtime之动态方法决议

+ Objective-C Runtime(四) 动态方法决议 +

+ + + +
+ +
+ +

Objective-C Runtime之动态方法决议

动态方法决议/动态方法解析(Dynamic Method Resolution)

@@ -156,129 +202,109 @@

总结 - -

- -
- - - + +
+ + + + - -
+
+ + -
+ + -
+
+ + - - - -
+ - - - - - + + - - - - - + + + + + + + + + + + + + + - - - \ No newline at end of file + diff --git a/2015/05/15/2015-05-15-sdwebimageyuan-ma-jie-xi/index.html b/2015/05/15/2015-05-15-sdwebimageyuan-ma-jie-xi/index.html index e813bcd..b80d2a2 100644 --- a/2015/05/15/2015-05-15-sdwebimageyuan-ma-jie-xi/index.html +++ b/2015/05/15/2015-05-15-sdwebimageyuan-ma-jie-xi/index.html @@ -1,11 +1,15 @@ + + - - - - - SDWebImage源码解析 | CoderShmily's Blog - - + + + + + + SDWebImage源码解析 | CoderShmily's Blog + + + @@ -15,212 +19,234 @@ - - - - - - - - - - - - + + - -
-
- -
-
- -
- - -
- - -

- SDWebImage源码解析 -

- - -
- -
- - -

SDWebImage源码解析

-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#import "SDWebImageCompat.h"
#import "SDWebImageOperation.h"
#import "SDWebImageDownloader.h"
#import "SDImageCache.h"
typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) {
/**
* By default, when a URL fail to be downloaded, the URL is blacklisted so the library won't keep trying.
* This flag disable this blacklisting.
*/
/**
*默认情况下,如果一个url在下载的时候失败了,那么这个url会被加入黑名单并且library不会尝试再次下载,这个flag会阻止library把失败的url加入黑名单(简单来说如果选择了这个flag,那么即使某个url下载失败了,sdwebimage还是会尝试再次下载他.)
*/
SDWebImageRetryFailed = 1 << 0,
/**
* By default, image downloads are started during UI interactions, this flags disable this feature,
* leading to delayed download on UIScrollView deceleration for instance.
*/
/**
*默认情况下,图片会在交互发生的时候下载(例如你滑动tableview的时候),这个flag会禁止这个特性,导致的结果就是在scrollview减速的时候
*才会开始下载(也就是你滑动的时候scrollview不下载,你手从屏幕上移走,scrollview开始减速的时候才会开始下载图片)
*/
SDWebImageLowPriority = 1 << 1,
/**
* This flag disables on-disk caching
*/
/*
*这个flag禁止磁盘缓存,只有内存缓存
*/
SDWebImageCacheMemoryOnly = 1 << 2,
/**
* This flag enables progressive download, the image is displayed progressively during download as a browser would do.
* By default, the image is only displayed once completely downloaded.
*/
/*
*这个flag会在图片下载的时候就显示(就像你用浏览器浏览网页的时候那种图片下载,一截一截的显示(待确认))
*
*/
SDWebImageProgressiveDownload = 1 << 3,
/**
* Even if the image is cached, respect the HTTP response cache control, and refresh the image from remote location if needed.
* The disk caching will be handled by NSURLCache instead of SDWebImage leading to slight performance degradation.
* This option helps deal with images changing behind the same request URL, e.g. Facebook graph api profile pics.
* If a cached image is refreshed, the completion block is called once with the cached image and again with the final image.
*
* Use this flag only if you can't make your URLs static with embeded cache busting parameter.
*/
/*
*这个选项的意思看的不是很懂,大意是即使一个图片缓存了,还是会重新请求.并且缓存侧略依据NSURLCache而不是SDWebImage.
*
*/
SDWebImageRefreshCached = 1 << 4,
/**
* In iOS 4+, continue the download of the image if the app goes to background. This is achieved by asking the system for
* extra time in background to let the request finish. If the background task expires the operation will be cancelled.
*/
/*
*启动后台下载,加入你进入一个页面,有一张图片正在下载这时候你让app进入后台,图片还是会继续下载(这个估计要开backgroundfetch才有用)
*/
SDWebImageContinueInBackground = 1 << 5,
/**
* Handles cookies stored in NSHTTPCookieStore by setting
* NSMutableURLRequest.HTTPShouldHandleCookies = YES;
*/
/*
*可以控制存在NSHTTPCookieStore的cookies.(我没用过,等用过的人过来解释一下)
*/
SDWebImageHandleCookies = 1 << 6,
/**
* Enable to allow untrusted SSL ceriticates.
* Useful for testing purposes. Use with caution in production.
*/
/*
*允许不安全的SSL证书,在正式环境中慎用
*/
SDWebImageAllowInvalidSSLCertificates = 1 << 7,
/**
* By default, image are loaded in the order they were queued. This flag move them to
* the front of the queue and is loaded immediately instead of waiting for the current queue to be loaded (which
* could take a while).
*/
/*
*默认情况下,image在装载的时候是按照他们在队列中的顺序装载的(就是先进先出).这个flag会把他们移动到队列的前端,并且立刻装载
*而不是等到当前队列装载的时候再装载.
*/
SDWebImageHighPriority = 1 << 8,
/**
* By default, placeholder images are loaded while the image is loading. This flag will delay the loading
* of the placeholder image until after the image has finished loading.
*/
/*
*默认情况下,占位图会在图片下载的时候显示.这个flag开启会延迟占位图显示的时间,等到图片下载完成之后才会显示占位图.(等图片显示完了我干嘛还显示占位图?或许是我理解错了?)
*/
SDWebImageDelayPlaceholder = 1 << 9,
/**
* We usually don't call transformDownloadedImage delegate method on animated images,
* as most transformation code would mangle it.
* Use this flag to transform them anyway.
*/
/*
*是否transform图片(没用过,还要再看,但是据我估计,是否是图片有可能方向不对需要调整方向,例如采用iPhone拍摄的照片如果不纠正方向,那么图片是向左旋转90度的.可能很多人不知道iPhone的摄像头并不是竖直的,而是向左偏了90度.具体请google.)
*/
SDWebImageTransformAnimatedImage = 1 << 10,
};
typedef void(^SDWebImageCompletionBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL);
typedef void(^SDWebImageCompletionWithFinishedBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL);
typedef NSString *(^SDWebImageCacheKeyFilterBlock)(NSURL *url);
@class SDWebImageManager;
@protocol SDWebImageManagerDelegate <NSObject>
@optional
/**
* Controls which image should be downloaded when the image is not found in the cache.
*
* @param imageManager The current `SDWebImageManager`
* @param imageURL The url of the image to be downloaded
*
* @return Return NO to prevent the downloading of the image on cache misses. If not implemented, YES is implied.
*/
/*
*主要作用是当缓存里没有发现某张图片的缓存时,是否选择下载这张图片(默认是yes),可以选择no,那么sdwebimage在缓存中没有找到这张图片的时候不会选择下载
*/
- (BOOL)imageManager:(SDWebImageManager *)imageManager shouldDownloadImageForURL:(NSURL *)imageURL;
/**
* Allows to transform the image immediately after it has been downloaded and just before to cache it on disk and memory.
* NOTE: This method is called from a global queue in order to not to block the main thread.
*
* @param imageManager The current `SDWebImageManager`
* @param image The image to transform
* @param imageURL The url of the image to transform
*
* @return The transformed image object.
*/
/**
*在图片下载完成并且还没有加入磁盘缓存或者内存缓存的时候就transform这个图片.这个方法是在异步线程执行的,防治阻塞主线程.
*至于为什么在异步执行很简单,对一张图片纠正方向(也就是transform)是很耗资源的,一张2M大小的图片纠正方向你可以用instrument测试一下耗时.
*很恐怖
*/
- (UIImage *)imageManager:(SDWebImageManager *)imageManager transformDownloadedImage:(UIImage *)image withURL:(NSURL *)imageURL;
@end
/**
* The SDWebImageManager is the class behind the UIImageView+WebCache category and likes.
* It ties the asynchronous downloader (SDWebImageDownloader) with the image cache store (SDImageCache).
* You can use this class directly to benefit from web image downloading with caching in another context than
* a UIView.
*
* Here is a simple example of how to use SDWebImageManager:
*
* @code
SDWebImageManager *manager = [SDWebImageManager sharedManager];
[manager downloadImageWithURL:imageURL
options:0
progress:nil
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
if (image) {
// do something with image
}
}];
* @endcode
*/
/*
*这一段是阐述SDWebImageManager是干嘛的.其实UIImageView+WebCache这个category背后执行操作的就是这个SDWebImageManager.他会绑定一个下载器也就是SDWebImageDownloader和一个缓存SDImageCache.后面的大意应该是讲你可以直接使用一个其他上下文环境的SDWebImageManager,而不是仅仅限于一个UIView.
*/
@interface SDWebImageManager : NSObject
@property (weak, nonatomic) id <SDWebImageManagerDelegate> delegate;
/**
*如同上文所说,一个SDWebImageManager会绑定一个imageCache和一个下载器.
*/
@property (strong, nonatomic, readonly) SDImageCache *imageCache;
@property (strong, nonatomic, readonly) SDWebImageDownloader *imageDownloader;
/**
* The cache filter is a block used each time SDWebImageManager need to convert an URL into a cache key. This can
* be used to remove dynamic part of an image URL.
*
* The following example sets a filter in the application delegate that will remove any query-string from the
* URL before to use it as a cache key:
*
* @code
[[SDWebImageManager sharedManager] setCacheKeyFilter:^(NSURL *url) {
url = [[NSURL alloc] initWithScheme:url.scheme host:url.host path:url.path];
return [url absoluteString];
}];
* @endcode
*/
/*
* 这个cacheKeyFilter是干嘛的呢?很简单.1他是一个block.2.这个block的作用就是生成一个image的key.因为sdwebimage的缓存原理你可以当成是一个字典,每一个字典的value就是一张image,那么这个value对应的key是什么呢?就是cacheKeyFilter根据某个规则对这个图片的url做一些操作生成的.上面的示例就显示了怎么利用这个block把image的url重新组合生成一个key.以后当sdwebimage检测到你
*/
@property (nonatomic, copy) SDWebImageCacheKeyFilterBlock cacheKeyFilter;
/**
* Returns global SDWebImageManager instance.
*
* @return SDWebImageManager shared instance
*/
/*
*这个不用我解释了吧,生成一个SDWebImagemanager的单例.
*/
+ (SDWebImageManager *)sharedManager;
/**
* Downloads the image at the given URL if not present in cache or return the cached version otherwise.
* 从给定的URL中下载一个之前没有被缓存的Image.
*
* @param url The URL to the image
* @param options A mask to specify options to use for this request
* @param progressBlock A block called while image is downloading
* @param completedBlock A block called when operation has been completed.
*
* This parameter is required.
*
* This block has no return value and takes the requested UIImage as first parameter.
* In case of error the image parameter is nil and the second parameter may contain an NSError.
*
* The third parameter is an `SDImageCacheType` enum indicating if the image was retrived from the local cache
* or from the memory cache or from the network.
*
* The last parameter is set to NO when the SDWebImageProgressiveDownload option is used and the image is
* downloading. This block is thus called repetidly with a partial image. When image is fully downloaded, the
* block is called a last time with the full image and the last parameter set to YES.
*
* @return Returns an NSObject conforming to SDWebImageOperation. Should be an instance of SDWebImageDownloaderOperation
*/
/*
* 这个方法主要就是SDWebImage下载图片的方法了.
* 第一个参数是必须要的,就是image的url
* 第二个参数就是我们上面的Options,你可以定制化各种各样的操作.详情参上.
* 第三个参数是一个回调block,用于图片在下载过程中的回调.(英文注释应该是有问题的.)
* 第四个参数是一个下载完成的回调.会在图片下载完成后回调.
* 返回值是一个NSObject类,并且这个NSObject类是conforming一个协议这个协议叫做SDWebImageOperation,这个协议很简单,就是一个cancel掉operation的协议.
*/
- (id <SDWebImageOperation>)downloadImageWithURL:(NSURL *)url
options:(SDWebImageOptions)options
progress:(SDWebImageDownloaderProgressBlock)progressBlock
completed:(SDWebImageCompletionWithFinishedBlock)completedBlock;
/**
* Saves image to cache for given URL
*
* @param image The image to cache
* @param url The URL to the image
*
*/
/*
* 将图片存入cache的方法,类似于字典的setValue: forKey:
*/
- (void)saveImageToCache:(UIImage *)image forURL:(NSURL *)url;
/**
* Cancel all current opreations
*/
/*
*取消掉当前所有的下载图片的operation
*/
- (void)cancelAll;
/**
* Check one or more operations running
*/
/*
* check一下是否有一个或者多个operation正在执行(简单来说就是check是否有图片在下载)
*/
- (BOOL)isRunning;
/**
* Check if image has already been cached
*
* @param url image url
*
* @return if the image was already cached
*/
/*
* 通过一个image的url是否已经存在,如果存在返回yes,否则返回no
*/
- (BOOL)cachedImageExistsForURL:(NSURL *)url;
/**
* Check if image has already been cached on disk only
*
* @param url image url
*
* @return if the image was already cached (disk only)
*/
/*
* 检测一个image是否已经被缓存到磁盘(是否存且仅存在disk里).
*/
- (BOOL)diskImageExistsForURL:(NSURL *)url;
/**
* Async check if image has already been cached
*
* @param url image url
* @param completionBlock the block to be executed when the check is finished
*
* @note the completion block is always executed on the main queue
*/
/*
* 如果检测到图片已经被缓存,那么执行回调block.这个block会永远执行在主线程.也就是你可以在这个回调block里更新ui.
*/
- (void)cachedImageExistsForURL:(NSURL *)url
completion:(SDWebImageCheckCacheCompletionBlock)completionBlock;
/**
* Async check if image has already been cached on disk only
*
* @param url image url
* @param completionBlock the block to be executed when the check is finished
*
* @note the completion block is always executed on the main queue
*/
/*
* 如果检测到图片已经被缓存在磁盘(存且仅存在disk),那么执行回调block.这个block会永远执行在主线程.也就是你可以在这个回调block里更新ui.
*/
- (void)diskImageExistsForURL:(NSURL *)url
completion:(SDWebImageCheckCacheCompletionBlock)completionBlock;
/**
*Return the cache key for a given URL
*/
/*
* 通过image的url返回image存在缓存里的key.有人会问了,为什么不直接把图片的url当做image的key来使用呢?而是非要对url做一些处理才能当做key.我的解释是,我也不太清楚.可能为了防止重复吧.
*/
- (NSString *)cacheKeyForURL:(NSURL *)url;
@end
#pragma mark - Deprecated
typedef void(^SDWebImageCompletedBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType) __deprecated_msg("Block type deprecated. Use `SDWebImageCompletionBlock`");
typedef void(^SDWebImageCompletedWithFinishedBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished) __deprecated_msg("Block type deprecated. Use `SDWebImageCompletionWithFinishedBlock`");
// 已被废弃
@interface SDWebImageManager (Deprecated)
/**
* Downloads the image at the given URL if not present in cache or return the cached version otherwise.
*
* @deprecated This method has been deprecated. Use `downloadImageWithURL:options:progress:completed:`
*/
- (id <SDWebImageOperation>)downloadWithURL:(NSURL *)url
options:(SDWebImageOptions)options
progress:(SDWebImageDownloaderProgressBlock)progressBlock
completed:(SDWebImageCompletedWithFinishedBlock)completedBlock __deprecated_msg("Method deprecated. Use `downloadImageWithURL:options:progress:completed:`");
@end
-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
#import <Foundation/Foundation.h>
/*
* This file is part of the SDWebImage package.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#import "SDWebImageManager.h"
#import <objc/message.h>
// 内部类.
@interface SDWebImageCombinedOperation : NSObject <SDWebImageOperation>
@property (assign, nonatomic, getter = isCancelled) BOOL cancelled;
@property (copy, nonatomic) SDWebImageNoParamsBlock cancelBlock;
@property (strong, nonatomic) NSOperation *cacheOperation;
@end
@interface SDWebImageManager ()
@property (strong, nonatomic, readwrite) SDImageCache *imageCache;
@property (strong, nonatomic, readwrite) SDWebImageDownloader *imageDownloader;
@property (strong, nonatomic) NSMutableSet *failedURLs;
@property (strong, nonatomic) NSMutableArray *runningOperations;
@end
@implementation SDWebImageManager
// 利用disptach_once 特性生成一个单例,用烂了的方法.不赘述.
+ (id)sharedManager {
static dispatch_once_t once;
static id instance;
dispatch_once(&once, ^{
instance = [self new];
});
return instance;
}
// 初始化方法.
// 1.获得一个SDImageCache的单例.2.获取一个SDWebImageDownloader的单例.3.新建一个MutableSet来存储下载失败的url.
// 4.新建一个用来存储下载operation的可变数组.
// 为什么不用MutableArray储存下载失败的URL?
// 因为NSSet类有一个特性,就是Hash.实际上NSSet是一个哈希表,哈希表比数组优秀的地方是什么呢?就是查找速度快.查找同样一个元素,哈希表只需要通过key
// 即可取到,而数组至少需要遍历依次.因为SDWebImage里有关失败URL的业务需求是,一个失败的URL只需要储存一次.这样的话Set自然比Array更合适.
- (id)init {
if ((self = [super init])) {
_imageCache = [self createCache];
_imageDownloader = [SDWebImageDownloader sharedDownloader];
_failedURLs = [NSMutableSet new];
_runningOperations = [NSMutableArray new];
}
return self;
}
// 获取一个cache的单例
- (SDImageCache *)createCache {
return [SDImageCache sharedImageCache];
}
// 利用Image的URL生成一个缓存时需要的key.
// 这里有两种情况,第一种是如果检测到cacheKeyFilter不为空时,利用cacheKeyFilter来处理URL生成一个key.
// 如果为空,那么直接返回URL的string内容,当做key.
- (NSString *)cacheKeyForURL:(NSURL *)url {
if (self.cacheKeyFilter) {
return self.cacheKeyFilter(url);
}
else {
return [url absoluteString];
}
}
// 检测一张图片是否已被缓存.
// 首先检测内存缓存是否存在这张图片,如果已有,直接返回yes.
// 如果内存缓存里没有这张图片,那么调用diskImageExistsWithKey这个方法去硬盘缓存里找
- (BOOL)cachedImageExistsForURL:(NSURL *)url {
NSString *key = [self cacheKeyForURL:url];
if ([self.imageCache imageFromMemoryCacheForKey:key] != nil) return YES;
return [self.imageCache diskImageExistsWithKey:key];
}
// 检测硬盘里是否缓存了图片
- (BOOL)diskImageExistsForURL:(NSURL *)url {
NSString *key = [self cacheKeyForURL:url];
return [self.imageCache diskImageExistsWithKey:key];
}
// 首先生成一个用来cache 住Image的key(利用key的url生成)
// 然后检测内存缓存里是否已经有这张图片
// 如果已经被缓存,那么再主线程里回调block
// 如果没有检测到,那么调用diskImageExistsWithKey,这个方法会在异步线程里,将图片存到硬盘,当然在存图之前也会检测是否已在硬盘缓存图片.
- (void)cachedImageExistsForURL:(NSURL *)url
completion:(SDWebImageCheckCacheCompletionBlock)completionBlock {
NSString *key = [self cacheKeyForURL:url];
BOOL isInMemoryCache = ([self.imageCache imageFromMemoryCacheForKey:key] != nil);
if (isInMemoryCache) {
// making sure we call the completion block on the main queue
dispatch_async(dispatch_get_main_queue(), ^{
if (completionBlock) {
completionBlock(YES);
}
});
return;
}
[self.imageCache diskImageExistsWithKey:key completion:^(BOOL isInDiskCache) {
// the completion block of checkDiskCacheForImageWithKey:completion: is always called on the main queue, no need to further dispatch
if (completionBlock) {
completionBlock(isInDiskCache);
}
}];
}
//将图片存入硬盘
- (void)diskImageExistsForURL:(NSURL *)url
completion:(SDWebImageCheckCacheCompletionBlock)completionBlock {
NSString *key = [self cacheKeyForURL:url];
[self.imageCache diskImageExistsWithKey:key completion:^(BOOL isInDiskCache) {
// the completion block of checkDiskCacheForImageWithKey:completion: is always called on the main queue, no need to further dispatch
if (completionBlock) {
completionBlock(isInDiskCache);
}
}];
}
// 通过url建立一个operation用来下载图片.
- (id <SDWebImageOperation>)downloadImageWithURL:(NSURL *)url
options:(SDWebImageOptions)options
progress:(SDWebImageDownloaderProgressBlock)progressBlock
completed:(SDWebImageCompletionWithFinishedBlock)completedBlock {
// Invoking this method without a completedBlock is pointless
NSAssert(completedBlock != nil, @"If you mean to prefetch the image, use -[SDWebImagePrefetcher prefetchURLs] instead");
// Very common mistake is to send the URL using NSString object instead of NSURL. For some strange reason, XCode won't
// throw any warning for this type mismatch. Here we failsafe this error by allowing URLs to be passed as NSString.
if ([url isKindOfClass:NSString.class]) {
url = [NSURL URLWithString:(NSString *)url];
}
// Prevents app crashing on argument type error like sending NSNull instead of NSURL
if (![url isKindOfClass:NSURL.class]) {
url = nil;
}
__block SDWebImageCombinedOperation *operation = [SDWebImageCombinedOperation new];
__weak SDWebImageCombinedOperation *weakOperation = operation;
BOOL isFailedUrl = NO;
// 创建一个互斥锁防止现在有别的线程修改failedURLs.
// 判断这个url是否是fail过的.如果url failed过的那么isFailedUrl就是true
@synchronized (self.failedURLs) {
isFailedUrl = [self.failedURLs containsObject:url];
}
// 如果url不存在那么直接返回一个block,如果url存在.那么继续进行判断.
// options与SDWebImageRetryFailed这个option进行按位与操作.判断用户的options里是否有retry这个option.
// 如果用户的options里没有retry这个选项并且isFaileUrl 是true.那么就回调一个error的block.
if (!url || (!(options & SDWebImageRetryFailed) && isFailedUrl)) {
dispatch_main_sync_safe(^{
NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorFileDoesNotExist userInfo:nil];
completedBlock(nil, error, SDImageCacheTypeNone, YES, url);
});
return operation;
}
// 创建一个互斥锁防止现在有别的线程修改runningOperations.
@synchronized (self.runningOperations) {
[self.runningOperations addObject:operation];
}
NSString *key = [self cacheKeyForURL:url];
// cacheOperation应该是一个用来下载图片并且缓存的operation
operation.cacheOperation = [self.imageCache queryDiskCacheForKey:key done:^(UIImage *image, SDImageCacheType cacheType) {
// 判断operation这时候有没有执行cancel操作,如果cancel掉了就把这个operation从我们的operation数组里remove掉然后return
if (operation.isCancelled) {
@synchronized (self.runningOperations) {
[self.runningOperations removeObject:operation];
}
return;
}
if ((!image || options & SDWebImageRefreshCached) && (![self.delegate respondsToSelector:@selector(imageManager:shouldDownloadImageForURL:)] || [self.delegate imageManager:self shouldDownloadImageForURL:url])) {
if (image && options & SDWebImageRefreshCached) {
dispatch_main_sync_safe(^{
// If image was found in the cache bug SDWebImageRefreshCached is provided, notify about the cached image
// AND try to re-download it in order to let a chance to NSURLCache to refresh it from server.
completedBlock(image, nil, cacheType, YES, url);
});
}
// download if no image or requested to refresh anyway, and download allowed by delegate
// 下面都是判断我们的options里包含哪些SDWebImageOptions,然后给我们的downloaderOptions相应的添加对应的SDWebImageDownloaderOptions. downloaderOptions |= SDWebImageDownloaderLowPriority这种表达式的意思等同于
// downloaderOptions = downloaderOptions | SDWebImageDownloaderLowPriority
SDWebImageDownloaderOptions downloaderOptions = 0;
if (options & SDWebImageLowPriority) downloaderOptions |= SDWebImageDownloaderLowPriority;
if (options & SDWebImageProgressiveDownload) downloaderOptions |= SDWebImageDownloaderProgressiveDownload;
if (options & SDWebImageRefreshCached) downloaderOptions |= SDWebImageDownloaderUseNSURLCache;
if (options & SDWebImageContinueInBackground) downloaderOptions |= SDWebImageDownloaderContinueInBackground;
if (options & SDWebImageHandleCookies) downloaderOptions |= SDWebImageDownloaderHandleCookies;
if (options & SDWebImageAllowInvalidSSLCertificates) downloaderOptions |= SDWebImageDownloaderAllowInvalidSSLCertificates;
if (options & SDWebImageHighPriority) downloaderOptions |= SDWebImageDownloaderHighPriority;
if (image && options & SDWebImageRefreshCached) {
// force progressive off if image already cached but forced refreshing
downloaderOptions &= ~SDWebImageDownloaderProgressiveDownload;
// ignore image read from NSURLCache if image if cached but force refreshing
downloaderOptions |= SDWebImageDownloaderIgnoreCachedResponse;
}
// 调用imageDownloader去下载image并且返回执行这个request的download的operation
id <SDWebImageOperation> subOperation = [self.imageDownloader downloadImageWithURL:url options:downloaderOptions progress:progressBlock completed:^(UIImage *downloadedImage, NSData *data, NSError *error, BOOL finished) {
if (weakOperation.isCancelled) {
// Do nothing if the operation was cancelled
// See #699 for more details
// if we would call the completedBlock, there could be a race condition between this block and another completedBlock for the same object, so if this one is called second, we will overwrite the new data
}
else if (error) {
dispatch_main_sync_safe(^{
if (!weakOperation.isCancelled) {
completedBlock(nil, error, SDImageCacheTypeNone, finished, url);
}
});
if (error.code != NSURLErrorNotConnectedToInternet && error.code != NSURLErrorCancelled && error.code != NSURLErrorTimedOut) {
@synchronized (self.failedURLs) {
[self.failedURLs addObject:url];
}
}
}
else {
if ((options & SDWebImageRetryFailed)) {
@synchronized (self.failedURLs) {
[self.failedURLs removeObject:url];
}
}
BOOL cacheOnDisk = !(options & SDWebImageCacheMemoryOnly);
if (options & SDWebImageRefreshCached && image && !downloadedImage) {
// Image refresh hit the NSURLCache cache, do not call the completion block
}
else if (downloadedImage && (!downloadedImage.images || (options & SDWebImageTransformAnimatedImage)) && [self.delegate respondsToSelector:@selector(imageManager:transformDownloadedImage:withURL:)]) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
UIImage *transformedImage = [self.delegate imageManager:self transformDownloadedImage:downloadedImage withURL:url];
if (transformedImage && finished) {
BOOL imageWasTransformed = ![transformedImage isEqual:downloadedImage];
[self.imageCache storeImage:transformedImage recalculateFromImage:imageWasTransformed imageData:data forKey:key toDisk:cacheOnDisk];
}
dispatch_main_sync_safe(^{
if (!weakOperation.isCancelled) {
completedBlock(transformedImage, nil, SDImageCacheTypeNone, finished, url);
}
});
});
}
else {
if (downloadedImage && finished) {
[self.imageCache storeImage:downloadedImage recalculateFromImage:NO imageData:data forKey:key toDisk:cacheOnDisk];
}
dispatch_main_sync_safe(^{
if (!weakOperation.isCancelled) {
completedBlock(downloadedImage, nil, SDImageCacheTypeNone, finished, url);
}
});
}
}
if (finished) {
@synchronized (self.runningOperations) {
[self.runningOperations removeObject:operation];
}
}
}];
operation.cancelBlock = ^{
[subOperation cancel];
@synchronized (self.runningOperations) {
[self.runningOperations removeObject:weakOperation];
}
};
}
else if (image) {
dispatch_main_sync_safe(^{
if (!weakOperation.isCancelled) {
completedBlock(image, nil, cacheType, YES, url);
}
});
@synchronized (self.runningOperations) {
[self.runningOperations removeObject:operation];
}
}
else {
// Image not in cache and download disallowed by delegate
dispatch_main_sync_safe(^{
if (!weakOperation.isCancelled) {
completedBlock(nil, nil, SDImageCacheTypeNone, YES, url);
}
});
@synchronized (self.runningOperations) {
[self.runningOperations removeObject:operation];
}
}
}];
return operation;
}
- (void)saveImageToCache:(UIImage *)image forURL:(NSURL *)url {
if (image && url) {
NSString *key = [self cacheKeyForURL:url];
[self.imageCache storeImage:image forKey:key toDisk:YES];
}
}
// cancel掉所有正在执行的operation
- (void)cancelAll {
@synchronized (self.runningOperations) {
NSArray *copiedOperations = [self.runningOperations copy];
[copiedOperations makeObjectsPerformSelector:@selector(cancel)];
[self.runningOperations removeObjectsInArray:copiedOperations];
}
}
// 判断是否有正在运行的operation
- (BOOL)isRunning {
return self.runningOperations.count > 0;
}
@end
@implementation SDWebImageCombinedOperation
- (void)setCancelBlock:(SDWebImageNoParamsBlock)cancelBlock {
// check if the operation is already cancelled, then we just call the cancelBlock
if (self.isCancelled) {
if (cancelBlock) {
cancelBlock();
}
_cancelBlock = nil; // don't forget to nil the cancelBlock, otherwise we will get crashes
} else {
_cancelBlock = [cancelBlock copy];
}
}
- (void)cancel {
self.cancelled = YES;
if (self.cacheOperation) {
[self.cacheOperation cancel];
self.cacheOperation = nil;
}
if (self.cancelBlock) {
self.cancelBlock();
// TODO: this is a temporary fix to #809.
// Until we can figure the exact cause of the crash, going with the ivar instead of the setter
// self.cancelBlock = nil;
_cancelBlock = nil;
}
}
@end
@implementation SDWebImageManager (Deprecated)
// deprecated method, uses the non deprecated method
// adapter for the completion block
- (id <SDWebImageOperation>)downloadWithURL:(NSURL *)url options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletedWithFinishedBlock)completedBlock {
return [self downloadImageWithURL:url
options:options
progress:progressBlock
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
if (completedBlock) {
completedBlock(image, error, cacheType, finished);
}
}];
}
@end
+ + - + - -
- - - - -
+
- - - -
-
- -
- + +
+ + +
+ +
+ + +
+ +
+ + +
- - + + + + + + + + + + + + + + + + + + + + + - + + - - + - - - \ No newline at end of file + diff --git a/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html b/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html index b4386ae..739d4f6 100644 --- a/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html +++ b/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html @@ -1,11 +1,15 @@ + + - - - - - Swift3.0学习笔记 | CoderShmily's Blog - - + + + + + + Swift3.0学习笔记 | CoderShmily's Blog + + + @@ -15,86 +19,128 @@ - - - - - - - - - - - - + + - -
-
- -
-
- -
+ -
- - -

- Swift3.0学习笔记 -

- + + + 首页 + + + + + +
+ +
+
+ + + +
+ + + +
- +
+ +
+ + +

-
- - -

总结一些 Swift3.0学习笔记

+ Swift3.0学习笔记 +

+ + + +
+ +
+ +

总结一些 Swift3.0学习笔记

Any AnyObject NSObject

Int Double String struct都是结构体

    @@ -206,120 +252,102 @@

    使用注意:需要使用public关键字修饰资源文建中,需要暴露给外界的内容

- -
- -
- - - + +
+ + + + - -
+
+ + -
+ + -
+
+ + - - -
-

最新文章

-
- + + + + +
-
+ - - - - - + + - - - - - + + + + + + + + + + + + + + - - - \ No newline at end of file + diff --git a/archives/2015/05/index.html b/archives/2015/05/index.html index ac4a70d..cb234a3 100644 --- a/archives/2015/05/index.html +++ b/archives/2015/05/index.html @@ -1,11 +1,15 @@ + + - - - - - 归档: 2015/5 | CoderShmily's Blog - - + + + + + + 归档: 5/2015: 2015 | CoderShmily's Blog + + + @@ -14,316 +18,275 @@ - - - - - - - - - - - - + + - -
-
- -
-
- - - - - -
-
- 2015 + + + + + + + + + +
- -
- - - - + - - + - - - - + - - - +
+ + + + KVC 和 KVO深入 + + + +
- - - - - -
- - - - - -
- + + - - - - - + + + + + + + + + + + + + + - - - \ No newline at end of file + diff --git a/archives/2015/index.html b/archives/2015/index.html index 667497a..69e60a2 100644 --- a/archives/2015/index.html +++ b/archives/2015/index.html @@ -1,11 +1,15 @@ + + - - - - - 归档: 2015 | CoderShmily's Blog - - + + + + + + 归档: 2015 | CoderShmily's Blog + + + @@ -14,316 +18,275 @@ - - - - - - - - - - - - + + - -
-
- -
-
- - - - - -
-
- 2015 + + + + + + + + + +
- -
- - - - + - - + - - - - + - - - +
+ + + + KVC 和 KVO深入 + + + +
- - - - - -
- - - - - -
- + + - - - - - + + + + + + + + + + + + + + - - - \ No newline at end of file + diff --git a/archives/2016/11/index.html b/archives/2016/11/index.html index 8e96047..6aec8d5 100644 --- a/archives/2016/11/index.html +++ b/archives/2016/11/index.html @@ -1,11 +1,15 @@ + + - - - - - 归档: 2016/11 | CoderShmily's Blog - - + + + + + + 归档: 11/2016: 2016 | CoderShmily's Blog + + + @@ -14,183 +18,191 @@ - - - - - - - - - - - - + + - -
-
- -
-
- - - - - -
-
- 2016 -
-
- - - - -
- + + -
- - - -
- +
+
- - - - - + + + + + + + + + + + + + + - - - \ No newline at end of file + diff --git a/archives/2016/index.html b/archives/2016/index.html index cbbead6..382c8e0 100644 --- a/archives/2016/index.html +++ b/archives/2016/index.html @@ -1,11 +1,15 @@ + + - - - - - 归档: 2016 | CoderShmily's Blog - - + + + + + + 归档: 2016 | CoderShmily's Blog + + + @@ -14,183 +18,191 @@ - - - - - - - - - - - - + + - -
-
- -
-
- - - - - -
-
- 2016 -
-
- - - - -
- + + -
- - - -
- +
+
- - - - - + + + + + + + + + + + + + + - - - \ No newline at end of file + diff --git a/archives/index.html b/archives/index.html index 6cfe37c..e99d13b 100644 --- a/archives/index.html +++ b/archives/index.html @@ -1,11 +1,15 @@ + + - - - - - 归档 | CoderShmily's Blog - - + + + + + + 归档 | CoderShmily's Blog + + + @@ -14,345 +18,204 @@ - - - - - - - - - - - - + + - -
-
- -
-
- - - - - - -
-
- 2016 -
-
- - - - - -
- - -
-
- 2015 + + + + + +
- -
- - - -
- +
+
- - - - - + + + + + + + + + + + + + + - - - \ No newline at end of file + diff --git a/categories/Swift/index.html b/categories/Swift/index.html index 669fe07..51110bb 100644 --- a/categories/Swift/index.html +++ b/categories/Swift/index.html @@ -1,11 +1,15 @@ + + - - - - - Category: Swift | CoderShmily's Blog - - + + + + + + 分类: Swift | CoderShmily's Blog + + + @@ -14,212 +18,196 @@ - - - - - - - - - - - - + + - -
-
- -
-
- - + + + +
-
-
- 2015 -
-
- -
- -
- - - -
- + - +
+
- - - - - + + + + + + + + + + + + + + - - - \ No newline at end of file + diff --git a/categories/iOS/index.html b/categories/iOS/index.html new file mode 100644 index 0000000..1758685 --- /dev/null +++ b/categories/iOS/index.html @@ -0,0 +1,268 @@ + + + + + + + + + 分类: iOS | CoderShmily's Blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
+

iOS

+ +
+ + + SDWebImage源码解析 + + + +
+ + + + + +
+ + + Objective-C Runtime(一) 概述 + + + +
+ + + +
+ + + KVC 和 KVO深入 + + + +
+ +
+ + + 单例模式的ARC和MRC实现 + + + +
+ +
+ + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + diff --git a/css/aloha.css b/css/aloha.css new file mode 100644 index 0000000..7492600 --- /dev/null +++ b/css/aloha.css @@ -0,0 +1,278 @@ +.post-content { + display: inline; +} +.post-content div { + padding-top: 10px; +} +footer { + bottom: 0; + background-color: #00B5AD; + height: 50px; +} +.main.container .article-footer { + margin-top: 20px; +} +.main.container .pagination { + margin-top: 40px; + margin-bottom: 40px; +} +.post-description .post-description-item { + padding-right: 10px; + height: 100%; + vertical-align: middle; +} +pre { + word-break: break-all; + word-wrap: break-word; +} +.tag-container .tagpage.header { + font-size: 30px; +} +.tag-container .ui.dividing.header { + vertical-align: middle; +} +#search-modal #search-results .highlight { + background-color: #c6e6f4; +} +#search-modal #search-results .search-result-tags { + padding-top: 5px; +} +#search-modal .algolia-logo { + float: right; +} +.sidebar-card { + padding: 10px; +} +#body .menu-buttons { + position: fixed; + z-index: 2147483647; + bottom: 20px; + left: 20px; +} +#body .body-content #content { + margin-top: 60px; +} +#sidebar-top .content { + position: relative; + background: #FFF; + margin: 1rem 0; + text-align: center; +} +.article-inner .post-description { + padding-top: 10px; +} +@media only screen and (max-width: 1200px) and (min-width: 768px) { + .nav-left { + text-align: right; + } + .nav-right { + text-align: left; + } +} +@media only screen and (min-width: 1200px) { + .nav-left { + text-align: right; + } + .nav-right { + text-align: left; + } +} +@media only screen and (max-width: 767px) { + .nav-left { + text-align: center; + } + .nav-right { + text-align: center; + } +} +#article-toc { + top: 55px; +} +.article-entry pre, +.article-entry code { + font-family: "Source Code Pro", Consolas, Monaco, Menlo, Consolas, monospace; +} +.article-entry code { + background: #eee; + text-shadow: 0 1px #fff; + padding: 0 0.3em; +} +.article-entry pre { + background: #2d2d2d; + margin-right: -20px; + margin-left: -20px; + padding: 15px 20px; + border-style: solid; + border-color: #ddd; + border-width: 1px 0; + overflow: auto; + color: #cccccc; + line-height: 22.4px; +} +.article-entry pre code { + background: none; + text-shadow: none; + padding: 0; +} +.article-entry .highlight { + background: #2d2d2d; + margin-right: -20px; + margin-left: -20px; + padding: 15px 20px; + border-style: solid; + border-color: #ddd; + border-width: 1px 0; + overflow: auto; + color: #cccccc; + line-height: 22.4px; + margin-right: 0; + margin-left: 0; +} +.article-entry .highlight pre { + border: none; + margin: 0; + padding: 0; +} +.article-entry .highlight table { + margin: 0; + width: auto; +} +.article-entry .highlight td { + border: none; + padding: 0; +} +.article-entry .highlight figcaption { + font-size: 0.85em; + color: #999999; + line-height: 1em; + margin-bottom: 1em; +} +.article-entry .highlight figcaption:before, +.article-entry .highlight figcaption:after { + content: " "; + /* 1 */ + display: table; + /* 2 */ +} +.article-entry .highlight figcaption:after { + clear: both; +} +.article-entry .highlight figcaption a { + float: right; +} +.article-entry .highlight .gutter pre { + color: #666; + font-size: 0.85em; + text-align: right; + padding-right: 20px; +} +.article-entry .highlight .line { + height: 22.4px; +} +.article-entry .highlight .line.marked { + background: #515151; +} +.article-entry .gist { + margin: 0 -20px; + border-style: solid; + border-color: #ddd; + border-width: 1px 0; + background: #2d2d2d; + padding: 15px 20px 15px 0; +} +.article-entry .gist .gist-file { + border: none; + font-family: "Source Code Pro", Consolas, Monaco, Menlo, Consolas, monospace; + margin: 0; +} +.article-entry .gist .gist-file .gist-data { + background: none; + border: none; +} +.article-entry .gist .gist-file .gist-data .line-numbers { + color: #666; + font-size: 0.85em; + background: none; + border: none; + padding: 0 20px 0 0; +} +.article-entry .gist .gist-file .gist-data .line-data { + padding: 0 !important; +} +.article-entry .gist .gist-file .highlight { + margin: 0; + padding: 0; + border: none; +} +.article-entry .gist .gist-file .gist-meta { + background: #2d2d2d; + color: #999999; + font: 0.85em -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; + text-shadow: 0 0; + padding: 0; + margin-top: 1em; + margin-left: 20px; +} +.article-entry .gist .gist-file .gist-meta a { + color: #258fb8; + font-weight: normal; +} +.article-entry .gist .gist-file .gist-meta a:hover { + text-decoration: underline; +} +pre .comment, +pre .title { + color: #999999; +} +pre .variable, +pre .attribute, +pre .tag, +pre .regexp, +pre .ruby .constant, +pre .xml .tag .title, +pre .xml .pi, +pre .xml .doctype, +pre .html .doctype, +pre .css .id, +pre .css .class, +pre .css .pseudo { + color: #f2777a; +} +pre .number, +pre .preprocessor, +pre .built_in, +pre .literal, +pre .params, +pre .constant { + color: #f99157; +} +pre .class, +pre .ruby .class .title, +pre .css .rules .attribute { + color: #99cc99; +} +pre .string, +pre .value, +pre .inheritance, +pre .header, +pre .ruby .symbol, +pre .xml .cdata { + color: #99cc99; +} +pre .css .hexcolor { + color: #66cccc; +} +pre .function, +pre .python .decorator, +pre .python .title, +pre .ruby .function .title, +pre .ruby .title .keyword, +pre .perl .sub, +pre .javascript .title, +pre .coffeescript .title { + color: #6699cc; +} +pre .keyword, +pre .javascript .function { + color: #cc99cc; +} diff --git a/css/aloha.less b/css/aloha.less new file mode 100644 index 0000000..df913c4 --- /dev/null +++ b/css/aloha.less @@ -0,0 +1,2 @@ +@import "_partial/main"; +@import "_partial/highlight"; \ No newline at end of file diff --git a/css/fonts/FontAwesome.otf b/css/fonts/FontAwesome.otf deleted file mode 100644 index 8b0f54e47e1d356dcf1496942a50e228e0f1ee14..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 62856 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

- - - -
- -
- -

特色

+ + +
- - - - - - - - + + - + + + + + + - - - - - +
+ +
+ +
+
+ + + + + + - - - - - - - - - - + - + - + \ No newline at end of file diff --git a/2015/05/02/2015-05-02-singleton/index.html b/2015/05/02/2015-05-02-singleton/index.html index 0f4c8ec..3bcc891 100644 --- a/2015/05/02/2015-05-02-singleton/index.html +++ b/2015/05/02/2015-05-02-singleton/index.html @@ -1,15 +1,11 @@ - - - - - - - - 单例模式的ARC和MRC实现 | CoderShmily's Blog - - - + + + + + 单例模式的ARC和MRC实现 | CoderShmily's Blog + + @@ -19,128 +15,50 @@ - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + - - - - - - - - + + - + + + + + + - - - - - +
+ +
+ +
+
+ + + + + + - - - - - - - - - - + - + - + \ No newline at end of file diff --git a/2015/05/03/2015-05-03-kvc-he-kvoshen-ru/index.html b/2015/05/03/2015-05-03-kvc-he-kvoshen-ru/index.html index 502442d..7c56a5e 100644 --- a/2015/05/03/2015-05-03-kvc-he-kvoshen-ru/index.html +++ b/2015/05/03/2015-05-03-kvc-he-kvoshen-ru/index.html @@ -1,15 +1,11 @@ - - - - - - - - KVC 和 KVO深入 | CoderShmily's Blog - - - + + + + + KVC 和 KVO深入 | CoderShmily's Blog + + @@ -19,128 +15,50 @@ - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + - - - - - - - - - + + - + + + + + + - - - - - +
+ +
+ +
+
+ + + + + + - - - - - - - - - - + - + - + \ No newline at end of file diff --git a/2015/05/04/2015-05-04-runtime-dui-xiang-mo-xing/index.html b/2015/05/04/2015-05-04-runtime-dui-xiang-mo-xing/index.html index 15e9b1b..f451c33 100644 --- a/2015/05/04/2015-05-04-runtime-dui-xiang-mo-xing/index.html +++ b/2015/05/04/2015-05-04-runtime-dui-xiang-mo-xing/index.html @@ -1,15 +1,11 @@ - - - - - - - - Objective-C Runtime(二) 对象模型 | CoderShmily's Blog - - - + + Objective-C Runtime(二) 对象模型 | CoderShmily's Blog + + @@ -22,128 +18,50 @@ - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + - - - - - - - - + + - + + + + + + - - - - - +
+ +
+ +
+
+ + + + + + - - - - - - - - - - + - + - + \ No newline at end of file diff --git a/2015/05/05/2015-05-05-runtime-gai-shu/index.html b/2015/05/05/2015-05-05-runtime-gai-shu/index.html index 37d2973..b2e97e7 100644 --- a/2015/05/05/2015-05-05-runtime-gai-shu/index.html +++ b/2015/05/05/2015-05-05-runtime-gai-shu/index.html @@ -1,15 +1,11 @@ - - - - - - - - Objective-C Runtime(一) 概述 | CoderShmily's Blog - - - + + + + + Objective-C Runtime(一) 概述 | CoderShmily's Blog + + @@ -19,128 +15,50 @@ - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + - - - - - - - - + + - + + + + + + - - - - - +
+ +
+ +
+
+ + + + + + - - - - - - - - - - + - + - + \ No newline at end of file diff --git a/2015/05/06/2015-05-06-objective-c-runtime-san-xiao-xi-chuan-di/index.html b/2015/05/06/2015-05-06-objective-c-runtime-san-xiao-xi-chuan-di/index.html index dcac7be..a2bfbd1 100644 --- a/2015/05/06/2015-05-06-objective-c-runtime-san-xiao-xi-chuan-di/index.html +++ b/2015/05/06/2015-05-06-objective-c-runtime-san-xiao-xi-chuan-di/index.html @@ -1,15 +1,11 @@ - - - - - - - - Objective-C Runtime(三) 消息传递 | CoderShmily's Blog - - - + + + + + Objective-C Runtime(三) 消息传递 | CoderShmily's Blog + + @@ -19,128 +15,50 @@ - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + - - - - - - - - + + - + + + + + + - - - - - +
+ +
+ +
+
+ + + + + + - - - - - - - - - - + - + - + \ No newline at end of file diff --git a/2015/05/07/2015-05-07-objective-c-runtime-si-dong-tai-fang-fa-jue-yi-dynamic-method-resolution/index.html b/2015/05/07/2015-05-07-objective-c-runtime-si-dong-tai-fang-fa-jue-yi-dynamic-method-resolution/index.html index a6412e6..fb365e2 100644 --- a/2015/05/07/2015-05-07-objective-c-runtime-si-dong-tai-fang-fa-jue-yi-dynamic-method-resolution/index.html +++ b/2015/05/07/2015-05-07-objective-c-runtime-si-dong-tai-fang-fa-jue-yi-dynamic-method-resolution/index.html @@ -1,15 +1,11 @@ - - - - - - - - Objective-C Runtime(四) 动态方法决议 | CoderShmily's Blog - - - + + + + + Objective-C Runtime(四) 动态方法决议 | CoderShmily's Blog + + @@ -19,128 +15,50 @@ - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + - - - - - - -
- -
- -
  1. 加入消息转发
  2. 总结
-
- -
- + + - + + + + + + - - - - - +
+ +
+ +
+
+ + + + + + - - - - - - - - - - + - + - + \ No newline at end of file diff --git a/2015/05/15/2015-05-15-sdwebimageyuan-ma-jie-xi/index.html b/2015/05/15/2015-05-15-sdwebimageyuan-ma-jie-xi/index.html index b80d2a2..6ed1eac 100644 --- a/2015/05/15/2015-05-15-sdwebimageyuan-ma-jie-xi/index.html +++ b/2015/05/15/2015-05-15-sdwebimageyuan-ma-jie-xi/index.html @@ -1,15 +1,11 @@ - - - - - - - - SDWebImage源码解析 | CoderShmily's Blog - - - + + + + + SDWebImage源码解析 | CoderShmily's Blog + + @@ -19,234 +15,179 @@ + + + + + + + + + + + - - - + +
+
+ +
+
+ +
- - - - - +
- - - - - - - - - - - - + +

+ SDWebImage源码解析 +

+ -
+ +
+ +

SDWebImage源码解析

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#import "SDWebImageCompat.h"
#import "SDWebImageOperation.h"
#import "SDWebImageDownloader.h"
#import "SDImageCache.h"
typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) {
/**
* By default, when a URL fail to be downloaded, the URL is blacklisted so the library won't keep trying.
* This flag disable this blacklisting.
*/
/**
*默认情况下,如果一个url在下载的时候失败了,那么这个url会被加入黑名单并且library不会尝试再次下载,这个flag会阻止library把失败的url加入黑名单(简单来说如果选择了这个flag,那么即使某个url下载失败了,sdwebimage还是会尝试再次下载他.)
*/
SDWebImageRetryFailed = 1 << 0,
/**
* By default, image downloads are started during UI interactions, this flags disable this feature,
* leading to delayed download on UIScrollView deceleration for instance.
*/
/**
*默认情况下,图片会在交互发生的时候下载(例如你滑动tableview的时候),这个flag会禁止这个特性,导致的结果就是在scrollview减速的时候
*才会开始下载(也就是你滑动的时候scrollview不下载,你手从屏幕上移走,scrollview开始减速的时候才会开始下载图片)
*/
SDWebImageLowPriority = 1 << 1,
/**
* This flag disables on-disk caching
*/
/*
*这个flag禁止磁盘缓存,只有内存缓存
*/
SDWebImageCacheMemoryOnly = 1 << 2,
/**
* This flag enables progressive download, the image is displayed progressively during download as a browser would do.
* By default, the image is only displayed once completely downloaded.
*/
/*
*这个flag会在图片下载的时候就显示(就像你用浏览器浏览网页的时候那种图片下载,一截一截的显示(待确认))
*
*/
SDWebImageProgressiveDownload = 1 << 3,
/**
* Even if the image is cached, respect the HTTP response cache control, and refresh the image from remote location if needed.
* The disk caching will be handled by NSURLCache instead of SDWebImage leading to slight performance degradation.
* This option helps deal with images changing behind the same request URL, e.g. Facebook graph api profile pics.
* If a cached image is refreshed, the completion block is called once with the cached image and again with the final image.
*
* Use this flag only if you can't make your URLs static with embeded cache busting parameter.
*/
/*
*这个选项的意思看的不是很懂,大意是即使一个图片缓存了,还是会重新请求.并且缓存侧略依据NSURLCache而不是SDWebImage.
*
*/
SDWebImageRefreshCached = 1 << 4,
/**
* In iOS 4+, continue the download of the image if the app goes to background. This is achieved by asking the system for
* extra time in background to let the request finish. If the background task expires the operation will be cancelled.
*/
/*
*启动后台下载,加入你进入一个页面,有一张图片正在下载这时候你让app进入后台,图片还是会继续下载(这个估计要开backgroundfetch才有用)
*/
SDWebImageContinueInBackground = 1 << 5,
/**
* Handles cookies stored in NSHTTPCookieStore by setting
* NSMutableURLRequest.HTTPShouldHandleCookies = YES;
*/
/*
*可以控制存在NSHTTPCookieStore的cookies.(我没用过,等用过的人过来解释一下)
*/
SDWebImageHandleCookies = 1 << 6,
/**
* Enable to allow untrusted SSL ceriticates.
* Useful for testing purposes. Use with caution in production.
*/
/*
*允许不安全的SSL证书,在正式环境中慎用
*/
SDWebImageAllowInvalidSSLCertificates = 1 << 7,
/**
* By default, image are loaded in the order they were queued. This flag move them to
* the front of the queue and is loaded immediately instead of waiting for the current queue to be loaded (which
* could take a while).
*/
/*
*默认情况下,image在装载的时候是按照他们在队列中的顺序装载的(就是先进先出).这个flag会把他们移动到队列的前端,并且立刻装载
*而不是等到当前队列装载的时候再装载.
*/
SDWebImageHighPriority = 1 << 8,
/**
* By default, placeholder images are loaded while the image is loading. This flag will delay the loading
* of the placeholder image until after the image has finished loading.
*/
/*
*默认情况下,占位图会在图片下载的时候显示.这个flag开启会延迟占位图显示的时间,等到图片下载完成之后才会显示占位图.(等图片显示完了我干嘛还显示占位图?或许是我理解错了?)
*/
SDWebImageDelayPlaceholder = 1 << 9,
/**
* We usually don't call transformDownloadedImage delegate method on animated images,
* as most transformation code would mangle it.
* Use this flag to transform them anyway.
*/
/*
*是否transform图片(没用过,还要再看,但是据我估计,是否是图片有可能方向不对需要调整方向,例如采用iPhone拍摄的照片如果不纠正方向,那么图片是向左旋转90度的.可能很多人不知道iPhone的摄像头并不是竖直的,而是向左偏了90度.具体请google.)
*/
SDWebImageTransformAnimatedImage = 1 << 10,
};
typedef void(^SDWebImageCompletionBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL);
typedef void(^SDWebImageCompletionWithFinishedBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL);
typedef NSString *(^SDWebImageCacheKeyFilterBlock)(NSURL *url);
@class SDWebImageManager;
@protocol SDWebImageManagerDelegate <NSObject>
@optional
/**
* Controls which image should be downloaded when the image is not found in the cache.
*
* @param imageManager The current `SDWebImageManager`
* @param imageURL The url of the image to be downloaded
*
* @return Return NO to prevent the downloading of the image on cache misses. If not implemented, YES is implied.
*/
/*
*主要作用是当缓存里没有发现某张图片的缓存时,是否选择下载这张图片(默认是yes),可以选择no,那么sdwebimage在缓存中没有找到这张图片的时候不会选择下载
*/
- (BOOL)imageManager:(SDWebImageManager *)imageManager shouldDownloadImageForURL:(NSURL *)imageURL;
/**
* Allows to transform the image immediately after it has been downloaded and just before to cache it on disk and memory.
* NOTE: This method is called from a global queue in order to not to block the main thread.
*
* @param imageManager The current `SDWebImageManager`
* @param image The image to transform
* @param imageURL The url of the image to transform
*
* @return The transformed image object.
*/
/**
*在图片下载完成并且还没有加入磁盘缓存或者内存缓存的时候就transform这个图片.这个方法是在异步线程执行的,防治阻塞主线程.
*至于为什么在异步执行很简单,对一张图片纠正方向(也就是transform)是很耗资源的,一张2M大小的图片纠正方向你可以用instrument测试一下耗时.
*很恐怖
*/
- (UIImage *)imageManager:(SDWebImageManager *)imageManager transformDownloadedImage:(UIImage *)image withURL:(NSURL *)imageURL;
@end
/**
* The SDWebImageManager is the class behind the UIImageView+WebCache category and likes.
* It ties the asynchronous downloader (SDWebImageDownloader) with the image cache store (SDImageCache).
* You can use this class directly to benefit from web image downloading with caching in another context than
* a UIView.
*
* Here is a simple example of how to use SDWebImageManager:
*
* @code
SDWebImageManager *manager = [SDWebImageManager sharedManager];
[manager downloadImageWithURL:imageURL
options:0
progress:nil
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
if (image) {
// do something with image
}
}];
* @endcode
*/
/*
*这一段是阐述SDWebImageManager是干嘛的.其实UIImageView+WebCache这个category背后执行操作的就是这个SDWebImageManager.他会绑定一个下载器也就是SDWebImageDownloader和一个缓存SDImageCache.后面的大意应该是讲你可以直接使用一个其他上下文环境的SDWebImageManager,而不是仅仅限于一个UIView.
*/
@interface SDWebImageManager : NSObject
@property (weak, nonatomic) id <SDWebImageManagerDelegate> delegate;
/**
*如同上文所说,一个SDWebImageManager会绑定一个imageCache和一个下载器.
*/
@property (strong, nonatomic, readonly) SDImageCache *imageCache;
@property (strong, nonatomic, readonly) SDWebImageDownloader *imageDownloader;
/**
* The cache filter is a block used each time SDWebImageManager need to convert an URL into a cache key. This can
* be used to remove dynamic part of an image URL.
*
* The following example sets a filter in the application delegate that will remove any query-string from the
* URL before to use it as a cache key:
*
* @code
[[SDWebImageManager sharedManager] setCacheKeyFilter:^(NSURL *url) {
url = [[NSURL alloc] initWithScheme:url.scheme host:url.host path:url.path];
return [url absoluteString];
}];
* @endcode
*/
/*
* 这个cacheKeyFilter是干嘛的呢?很简单.1他是一个block.2.这个block的作用就是生成一个image的key.因为sdwebimage的缓存原理你可以当成是一个字典,每一个字典的value就是一张image,那么这个value对应的key是什么呢?就是cacheKeyFilter根据某个规则对这个图片的url做一些操作生成的.上面的示例就显示了怎么利用这个block把image的url重新组合生成一个key.以后当sdwebimage检测到你
*/
@property (nonatomic, copy) SDWebImageCacheKeyFilterBlock cacheKeyFilter;
/**
* Returns global SDWebImageManager instance.
*
* @return SDWebImageManager shared instance
*/
/*
*这个不用我解释了吧,生成一个SDWebImagemanager的单例.
*/
+ (SDWebImageManager *)sharedManager;
/**
* Downloads the image at the given URL if not present in cache or return the cached version otherwise.
* 从给定的URL中下载一个之前没有被缓存的Image.
*
* @param url The URL to the image
* @param options A mask to specify options to use for this request
* @param progressBlock A block called while image is downloading
* @param completedBlock A block called when operation has been completed.
*
* This parameter is required.
*
* This block has no return value and takes the requested UIImage as first parameter.
* In case of error the image parameter is nil and the second parameter may contain an NSError.
*
* The third parameter is an `SDImageCacheType` enum indicating if the image was retrived from the local cache
* or from the memory cache or from the network.
*
* The last parameter is set to NO when the SDWebImageProgressiveDownload option is used and the image is
* downloading. This block is thus called repetidly with a partial image. When image is fully downloaded, the
* block is called a last time with the full image and the last parameter set to YES.
*
* @return Returns an NSObject conforming to SDWebImageOperation. Should be an instance of SDWebImageDownloaderOperation
*/
/*
* 这个方法主要就是SDWebImage下载图片的方法了.
* 第一个参数是必须要的,就是image的url
* 第二个参数就是我们上面的Options,你可以定制化各种各样的操作.详情参上.
* 第三个参数是一个回调block,用于图片在下载过程中的回调.(英文注释应该是有问题的.)
* 第四个参数是一个下载完成的回调.会在图片下载完成后回调.
* 返回值是一个NSObject类,并且这个NSObject类是conforming一个协议这个协议叫做SDWebImageOperation,这个协议很简单,就是一个cancel掉operation的协议.
*/
- (id <SDWebImageOperation>)downloadImageWithURL:(NSURL *)url
options:(SDWebImageOptions)options
progress:(SDWebImageDownloaderProgressBlock)progressBlock
completed:(SDWebImageCompletionWithFinishedBlock)completedBlock;
/**
* Saves image to cache for given URL
*
* @param image The image to cache
* @param url The URL to the image
*
*/
/*
* 将图片存入cache的方法,类似于字典的setValue: forKey:
*/
- (void)saveImageToCache:(UIImage *)image forURL:(NSURL *)url;
/**
* Cancel all current opreations
*/
/*
*取消掉当前所有的下载图片的operation
*/
- (void)cancelAll;
/**
* Check one or more operations running
*/
/*
* check一下是否有一个或者多个operation正在执行(简单来说就是check是否有图片在下载)
*/
- (BOOL)isRunning;
/**
* Check if image has already been cached
*
* @param url image url
*
* @return if the image was already cached
*/
/*
* 通过一个image的url是否已经存在,如果存在返回yes,否则返回no
*/
- (BOOL)cachedImageExistsForURL:(NSURL *)url;
/**
* Check if image has already been cached on disk only
*
* @param url image url
*
* @return if the image was already cached (disk only)
*/
/*
* 检测一个image是否已经被缓存到磁盘(是否存且仅存在disk里).
*/
- (BOOL)diskImageExistsForURL:(NSURL *)url;
/**
* Async check if image has already been cached
*
* @param url image url
* @param completionBlock the block to be executed when the check is finished
*
* @note the completion block is always executed on the main queue
*/
/*
* 如果检测到图片已经被缓存,那么执行回调block.这个block会永远执行在主线程.也就是你可以在这个回调block里更新ui.
*/
- (void)cachedImageExistsForURL:(NSURL *)url
completion:(SDWebImageCheckCacheCompletionBlock)completionBlock;
/**
* Async check if image has already been cached on disk only
*
* @param url image url
* @param completionBlock the block to be executed when the check is finished
*
* @note the completion block is always executed on the main queue
*/
/*
* 如果检测到图片已经被缓存在磁盘(存且仅存在disk),那么执行回调block.这个block会永远执行在主线程.也就是你可以在这个回调block里更新ui.
*/
- (void)diskImageExistsForURL:(NSURL *)url
completion:(SDWebImageCheckCacheCompletionBlock)completionBlock;
/**
*Return the cache key for a given URL
*/
/*
* 通过image的url返回image存在缓存里的key.有人会问了,为什么不直接把图片的url当做image的key来使用呢?而是非要对url做一些处理才能当做key.我的解释是,我也不太清楚.可能为了防止重复吧.
*/
- (NSString *)cacheKeyForURL:(NSURL *)url;
@end
#pragma mark - Deprecated
typedef void(^SDWebImageCompletedBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType) __deprecated_msg("Block type deprecated. Use `SDWebImageCompletionBlock`");
typedef void(^SDWebImageCompletedWithFinishedBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished) __deprecated_msg("Block type deprecated. Use `SDWebImageCompletionWithFinishedBlock`");
// 已被废弃
@interface SDWebImageManager (Deprecated)
/**
* Downloads the image at the given URL if not present in cache or return the cached version otherwise.
*
* @deprecated This method has been deprecated. Use `downloadImageWithURL:options:progress:completed:`
*/
- (id <SDWebImageOperation>)downloadWithURL:(NSURL *)url
options:(SDWebImageOptions)options
progress:(SDWebImageDownloaderProgressBlock)progressBlock
completed:(SDWebImageCompletedWithFinishedBlock)completedBlock __deprecated_msg("Method deprecated. Use `downloadImageWithURL:options:progress:completed:`");
@end
+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
#import <Foundation/Foundation.h>
/*
* This file is part of the SDWebImage package.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#import "SDWebImageManager.h"
#import <objc/message.h>
// 内部类.
@interface SDWebImageCombinedOperation : NSObject <SDWebImageOperation>
@property (assign, nonatomic, getter = isCancelled) BOOL cancelled;
@property (copy, nonatomic) SDWebImageNoParamsBlock cancelBlock;
@property (strong, nonatomic) NSOperation *cacheOperation;
@end
@interface SDWebImageManager ()
@property (strong, nonatomic, readwrite) SDImageCache *imageCache;
@property (strong, nonatomic, readwrite) SDWebImageDownloader *imageDownloader;
@property (strong, nonatomic) NSMutableSet *failedURLs;
@property (strong, nonatomic) NSMutableArray *runningOperations;
@end
@implementation SDWebImageManager
// 利用disptach_once 特性生成一个单例,用烂了的方法.不赘述.
+ (id)sharedManager {
static dispatch_once_t once;
static id instance;
dispatch_once(&once, ^{
instance = [self new];
});
return instance;
}
// 初始化方法.
// 1.获得一个SDImageCache的单例.2.获取一个SDWebImageDownloader的单例.3.新建一个MutableSet来存储下载失败的url.
// 4.新建一个用来存储下载operation的可变数组.
// 为什么不用MutableArray储存下载失败的URL?
// 因为NSSet类有一个特性,就是Hash.实际上NSSet是一个哈希表,哈希表比数组优秀的地方是什么呢?就是查找速度快.查找同样一个元素,哈希表只需要通过key
// 即可取到,而数组至少需要遍历依次.因为SDWebImage里有关失败URL的业务需求是,一个失败的URL只需要储存一次.这样的话Set自然比Array更合适.
- (id)init {
if ((self = [super init])) {
_imageCache = [self createCache];
_imageDownloader = [SDWebImageDownloader sharedDownloader];
_failedURLs = [NSMutableSet new];
_runningOperations = [NSMutableArray new];
}
return self;
}
// 获取一个cache的单例
- (SDImageCache *)createCache {
return [SDImageCache sharedImageCache];
}
// 利用Image的URL生成一个缓存时需要的key.
// 这里有两种情况,第一种是如果检测到cacheKeyFilter不为空时,利用cacheKeyFilter来处理URL生成一个key.
// 如果为空,那么直接返回URL的string内容,当做key.
- (NSString *)cacheKeyForURL:(NSURL *)url {
if (self.cacheKeyFilter) {
return self.cacheKeyFilter(url);
}
else {
return [url absoluteString];
}
}
// 检测一张图片是否已被缓存.
// 首先检测内存缓存是否存在这张图片,如果已有,直接返回yes.
// 如果内存缓存里没有这张图片,那么调用diskImageExistsWithKey这个方法去硬盘缓存里找
- (BOOL)cachedImageExistsForURL:(NSURL *)url {
NSString *key = [self cacheKeyForURL:url];
if ([self.imageCache imageFromMemoryCacheForKey:key] != nil) return YES;
return [self.imageCache diskImageExistsWithKey:key];
}
// 检测硬盘里是否缓存了图片
- (BOOL)diskImageExistsForURL:(NSURL *)url {
NSString *key = [self cacheKeyForURL:url];
return [self.imageCache diskImageExistsWithKey:key];
}
// 首先生成一个用来cache 住Image的key(利用key的url生成)
// 然后检测内存缓存里是否已经有这张图片
// 如果已经被缓存,那么再主线程里回调block
// 如果没有检测到,那么调用diskImageExistsWithKey,这个方法会在异步线程里,将图片存到硬盘,当然在存图之前也会检测是否已在硬盘缓存图片.
- (void)cachedImageExistsForURL:(NSURL *)url
completion:(SDWebImageCheckCacheCompletionBlock)completionBlock {
NSString *key = [self cacheKeyForURL:url];
BOOL isInMemoryCache = ([self.imageCache imageFromMemoryCacheForKey:key] != nil);
if (isInMemoryCache) {
// making sure we call the completion block on the main queue
dispatch_async(dispatch_get_main_queue(), ^{
if (completionBlock) {
completionBlock(YES);
}
});
return;
}
[self.imageCache diskImageExistsWithKey:key completion:^(BOOL isInDiskCache) {
// the completion block of checkDiskCacheForImageWithKey:completion: is always called on the main queue, no need to further dispatch
if (completionBlock) {
completionBlock(isInDiskCache);
}
}];
}
//将图片存入硬盘
- (void)diskImageExistsForURL:(NSURL *)url
completion:(SDWebImageCheckCacheCompletionBlock)completionBlock {
NSString *key = [self cacheKeyForURL:url];
[self.imageCache diskImageExistsWithKey:key completion:^(BOOL isInDiskCache) {
// the completion block of checkDiskCacheForImageWithKey:completion: is always called on the main queue, no need to further dispatch
if (completionBlock) {
completionBlock(isInDiskCache);
}
}];
}
// 通过url建立一个operation用来下载图片.
- (id <SDWebImageOperation>)downloadImageWithURL:(NSURL *)url
options:(SDWebImageOptions)options
progress:(SDWebImageDownloaderProgressBlock)progressBlock
completed:(SDWebImageCompletionWithFinishedBlock)completedBlock {
// Invoking this method without a completedBlock is pointless
NSAssert(completedBlock != nil, @"If you mean to prefetch the image, use -[SDWebImagePrefetcher prefetchURLs] instead");
// Very common mistake is to send the URL using NSString object instead of NSURL. For some strange reason, XCode won't
// throw any warning for this type mismatch. Here we failsafe this error by allowing URLs to be passed as NSString.
if ([url isKindOfClass:NSString.class]) {
url = [NSURL URLWithString:(NSString *)url];
}
// Prevents app crashing on argument type error like sending NSNull instead of NSURL
if (![url isKindOfClass:NSURL.class]) {
url = nil;
}
__block SDWebImageCombinedOperation *operation = [SDWebImageCombinedOperation new];
__weak SDWebImageCombinedOperation *weakOperation = operation;
BOOL isFailedUrl = NO;
// 创建一个互斥锁防止现在有别的线程修改failedURLs.
// 判断这个url是否是fail过的.如果url failed过的那么isFailedUrl就是true
@synchronized (self.failedURLs) {
isFailedUrl = [self.failedURLs containsObject:url];
}
// 如果url不存在那么直接返回一个block,如果url存在.那么继续进行判断.
// options与SDWebImageRetryFailed这个option进行按位与操作.判断用户的options里是否有retry这个option.
// 如果用户的options里没有retry这个选项并且isFaileUrl 是true.那么就回调一个error的block.
if (!url || (!(options & SDWebImageRetryFailed) && isFailedUrl)) {
dispatch_main_sync_safe(^{
NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorFileDoesNotExist userInfo:nil];
completedBlock(nil, error, SDImageCacheTypeNone, YES, url);
});
return operation;
}
// 创建一个互斥锁防止现在有别的线程修改runningOperations.
@synchronized (self.runningOperations) {
[self.runningOperations addObject:operation];
}
NSString *key = [self cacheKeyForURL:url];
// cacheOperation应该是一个用来下载图片并且缓存的operation
operation.cacheOperation = [self.imageCache queryDiskCacheForKey:key done:^(UIImage *image, SDImageCacheType cacheType) {
// 判断operation这时候有没有执行cancel操作,如果cancel掉了就把这个operation从我们的operation数组里remove掉然后return
if (operation.isCancelled) {
@synchronized (self.runningOperations) {
[self.runningOperations removeObject:operation];
}
return;
}
if ((!image || options & SDWebImageRefreshCached) && (![self.delegate respondsToSelector:@selector(imageManager:shouldDownloadImageForURL:)] || [self.delegate imageManager:self shouldDownloadImageForURL:url])) {
if (image && options & SDWebImageRefreshCached) {
dispatch_main_sync_safe(^{
// If image was found in the cache bug SDWebImageRefreshCached is provided, notify about the cached image
// AND try to re-download it in order to let a chance to NSURLCache to refresh it from server.
completedBlock(image, nil, cacheType, YES, url);
});
}
// download if no image or requested to refresh anyway, and download allowed by delegate
// 下面都是判断我们的options里包含哪些SDWebImageOptions,然后给我们的downloaderOptions相应的添加对应的SDWebImageDownloaderOptions. downloaderOptions |= SDWebImageDownloaderLowPriority这种表达式的意思等同于
// downloaderOptions = downloaderOptions | SDWebImageDownloaderLowPriority
SDWebImageDownloaderOptions downloaderOptions = 0;
if (options & SDWebImageLowPriority) downloaderOptions |= SDWebImageDownloaderLowPriority;
if (options & SDWebImageProgressiveDownload) downloaderOptions |= SDWebImageDownloaderProgressiveDownload;
if (options & SDWebImageRefreshCached) downloaderOptions |= SDWebImageDownloaderUseNSURLCache;
if (options & SDWebImageContinueInBackground) downloaderOptions |= SDWebImageDownloaderContinueInBackground;
if (options & SDWebImageHandleCookies) downloaderOptions |= SDWebImageDownloaderHandleCookies;
if (options & SDWebImageAllowInvalidSSLCertificates) downloaderOptions |= SDWebImageDownloaderAllowInvalidSSLCertificates;
if (options & SDWebImageHighPriority) downloaderOptions |= SDWebImageDownloaderHighPriority;
if (image && options & SDWebImageRefreshCached) {
// force progressive off if image already cached but forced refreshing
downloaderOptions &= ~SDWebImageDownloaderProgressiveDownload;
// ignore image read from NSURLCache if image if cached but force refreshing
downloaderOptions |= SDWebImageDownloaderIgnoreCachedResponse;
}
// 调用imageDownloader去下载image并且返回执行这个request的download的operation
id <SDWebImageOperation> subOperation = [self.imageDownloader downloadImageWithURL:url options:downloaderOptions progress:progressBlock completed:^(UIImage *downloadedImage, NSData *data, NSError *error, BOOL finished) {
if (weakOperation.isCancelled) {
// Do nothing if the operation was cancelled
// See #699 for more details
// if we would call the completedBlock, there could be a race condition between this block and another completedBlock for the same object, so if this one is called second, we will overwrite the new data
}
else if (error) {
dispatch_main_sync_safe(^{
if (!weakOperation.isCancelled) {
completedBlock(nil, error, SDImageCacheTypeNone, finished, url);
}
});
if (error.code != NSURLErrorNotConnectedToInternet && error.code != NSURLErrorCancelled && error.code != NSURLErrorTimedOut) {
@synchronized (self.failedURLs) {
[self.failedURLs addObject:url];
}
}
}
else {
if ((options & SDWebImageRetryFailed)) {
@synchronized (self.failedURLs) {
[self.failedURLs removeObject:url];
}
}
BOOL cacheOnDisk = !(options & SDWebImageCacheMemoryOnly);
if (options & SDWebImageRefreshCached && image && !downloadedImage) {
// Image refresh hit the NSURLCache cache, do not call the completion block
}
else if (downloadedImage && (!downloadedImage.images || (options & SDWebImageTransformAnimatedImage)) && [self.delegate respondsToSelector:@selector(imageManager:transformDownloadedImage:withURL:)]) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
UIImage *transformedImage = [self.delegate imageManager:self transformDownloadedImage:downloadedImage withURL:url];
if (transformedImage && finished) {
BOOL imageWasTransformed = ![transformedImage isEqual:downloadedImage];
[self.imageCache storeImage:transformedImage recalculateFromImage:imageWasTransformed imageData:data forKey:key toDisk:cacheOnDisk];
}
dispatch_main_sync_safe(^{
if (!weakOperation.isCancelled) {
completedBlock(transformedImage, nil, SDImageCacheTypeNone, finished, url);
}
});
});
}
else {
if (downloadedImage && finished) {
[self.imageCache storeImage:downloadedImage recalculateFromImage:NO imageData:data forKey:key toDisk:cacheOnDisk];
}
dispatch_main_sync_safe(^{
if (!weakOperation.isCancelled) {
completedBlock(downloadedImage, nil, SDImageCacheTypeNone, finished, url);
}
});
}
}
if (finished) {
@synchronized (self.runningOperations) {
[self.runningOperations removeObject:operation];
}
}
}];
operation.cancelBlock = ^{
[subOperation cancel];
@synchronized (self.runningOperations) {
[self.runningOperations removeObject:weakOperation];
}
};
}
else if (image) {
dispatch_main_sync_safe(^{
if (!weakOperation.isCancelled) {
completedBlock(image, nil, cacheType, YES, url);
}
});
@synchronized (self.runningOperations) {
[self.runningOperations removeObject:operation];
}
}
else {
// Image not in cache and download disallowed by delegate
dispatch_main_sync_safe(^{
if (!weakOperation.isCancelled) {
completedBlock(nil, nil, SDImageCacheTypeNone, YES, url);
}
});
@synchronized (self.runningOperations) {
[self.runningOperations removeObject:operation];
}
}
}];
return operation;
}
- (void)saveImageToCache:(UIImage *)image forURL:(NSURL *)url {
if (image && url) {
NSString *key = [self cacheKeyForURL:url];
[self.imageCache storeImage:image forKey:key toDisk:YES];
}
}
// cancel掉所有正在执行的operation
- (void)cancelAll {
@synchronized (self.runningOperations) {
NSArray *copiedOperations = [self.runningOperations copy];
[copiedOperations makeObjectsPerformSelector:@selector(cancel)];
[self.runningOperations removeObjectsInArray:copiedOperations];
}
}
// 判断是否有正在运行的operation
- (BOOL)isRunning {
return self.runningOperations.count > 0;
}
@end
@implementation SDWebImageCombinedOperation
- (void)setCancelBlock:(SDWebImageNoParamsBlock)cancelBlock {
// check if the operation is already cancelled, then we just call the cancelBlock
if (self.isCancelled) {
if (cancelBlock) {
cancelBlock();
}
_cancelBlock = nil; // don't forget to nil the cancelBlock, otherwise we will get crashes
} else {
_cancelBlock = [cancelBlock copy];
}
}
- (void)cancel {
self.cancelled = YES;
if (self.cacheOperation) {
[self.cacheOperation cancel];
self.cacheOperation = nil;
}
if (self.cancelBlock) {
self.cancelBlock();
// TODO: this is a temporary fix to #809.
// Until we can figure the exact cause of the crash, going with the ivar instead of the setter
// self.cancelBlock = nil;
_cancelBlock = nil;
}
}
@end
@implementation SDWebImageManager (Deprecated)
// deprecated method, uses the non deprecated method
// adapter for the completion block
- (id <SDWebImageOperation>)downloadWithURL:(NSURL *)url options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletedWithFinishedBlock)completedBlock {
return [self downloadImageWithURL:url
options:options
progress:progressBlock
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
if (completedBlock) {
completedBlock(image, error, cacheType, finished);
}
}];
}
@end
- - + + + + +
-
- - - - + + +
- -
-
- - - -
- + +
+

归档

+ +
-
- -
- -
- -

+ - SDWebImage源码解析 -

- - - -
- -
- -

SDWebImage源码解析

-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#import "SDWebImageCompat.h"
#import "SDWebImageOperation.h"
#import "SDWebImageDownloader.h"
#import "SDImageCache.h"
typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) {
/**
* By default, when a URL fail to be downloaded, the URL is blacklisted so the library won't keep trying.
* This flag disable this blacklisting.
*/
/**
*默认情况下,如果一个url在下载的时候失败了,那么这个url会被加入黑名单并且library不会尝试再次下载,这个flag会阻止library把失败的url加入黑名单(简单来说如果选择了这个flag,那么即使某个url下载失败了,sdwebimage还是会尝试再次下载他.)
*/
SDWebImageRetryFailed = 1 << 0,
/**
* By default, image downloads are started during UI interactions, this flags disable this feature,
* leading to delayed download on UIScrollView deceleration for instance.
*/
/**
*默认情况下,图片会在交互发生的时候下载(例如你滑动tableview的时候),这个flag会禁止这个特性,导致的结果就是在scrollview减速的时候
*才会开始下载(也就是你滑动的时候scrollview不下载,你手从屏幕上移走,scrollview开始减速的时候才会开始下载图片)
*/
SDWebImageLowPriority = 1 << 1,
/**
* This flag disables on-disk caching
*/
/*
*这个flag禁止磁盘缓存,只有内存缓存
*/
SDWebImageCacheMemoryOnly = 1 << 2,
/**
* This flag enables progressive download, the image is displayed progressively during download as a browser would do.
* By default, the image is only displayed once completely downloaded.
*/
/*
*这个flag会在图片下载的时候就显示(就像你用浏览器浏览网页的时候那种图片下载,一截一截的显示(待确认))
*
*/
SDWebImageProgressiveDownload = 1 << 3,
/**
* Even if the image is cached, respect the HTTP response cache control, and refresh the image from remote location if needed.
* The disk caching will be handled by NSURLCache instead of SDWebImage leading to slight performance degradation.
* This option helps deal with images changing behind the same request URL, e.g. Facebook graph api profile pics.
* If a cached image is refreshed, the completion block is called once with the cached image and again with the final image.
*
* Use this flag only if you can't make your URLs static with embeded cache busting parameter.
*/
/*
*这个选项的意思看的不是很懂,大意是即使一个图片缓存了,还是会重新请求.并且缓存侧略依据NSURLCache而不是SDWebImage.
*
*/
SDWebImageRefreshCached = 1 << 4,
/**
* In iOS 4+, continue the download of the image if the app goes to background. This is achieved by asking the system for
* extra time in background to let the request finish. If the background task expires the operation will be cancelled.
*/
/*
*启动后台下载,加入你进入一个页面,有一张图片正在下载这时候你让app进入后台,图片还是会继续下载(这个估计要开backgroundfetch才有用)
*/
SDWebImageContinueInBackground = 1 << 5,
/**
* Handles cookies stored in NSHTTPCookieStore by setting
* NSMutableURLRequest.HTTPShouldHandleCookies = YES;
*/
/*
*可以控制存在NSHTTPCookieStore的cookies.(我没用过,等用过的人过来解释一下)
*/
SDWebImageHandleCookies = 1 << 6,
/**
* Enable to allow untrusted SSL ceriticates.
* Useful for testing purposes. Use with caution in production.
*/
/*
*允许不安全的SSL证书,在正式环境中慎用
*/
SDWebImageAllowInvalidSSLCertificates = 1 << 7,
/**
* By default, image are loaded in the order they were queued. This flag move them to
* the front of the queue and is loaded immediately instead of waiting for the current queue to be loaded (which
* could take a while).
*/
/*
*默认情况下,image在装载的时候是按照他们在队列中的顺序装载的(就是先进先出).这个flag会把他们移动到队列的前端,并且立刻装载
*而不是等到当前队列装载的时候再装载.
*/
SDWebImageHighPriority = 1 << 8,
/**
* By default, placeholder images are loaded while the image is loading. This flag will delay the loading
* of the placeholder image until after the image has finished loading.
*/
/*
*默认情况下,占位图会在图片下载的时候显示.这个flag开启会延迟占位图显示的时间,等到图片下载完成之后才会显示占位图.(等图片显示完了我干嘛还显示占位图?或许是我理解错了?)
*/
SDWebImageDelayPlaceholder = 1 << 9,
/**
* We usually don't call transformDownloadedImage delegate method on animated images,
* as most transformation code would mangle it.
* Use this flag to transform them anyway.
*/
/*
*是否transform图片(没用过,还要再看,但是据我估计,是否是图片有可能方向不对需要调整方向,例如采用iPhone拍摄的照片如果不纠正方向,那么图片是向左旋转90度的.可能很多人不知道iPhone的摄像头并不是竖直的,而是向左偏了90度.具体请google.)
*/
SDWebImageTransformAnimatedImage = 1 << 10,
};
typedef void(^SDWebImageCompletionBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL);
typedef void(^SDWebImageCompletionWithFinishedBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL);
typedef NSString *(^SDWebImageCacheKeyFilterBlock)(NSURL *url);
@class SDWebImageManager;
@protocol SDWebImageManagerDelegate <NSObject>
@optional
/**
* Controls which image should be downloaded when the image is not found in the cache.
*
* @param imageManager The current `SDWebImageManager`
* @param imageURL The url of the image to be downloaded
*
* @return Return NO to prevent the downloading of the image on cache misses. If not implemented, YES is implied.
*/
/*
*主要作用是当缓存里没有发现某张图片的缓存时,是否选择下载这张图片(默认是yes),可以选择no,那么sdwebimage在缓存中没有找到这张图片的时候不会选择下载
*/
- (BOOL)imageManager:(SDWebImageManager *)imageManager shouldDownloadImageForURL:(NSURL *)imageURL;
/**
* Allows to transform the image immediately after it has been downloaded and just before to cache it on disk and memory.
* NOTE: This method is called from a global queue in order to not to block the main thread.
*
* @param imageManager The current `SDWebImageManager`
* @param image The image to transform
* @param imageURL The url of the image to transform
*
* @return The transformed image object.
*/
/**
*在图片下载完成并且还没有加入磁盘缓存或者内存缓存的时候就transform这个图片.这个方法是在异步线程执行的,防治阻塞主线程.
*至于为什么在异步执行很简单,对一张图片纠正方向(也就是transform)是很耗资源的,一张2M大小的图片纠正方向你可以用instrument测试一下耗时.
*很恐怖
*/
- (UIImage *)imageManager:(SDWebImageManager *)imageManager transformDownloadedImage:(UIImage *)image withURL:(NSURL *)imageURL;
@end
/**
* The SDWebImageManager is the class behind the UIImageView+WebCache category and likes.
* It ties the asynchronous downloader (SDWebImageDownloader) with the image cache store (SDImageCache).
* You can use this class directly to benefit from web image downloading with caching in another context than
* a UIView.
*
* Here is a simple example of how to use SDWebImageManager:
*
* @code
SDWebImageManager *manager = [SDWebImageManager sharedManager];
[manager downloadImageWithURL:imageURL
options:0
progress:nil
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
if (image) {
// do something with image
}
}];
* @endcode
*/
/*
*这一段是阐述SDWebImageManager是干嘛的.其实UIImageView+WebCache这个category背后执行操作的就是这个SDWebImageManager.他会绑定一个下载器也就是SDWebImageDownloader和一个缓存SDImageCache.后面的大意应该是讲你可以直接使用一个其他上下文环境的SDWebImageManager,而不是仅仅限于一个UIView.
*/
@interface SDWebImageManager : NSObject
@property (weak, nonatomic) id <SDWebImageManagerDelegate> delegate;
/**
*如同上文所说,一个SDWebImageManager会绑定一个imageCache和一个下载器.
*/
@property (strong, nonatomic, readonly) SDImageCache *imageCache;
@property (strong, nonatomic, readonly) SDWebImageDownloader *imageDownloader;
/**
* The cache filter is a block used each time SDWebImageManager need to convert an URL into a cache key. This can
* be used to remove dynamic part of an image URL.
*
* The following example sets a filter in the application delegate that will remove any query-string from the
* URL before to use it as a cache key:
*
* @code
[[SDWebImageManager sharedManager] setCacheKeyFilter:^(NSURL *url) {
url = [[NSURL alloc] initWithScheme:url.scheme host:url.host path:url.path];
return [url absoluteString];
}];
* @endcode
*/
/*
* 这个cacheKeyFilter是干嘛的呢?很简单.1他是一个block.2.这个block的作用就是生成一个image的key.因为sdwebimage的缓存原理你可以当成是一个字典,每一个字典的value就是一张image,那么这个value对应的key是什么呢?就是cacheKeyFilter根据某个规则对这个图片的url做一些操作生成的.上面的示例就显示了怎么利用这个block把image的url重新组合生成一个key.以后当sdwebimage检测到你
*/
@property (nonatomic, copy) SDWebImageCacheKeyFilterBlock cacheKeyFilter;
/**
* Returns global SDWebImageManager instance.
*
* @return SDWebImageManager shared instance
*/
/*
*这个不用我解释了吧,生成一个SDWebImagemanager的单例.
*/
+ (SDWebImageManager *)sharedManager;
/**
* Downloads the image at the given URL if not present in cache or return the cached version otherwise.
* 从给定的URL中下载一个之前没有被缓存的Image.
*
* @param url The URL to the image
* @param options A mask to specify options to use for this request
* @param progressBlock A block called while image is downloading
* @param completedBlock A block called when operation has been completed.
*
* This parameter is required.
*
* This block has no return value and takes the requested UIImage as first parameter.
* In case of error the image parameter is nil and the second parameter may contain an NSError.
*
* The third parameter is an `SDImageCacheType` enum indicating if the image was retrived from the local cache
* or from the memory cache or from the network.
*
* The last parameter is set to NO when the SDWebImageProgressiveDownload option is used and the image is
* downloading. This block is thus called repetidly with a partial image. When image is fully downloaded, the
* block is called a last time with the full image and the last parameter set to YES.
*
* @return Returns an NSObject conforming to SDWebImageOperation. Should be an instance of SDWebImageDownloaderOperation
*/
/*
* 这个方法主要就是SDWebImage下载图片的方法了.
* 第一个参数是必须要的,就是image的url
* 第二个参数就是我们上面的Options,你可以定制化各种各样的操作.详情参上.
* 第三个参数是一个回调block,用于图片在下载过程中的回调.(英文注释应该是有问题的.)
* 第四个参数是一个下载完成的回调.会在图片下载完成后回调.
* 返回值是一个NSObject类,并且这个NSObject类是conforming一个协议这个协议叫做SDWebImageOperation,这个协议很简单,就是一个cancel掉operation的协议.
*/
- (id <SDWebImageOperation>)downloadImageWithURL:(NSURL *)url
options:(SDWebImageOptions)options
progress:(SDWebImageDownloaderProgressBlock)progressBlock
completed:(SDWebImageCompletionWithFinishedBlock)completedBlock;
/**
* Saves image to cache for given URL
*
* @param image The image to cache
* @param url The URL to the image
*
*/
/*
* 将图片存入cache的方法,类似于字典的setValue: forKey:
*/
- (void)saveImageToCache:(UIImage *)image forURL:(NSURL *)url;
/**
* Cancel all current opreations
*/
/*
*取消掉当前所有的下载图片的operation
*/
- (void)cancelAll;
/**
* Check one or more operations running
*/
/*
* check一下是否有一个或者多个operation正在执行(简单来说就是check是否有图片在下载)
*/
- (BOOL)isRunning;
/**
* Check if image has already been cached
*
* @param url image url
*
* @return if the image was already cached
*/
/*
* 通过一个image的url是否已经存在,如果存在返回yes,否则返回no
*/
- (BOOL)cachedImageExistsForURL:(NSURL *)url;
/**
* Check if image has already been cached on disk only
*
* @param url image url
*
* @return if the image was already cached (disk only)
*/
/*
* 检测一个image是否已经被缓存到磁盘(是否存且仅存在disk里).
*/
- (BOOL)diskImageExistsForURL:(NSURL *)url;
/**
* Async check if image has already been cached
*
* @param url image url
* @param completionBlock the block to be executed when the check is finished
*
* @note the completion block is always executed on the main queue
*/
/*
* 如果检测到图片已经被缓存,那么执行回调block.这个block会永远执行在主线程.也就是你可以在这个回调block里更新ui.
*/
- (void)cachedImageExistsForURL:(NSURL *)url
completion:(SDWebImageCheckCacheCompletionBlock)completionBlock;
/**
* Async check if image has already been cached on disk only
*
* @param url image url
* @param completionBlock the block to be executed when the check is finished
*
* @note the completion block is always executed on the main queue
*/
/*
* 如果检测到图片已经被缓存在磁盘(存且仅存在disk),那么执行回调block.这个block会永远执行在主线程.也就是你可以在这个回调block里更新ui.
*/
- (void)diskImageExistsForURL:(NSURL *)url
completion:(SDWebImageCheckCacheCompletionBlock)completionBlock;
/**
*Return the cache key for a given URL
*/
/*
* 通过image的url返回image存在缓存里的key.有人会问了,为什么不直接把图片的url当做image的key来使用呢?而是非要对url做一些处理才能当做key.我的解释是,我也不太清楚.可能为了防止重复吧.
*/
- (NSString *)cacheKeyForURL:(NSURL *)url;
@end
#pragma mark - Deprecated
typedef void(^SDWebImageCompletedBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType) __deprecated_msg("Block type deprecated. Use `SDWebImageCompletionBlock`");
typedef void(^SDWebImageCompletedWithFinishedBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished) __deprecated_msg("Block type deprecated. Use `SDWebImageCompletionWithFinishedBlock`");
// 已被废弃
@interface SDWebImageManager (Deprecated)
/**
* Downloads the image at the given URL if not present in cache or return the cached version otherwise.
*
* @deprecated This method has been deprecated. Use `downloadImageWithURL:options:progress:completed:`
*/
- (id <SDWebImageOperation>)downloadWithURL:(NSURL *)url
options:(SDWebImageOptions)options
progress:(SDWebImageDownloaderProgressBlock)progressBlock
completed:(SDWebImageCompletedWithFinishedBlock)completedBlock __deprecated_msg("Method deprecated. Use `downloadImageWithURL:options:progress:completed:`");
@end
-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
#import <Foundation/Foundation.h>
/*
* This file is part of the SDWebImage package.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#import "SDWebImageManager.h"
#import <objc/message.h>
// 内部类.
@interface SDWebImageCombinedOperation : NSObject <SDWebImageOperation>
@property (assign, nonatomic, getter = isCancelled) BOOL cancelled;
@property (copy, nonatomic) SDWebImageNoParamsBlock cancelBlock;
@property (strong, nonatomic) NSOperation *cacheOperation;
@end
@interface SDWebImageManager ()
@property (strong, nonatomic, readwrite) SDImageCache *imageCache;
@property (strong, nonatomic, readwrite) SDWebImageDownloader *imageDownloader;
@property (strong, nonatomic) NSMutableSet *failedURLs;
@property (strong, nonatomic) NSMutableArray *runningOperations;
@end
@implementation SDWebImageManager
// 利用disptach_once 特性生成一个单例,用烂了的方法.不赘述.
+ (id)sharedManager {
static dispatch_once_t once;
static id instance;
dispatch_once(&once, ^{
instance = [self new];
});
return instance;
}
// 初始化方法.
// 1.获得一个SDImageCache的单例.2.获取一个SDWebImageDownloader的单例.3.新建一个MutableSet来存储下载失败的url.
// 4.新建一个用来存储下载operation的可变数组.
// 为什么不用MutableArray储存下载失败的URL?
// 因为NSSet类有一个特性,就是Hash.实际上NSSet是一个哈希表,哈希表比数组优秀的地方是什么呢?就是查找速度快.查找同样一个元素,哈希表只需要通过key
// 即可取到,而数组至少需要遍历依次.因为SDWebImage里有关失败URL的业务需求是,一个失败的URL只需要储存一次.这样的话Set自然比Array更合适.
- (id)init {
if ((self = [super init])) {
_imageCache = [self createCache];
_imageDownloader = [SDWebImageDownloader sharedDownloader];
_failedURLs = [NSMutableSet new];
_runningOperations = [NSMutableArray new];
}
return self;
}
// 获取一个cache的单例
- (SDImageCache *)createCache {
return [SDImageCache sharedImageCache];
}
// 利用Image的URL生成一个缓存时需要的key.
// 这里有两种情况,第一种是如果检测到cacheKeyFilter不为空时,利用cacheKeyFilter来处理URL生成一个key.
// 如果为空,那么直接返回URL的string内容,当做key.
- (NSString *)cacheKeyForURL:(NSURL *)url {
if (self.cacheKeyFilter) {
return self.cacheKeyFilter(url);
}
else {
return [url absoluteString];
}
}
// 检测一张图片是否已被缓存.
// 首先检测内存缓存是否存在这张图片,如果已有,直接返回yes.
// 如果内存缓存里没有这张图片,那么调用diskImageExistsWithKey这个方法去硬盘缓存里找
- (BOOL)cachedImageExistsForURL:(NSURL *)url {
NSString *key = [self cacheKeyForURL:url];
if ([self.imageCache imageFromMemoryCacheForKey:key] != nil) return YES;
return [self.imageCache diskImageExistsWithKey:key];
}
// 检测硬盘里是否缓存了图片
- (BOOL)diskImageExistsForURL:(NSURL *)url {
NSString *key = [self cacheKeyForURL:url];
return [self.imageCache diskImageExistsWithKey:key];
}
// 首先生成一个用来cache 住Image的key(利用key的url生成)
// 然后检测内存缓存里是否已经有这张图片
// 如果已经被缓存,那么再主线程里回调block
// 如果没有检测到,那么调用diskImageExistsWithKey,这个方法会在异步线程里,将图片存到硬盘,当然在存图之前也会检测是否已在硬盘缓存图片.
- (void)cachedImageExistsForURL:(NSURL *)url
completion:(SDWebImageCheckCacheCompletionBlock)completionBlock {
NSString *key = [self cacheKeyForURL:url];
BOOL isInMemoryCache = ([self.imageCache imageFromMemoryCacheForKey:key] != nil);
if (isInMemoryCache) {
// making sure we call the completion block on the main queue
dispatch_async(dispatch_get_main_queue(), ^{
if (completionBlock) {
completionBlock(YES);
}
});
return;
}
[self.imageCache diskImageExistsWithKey:key completion:^(BOOL isInDiskCache) {
// the completion block of checkDiskCacheForImageWithKey:completion: is always called on the main queue, no need to further dispatch
if (completionBlock) {
completionBlock(isInDiskCache);
}
}];
}
//将图片存入硬盘
- (void)diskImageExistsForURL:(NSURL *)url
completion:(SDWebImageCheckCacheCompletionBlock)completionBlock {
NSString *key = [self cacheKeyForURL:url];
[self.imageCache diskImageExistsWithKey:key completion:^(BOOL isInDiskCache) {
// the completion block of checkDiskCacheForImageWithKey:completion: is always called on the main queue, no need to further dispatch
if (completionBlock) {
completionBlock(isInDiskCache);
}
}];
}
// 通过url建立一个operation用来下载图片.
- (id <SDWebImageOperation>)downloadImageWithURL:(NSURL *)url
options:(SDWebImageOptions)options
progress:(SDWebImageDownloaderProgressBlock)progressBlock
completed:(SDWebImageCompletionWithFinishedBlock)completedBlock {
// Invoking this method without a completedBlock is pointless
NSAssert(completedBlock != nil, @"If you mean to prefetch the image, use -[SDWebImagePrefetcher prefetchURLs] instead");
// Very common mistake is to send the URL using NSString object instead of NSURL. For some strange reason, XCode won't
// throw any warning for this type mismatch. Here we failsafe this error by allowing URLs to be passed as NSString.
if ([url isKindOfClass:NSString.class]) {
url = [NSURL URLWithString:(NSString *)url];
}
// Prevents app crashing on argument type error like sending NSNull instead of NSURL
if (![url isKindOfClass:NSURL.class]) {
url = nil;
}
__block SDWebImageCombinedOperation *operation = [SDWebImageCombinedOperation new];
__weak SDWebImageCombinedOperation *weakOperation = operation;
BOOL isFailedUrl = NO;
// 创建一个互斥锁防止现在有别的线程修改failedURLs.
// 判断这个url是否是fail过的.如果url failed过的那么isFailedUrl就是true
@synchronized (self.failedURLs) {
isFailedUrl = [self.failedURLs containsObject:url];
}
// 如果url不存在那么直接返回一个block,如果url存在.那么继续进行判断.
// options与SDWebImageRetryFailed这个option进行按位与操作.判断用户的options里是否有retry这个option.
// 如果用户的options里没有retry这个选项并且isFaileUrl 是true.那么就回调一个error的block.
if (!url || (!(options & SDWebImageRetryFailed) && isFailedUrl)) {
dispatch_main_sync_safe(^{
NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorFileDoesNotExist userInfo:nil];
completedBlock(nil, error, SDImageCacheTypeNone, YES, url);
});
return operation;
}
// 创建一个互斥锁防止现在有别的线程修改runningOperations.
@synchronized (self.runningOperations) {
[self.runningOperations addObject:operation];
}
NSString *key = [self cacheKeyForURL:url];
// cacheOperation应该是一个用来下载图片并且缓存的operation
operation.cacheOperation = [self.imageCache queryDiskCacheForKey:key done:^(UIImage *image, SDImageCacheType cacheType) {
// 判断operation这时候有没有执行cancel操作,如果cancel掉了就把这个operation从我们的operation数组里remove掉然后return
if (operation.isCancelled) {
@synchronized (self.runningOperations) {
[self.runningOperations removeObject:operation];
}
return;
}
if ((!image || options & SDWebImageRefreshCached) && (![self.delegate respondsToSelector:@selector(imageManager:shouldDownloadImageForURL:)] || [self.delegate imageManager:self shouldDownloadImageForURL:url])) {
if (image && options & SDWebImageRefreshCached) {
dispatch_main_sync_safe(^{
// If image was found in the cache bug SDWebImageRefreshCached is provided, notify about the cached image
// AND try to re-download it in order to let a chance to NSURLCache to refresh it from server.
completedBlock(image, nil, cacheType, YES, url);
});
}
// download if no image or requested to refresh anyway, and download allowed by delegate
// 下面都是判断我们的options里包含哪些SDWebImageOptions,然后给我们的downloaderOptions相应的添加对应的SDWebImageDownloaderOptions. downloaderOptions |= SDWebImageDownloaderLowPriority这种表达式的意思等同于
// downloaderOptions = downloaderOptions | SDWebImageDownloaderLowPriority
SDWebImageDownloaderOptions downloaderOptions = 0;
if (options & SDWebImageLowPriority) downloaderOptions |= SDWebImageDownloaderLowPriority;
if (options & SDWebImageProgressiveDownload) downloaderOptions |= SDWebImageDownloaderProgressiveDownload;
if (options & SDWebImageRefreshCached) downloaderOptions |= SDWebImageDownloaderUseNSURLCache;
if (options & SDWebImageContinueInBackground) downloaderOptions |= SDWebImageDownloaderContinueInBackground;
if (options & SDWebImageHandleCookies) downloaderOptions |= SDWebImageDownloaderHandleCookies;
if (options & SDWebImageAllowInvalidSSLCertificates) downloaderOptions |= SDWebImageDownloaderAllowInvalidSSLCertificates;
if (options & SDWebImageHighPriority) downloaderOptions |= SDWebImageDownloaderHighPriority;
if (image && options & SDWebImageRefreshCached) {
// force progressive off if image already cached but forced refreshing
downloaderOptions &= ~SDWebImageDownloaderProgressiveDownload;
// ignore image read from NSURLCache if image if cached but force refreshing
downloaderOptions |= SDWebImageDownloaderIgnoreCachedResponse;
}
// 调用imageDownloader去下载image并且返回执行这个request的download的operation
id <SDWebImageOperation> subOperation = [self.imageDownloader downloadImageWithURL:url options:downloaderOptions progress:progressBlock completed:^(UIImage *downloadedImage, NSData *data, NSError *error, BOOL finished) {
if (weakOperation.isCancelled) {
// Do nothing if the operation was cancelled
// See #699 for more details
// if we would call the completedBlock, there could be a race condition between this block and another completedBlock for the same object, so if this one is called second, we will overwrite the new data
}
else if (error) {
dispatch_main_sync_safe(^{
if (!weakOperation.isCancelled) {
completedBlock(nil, error, SDImageCacheTypeNone, finished, url);
}
});
if (error.code != NSURLErrorNotConnectedToInternet && error.code != NSURLErrorCancelled && error.code != NSURLErrorTimedOut) {
@synchronized (self.failedURLs) {
[self.failedURLs addObject:url];
}
}
}
else {
if ((options & SDWebImageRetryFailed)) {
@synchronized (self.failedURLs) {
[self.failedURLs removeObject:url];
}
}
BOOL cacheOnDisk = !(options & SDWebImageCacheMemoryOnly);
if (options & SDWebImageRefreshCached && image && !downloadedImage) {
// Image refresh hit the NSURLCache cache, do not call the completion block
}
else if (downloadedImage && (!downloadedImage.images || (options & SDWebImageTransformAnimatedImage)) && [self.delegate respondsToSelector:@selector(imageManager:transformDownloadedImage:withURL:)]) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
UIImage *transformedImage = [self.delegate imageManager:self transformDownloadedImage:downloadedImage withURL:url];
if (transformedImage && finished) {
BOOL imageWasTransformed = ![transformedImage isEqual:downloadedImage];
[self.imageCache storeImage:transformedImage recalculateFromImage:imageWasTransformed imageData:data forKey:key toDisk:cacheOnDisk];
}
dispatch_main_sync_safe(^{
if (!weakOperation.isCancelled) {
completedBlock(transformedImage, nil, SDImageCacheTypeNone, finished, url);
}
});
});
}
else {
if (downloadedImage && finished) {
[self.imageCache storeImage:downloadedImage recalculateFromImage:NO imageData:data forKey:key toDisk:cacheOnDisk];
}
dispatch_main_sync_safe(^{
if (!weakOperation.isCancelled) {
completedBlock(downloadedImage, nil, SDImageCacheTypeNone, finished, url);
}
});
}
}
if (finished) {
@synchronized (self.runningOperations) {
[self.runningOperations removeObject:operation];
}
}
}];
operation.cancelBlock = ^{
[subOperation cancel];
@synchronized (self.runningOperations) {
[self.runningOperations removeObject:weakOperation];
}
};
}
else if (image) {
dispatch_main_sync_safe(^{
if (!weakOperation.isCancelled) {
completedBlock(image, nil, cacheType, YES, url);
}
});
@synchronized (self.runningOperations) {
[self.runningOperations removeObject:operation];
}
}
else {
// Image not in cache and download disallowed by delegate
dispatch_main_sync_safe(^{
if (!weakOperation.isCancelled) {
completedBlock(nil, nil, SDImageCacheTypeNone, YES, url);
}
});
@synchronized (self.runningOperations) {
[self.runningOperations removeObject:operation];
}
}
}];
return operation;
}
- (void)saveImageToCache:(UIImage *)image forURL:(NSURL *)url {
if (image && url) {
NSString *key = [self cacheKeyForURL:url];
[self.imageCache storeImage:image forKey:key toDisk:YES];
}
}
// cancel掉所有正在执行的operation
- (void)cancelAll {
@synchronized (self.runningOperations) {
NSArray *copiedOperations = [self.runningOperations copy];
[copiedOperations makeObjectsPerformSelector:@selector(cancel)];
[self.runningOperations removeObjectsInArray:copiedOperations];
}
}
// 判断是否有正在运行的operation
- (BOOL)isRunning {
return self.runningOperations.count > 0;
}
@end
@implementation SDWebImageCombinedOperation
- (void)setCancelBlock:(SDWebImageNoParamsBlock)cancelBlock {
// check if the operation is already cancelled, then we just call the cancelBlock
if (self.isCancelled) {
if (cancelBlock) {
cancelBlock();
}
_cancelBlock = nil; // don't forget to nil the cancelBlock, otherwise we will get crashes
} else {
_cancelBlock = [cancelBlock copy];
}
}
- (void)cancel {
self.cancelled = YES;
if (self.cacheOperation) {
[self.cacheOperation cancel];
self.cacheOperation = nil;
}
if (self.cancelBlock) {
self.cancelBlock();
// TODO: this is a temporary fix to #809.
// Until we can figure the exact cause of the crash, going with the ivar instead of the setter
// self.cancelBlock = nil;
_cancelBlock = nil;
}
}
@end
@implementation SDWebImageManager (Deprecated)
// deprecated method, uses the non deprecated method
// adapter for the completion block
- (id <SDWebImageOperation>)downloadWithURL:(NSURL *)url options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletedWithFinishedBlock)completedBlock {
return [self downloadImageWithURL:url
options:options
progress:progressBlock
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
if (completedBlock) {
completedBlock(image, error, cacheType, finished);
}
}];
}
@end
- - -
- - - - - -
- - - - - +
+

最新文章

+
+
- -
- - -
- -
- - -
- -
- - -
- -
- - -
-
-
- - - - - -
- +
+ + + + + - - - - - - - - - - + - +
- + \ No newline at end of file diff --git a/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html b/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html index 739d4f6..3826256 100644 --- a/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html +++ b/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html @@ -1,15 +1,11 @@ - - - - - - - - Swift3.0学习笔记 | CoderShmily's Blog - - - + + + + + Swift3.0学习笔记 | CoderShmily's Blog + + @@ -19,128 +15,50 @@ - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + - - - - - - - -
- +
+ +
+ +
+
+ + + + + + - - - - - - - - - - + - + - + \ No newline at end of file diff --git a/archives/2015/05/index.html b/archives/2015/05/index.html index cb234a3..c768c13 100644 --- a/archives/2015/05/index.html +++ b/archives/2015/05/index.html @@ -1,15 +1,11 @@ - - - - - - - - 归档: 5/2015: 2015 | CoderShmily's Blog - - - + + + + + 归档: 2015/5 | CoderShmily's Blog + + @@ -18,275 +14,285 @@ + + + + + + + + + + + - - - - - - + +
+
+ +
+
+ + - + + +
+
+ 2015 +
+
+ + - - - - - - - - + + + + - - - - 首页 - + + - -
- -
-
- - - - - - - - -

5/2015

+ -
- - - - SDWebImage源码解析 - + + +
+ -
- - - - Objective-C Runtime(一) 概述 - + + +
+ -
- - - - 单例模式的ARC和MRC实现 - + + +
+ + + +
+ -
+ +
+ + + +
- - - -
- + + + + + + - - - - - - - - - - + - + - + \ No newline at end of file diff --git a/archives/2015/index.html b/archives/2015/index.html index 69e60a2..b4ee781 100644 --- a/archives/2015/index.html +++ b/archives/2015/index.html @@ -1,15 +1,11 @@ - - - - - - - - 归档: 2015 | CoderShmily's Blog - - - + + + + + 归档: 2015 | CoderShmily's Blog + + @@ -18,275 +14,285 @@ + + + + + + + + + + + - - - - - - + +
+
+ +
+
+ + - + + +
+
+ 2015 +
+
+ + - - - - - - - - + + + + - - - - 首页 - + + - -
- -
-
- - - - - - - - -

undefined/2015

+ -
- - - - SDWebImage源码解析 - + + +
+ -
- - - - Objective-C Runtime(一) 概述 - + + +
+ -
- - - - 单例模式的ARC和MRC实现 - + + +
+ + + +
+ -
+ +
+ + + +
- - - -
- + + + + + + - - - - - - - - - - + - + - + \ No newline at end of file diff --git a/archives/2016/11/index.html b/archives/2016/11/index.html index 6aec8d5..9919988 100644 --- a/archives/2016/11/index.html +++ b/archives/2016/11/index.html @@ -1,15 +1,11 @@ - - - - - - - - 归档: 11/2016: 2016 | CoderShmily's Blog - - - + + + + + 归档: 2016/11 | CoderShmily's Blog + + @@ -18,191 +14,152 @@ + + + + + + + + + + + - - - - - - - - - + +
+
+ +
+
+ + - - - - - - - - + + +
+
+ 2016 +
+
+ + + +
+ -
+ +
- - + + - + - - - 首页 - +
+

归档

+ +
- + -
- -
-
- - - - - - - - -

11/2016

+ -
- - - - Swift3.0学习笔记 - - - -
+ + +
+
+ + + + + - - - - - - - - - - + - +
- + \ No newline at end of file diff --git a/archives/2016/index.html b/archives/2016/index.html index 382c8e0..4ef9afa 100644 --- a/archives/2016/index.html +++ b/archives/2016/index.html @@ -1,15 +1,11 @@ - - - - - - - - 归档: 2016 | CoderShmily's Blog - - - + + + + + 归档: 2016 | CoderShmily's Blog + + @@ -18,191 +14,152 @@ + + + + + + + + + + + - - - - - - - - - + +
+
+ +
+
+ + - - - - - - - - + + +
+
+ 2016 +
+
+ + + +
+ -
+ +
- - + + - + - - - 首页 - +
+

归档

+ +
- + -
- -
-
- - - - - - - - -

undefined/2016

+ -
- - - - Swift3.0学习笔记 - - - -
+ + +
+
+ + + + + - - - - - - - - - - + - +
- + \ No newline at end of file diff --git a/archives/index.html b/archives/index.html index e99d13b..7a5d502 100644 --- a/archives/index.html +++ b/archives/index.html @@ -1,15 +1,11 @@ - - - - - - - - 归档 | CoderShmily's Blog - - - + + + + + 归档 | CoderShmily's Blog + + @@ -18,204 +14,314 @@ + + + + + + + + + + + - - - - + + +
+
+ 2016 +
+
+ + - + +
+ + +
+
+ 2015 +
+
+ + - - - - - - - - + + + + - - - - 首页 - + + - -
- -
-
- - - - - - - -
- -

Archives

+ + - - -
+ +

+ KVC 和 KVO深入 +

+ -
+ + + + + + + + + + + +
+ - - + + + + + + - - - - - - - - - - + - + - + \ No newline at end of file diff --git a/categories/Swift/index.html b/categories/Swift/index.html index 51110bb..44ff482 100644 --- a/categories/Swift/index.html +++ b/categories/Swift/index.html @@ -1,15 +1,11 @@ - - - - - - - - 分类: Swift | CoderShmily's Blog - - - + + + + + Category: Swift | CoderShmily's Blog + + @@ -18,196 +14,181 @@ - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + - - - - + + + + + - - - - - - - - - - + - + - + \ No newline at end of file diff --git a/categories/iOS/index.html b/categories/iOS/index.html index 1758685..5e35da9 100644 --- a/categories/iOS/index.html +++ b/categories/iOS/index.html @@ -1,15 +1,11 @@ - - - - - - - - 分类: iOS | CoderShmily's Blog - - - + + + + + Category: iOS | CoderShmily's Blog + + @@ -18,251 +14,266 @@ + + + + + + + + + + + - - - - - - + +
+
+ +
+
+ + - + + +
+
+ 2015 +
+
+ + - - - - - - - - + + + + - - - - 首页 - + + - -
- -
-
- - - - -
-

iOS

- - + -
- - - Objective-C Runtime(一) 概述 - + + +
+ -
- - - 单例模式的ARC和MRC实现 - + + +
- -
+ -
- +
+ +
+ + + +
- - - -
- + + + + + + - - - - - - - - - - + - + - + \ No newline at end of file diff --git a/css/aloha.css b/css/aloha.css deleted file mode 100644 index 7492600..0000000 --- a/css/aloha.css +++ /dev/null @@ -1,278 +0,0 @@ -.post-content { - display: inline; -} -.post-content div { - padding-top: 10px; -} -footer { - bottom: 0; - background-color: #00B5AD; - height: 50px; -} -.main.container .article-footer { - margin-top: 20px; -} -.main.container .pagination { - margin-top: 40px; - margin-bottom: 40px; -} -.post-description .post-description-item { - padding-right: 10px; - height: 100%; - vertical-align: middle; -} -pre { - word-break: break-all; - word-wrap: break-word; -} -.tag-container .tagpage.header { - font-size: 30px; -} -.tag-container .ui.dividing.header { - vertical-align: middle; -} -#search-modal #search-results .highlight { - background-color: #c6e6f4; -} -#search-modal #search-results .search-result-tags { - padding-top: 5px; -} -#search-modal .algolia-logo { - float: right; -} -.sidebar-card { - padding: 10px; -} -#body .menu-buttons { - position: fixed; - z-index: 2147483647; - bottom: 20px; - left: 20px; -} -#body .body-content #content { - margin-top: 60px; -} -#sidebar-top .content { - position: relative; - background: #FFF; - margin: 1rem 0; - text-align: center; -} -.article-inner .post-description { - padding-top: 10px; -} -@media only screen and (max-width: 1200px) and (min-width: 768px) { - .nav-left { - text-align: right; - } - .nav-right { - text-align: left; - } -} -@media only screen and (min-width: 1200px) { - .nav-left { - text-align: right; - } - .nav-right { - text-align: left; - } -} -@media only screen and (max-width: 767px) { - .nav-left { - text-align: center; - } - .nav-right { - text-align: center; - } -} -#article-toc { - top: 55px; -} -.article-entry pre, -.article-entry code { - font-family: "Source Code Pro", Consolas, Monaco, Menlo, Consolas, monospace; -} -.article-entry code { - background: #eee; - text-shadow: 0 1px #fff; - padding: 0 0.3em; -} -.article-entry pre { - background: #2d2d2d; - margin-right: -20px; - margin-left: -20px; - padding: 15px 20px; - border-style: solid; - border-color: #ddd; - border-width: 1px 0; - overflow: auto; - color: #cccccc; - line-height: 22.4px; -} -.article-entry pre code { - background: none; - text-shadow: none; - padding: 0; -} -.article-entry .highlight { - background: #2d2d2d; - margin-right: -20px; - margin-left: -20px; - padding: 15px 20px; - border-style: solid; - border-color: #ddd; - border-width: 1px 0; - overflow: auto; - color: #cccccc; - line-height: 22.4px; - margin-right: 0; - margin-left: 0; -} -.article-entry .highlight pre { - border: none; - margin: 0; - padding: 0; -} -.article-entry .highlight table { - margin: 0; - width: auto; -} -.article-entry .highlight td { - border: none; - padding: 0; -} -.article-entry .highlight figcaption { - font-size: 0.85em; - color: #999999; - line-height: 1em; - margin-bottom: 1em; -} -.article-entry .highlight figcaption:before, -.article-entry .highlight figcaption:after { - content: " "; - /* 1 */ - display: table; - /* 2 */ -} -.article-entry .highlight figcaption:after { - clear: both; -} -.article-entry .highlight figcaption a { - float: right; -} -.article-entry .highlight .gutter pre { - color: #666; - font-size: 0.85em; - text-align: right; - padding-right: 20px; -} -.article-entry .highlight .line { - height: 22.4px; -} -.article-entry .highlight .line.marked { - background: #515151; -} -.article-entry .gist { - margin: 0 -20px; - border-style: solid; - border-color: #ddd; - border-width: 1px 0; - background: #2d2d2d; - padding: 15px 20px 15px 0; -} -.article-entry .gist .gist-file { - border: none; - font-family: "Source Code Pro", Consolas, Monaco, Menlo, Consolas, monospace; - margin: 0; -} -.article-entry .gist .gist-file .gist-data { - background: none; - border: none; -} -.article-entry .gist .gist-file .gist-data .line-numbers { - color: #666; - font-size: 0.85em; - background: none; - border: none; - padding: 0 20px 0 0; -} -.article-entry .gist .gist-file .gist-data .line-data { - padding: 0 !important; -} -.article-entry .gist .gist-file .highlight { - margin: 0; - padding: 0; - border: none; -} -.article-entry .gist .gist-file .gist-meta { - background: #2d2d2d; - color: #999999; - font: 0.85em -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; - text-shadow: 0 0; - padding: 0; - margin-top: 1em; - margin-left: 20px; -} -.article-entry .gist .gist-file .gist-meta a { - color: #258fb8; - font-weight: normal; -} -.article-entry .gist .gist-file .gist-meta a:hover { - text-decoration: underline; -} -pre .comment, -pre .title { - color: #999999; -} -pre .variable, -pre .attribute, -pre .tag, -pre .regexp, -pre .ruby .constant, -pre .xml .tag .title, -pre .xml .pi, -pre .xml .doctype, -pre .html .doctype, -pre .css .id, -pre .css .class, -pre .css .pseudo { - color: #f2777a; -} -pre .number, -pre .preprocessor, -pre .built_in, -pre .literal, -pre .params, -pre .constant { - color: #f99157; -} -pre .class, -pre .ruby .class .title, -pre .css .rules .attribute { - color: #99cc99; -} -pre .string, -pre .value, -pre .inheritance, -pre .header, -pre .ruby .symbol, -pre .xml .cdata { - color: #99cc99; -} -pre .css .hexcolor { - color: #66cccc; -} -pre .function, -pre .python .decorator, -pre .python .title, -pre .ruby .function .title, -pre .ruby .title .keyword, -pre .perl .sub, -pre .javascript .title, -pre .coffeescript .title { - color: #6699cc; -} -pre .keyword, -pre .javascript .function { - color: #cc99cc; -} diff --git a/css/aloha.less b/css/aloha.less deleted file mode 100644 index df913c4..0000000 --- a/css/aloha.less +++ /dev/null @@ -1,2 +0,0 @@ -@import "_partial/main"; -@import "_partial/highlight"; \ No newline at end of file diff --git a/css/fonts/FontAwesome.otf b/css/fonts/FontAwesome.otf new file mode 100644 index 0000000000000000000000000000000000000000..8b0f54e47e1d356dcf1496942a50e228e0f1ee14 GIT binary patch literal 62856 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 + - - - - - - - - - - - + + + + + + - - - - - - - - - - + - + - + \ No newline at end of file diff --git a/js/aloha-events.js b/js/aloha-events.js deleted file mode 100644 index 0e0b360..0000000 --- a/js/aloha-events.js +++ /dev/null @@ -1,14 +0,0 @@ -$(function () { - $("#menu-icon").on("click", function () { - $('#menu-sidebar') - .sidebar('setting', 'transition', 'overlay') - .sidebar('toggle'); - }); - $("#right-menu-icon").on("click", function () { - $('#right-menu-sidebar') - .sidebar('setting', 'transition', 'overlay') - .sidebar('toggle'); - ; - }); - $("#article-toc").sticky({ context: '#article-content' }); -}) \ No newline at end of file diff --git a/js/aloha.js b/js/aloha.js deleted file mode 100644 index 8e224cc..0000000 --- a/js/aloha.js +++ /dev/null @@ -1,3 +0,0 @@ -$(function () { - -}); \ No newline at end of file diff --git a/js/script.js b/js/script.js new file mode 100644 index 0000000..1e58767 --- /dev/null +++ b/js/script.js @@ -0,0 +1,137 @@ +(function($){ + // Search + var $searchWrap = $('#search-form-wrap'), + isSearchAnim = false, + searchAnimDuration = 200; + + var startSearchAnim = function(){ + isSearchAnim = true; + }; + + var stopSearchAnim = function(callback){ + setTimeout(function(){ + isSearchAnim = false; + callback && callback(); + }, searchAnimDuration); + }; + + $('#nav-search-btn').on('click', function(){ + if (isSearchAnim) return; + + startSearchAnim(); + $searchWrap.addClass('on'); + stopSearchAnim(function(){ + $('.search-form-input').focus(); + }); + }); + + $('.search-form-input').on('blur', function(){ + startSearchAnim(); + $searchWrap.removeClass('on'); + stopSearchAnim(); + }); + + // Share + $('body').on('click', function(){ + $('.article-share-box.on').removeClass('on'); + }).on('click', '.article-share-link', function(e){ + e.stopPropagation(); + + var $this = $(this), + url = $this.attr('data-url'), + encodedUrl = encodeURIComponent(url), + id = 'article-share-box-' + $this.attr('data-id'), + offset = $this.offset(); + + if ($('#' + id).length){ + var box = $('#' + id); + + if (box.hasClass('on')){ + box.removeClass('on'); + return; + } + } else { + var html = [ + '
', + '', + '
', + '', + '', + '', + '', + '
', + '
' + ].join(''); + + var box = $(html); + + $('body').append(box); + } + + $('.article-share-box.on').hide(); + + box.css({ + top: offset.top + 25, + left: offset.left + }).addClass('on'); + }).on('click', '.article-share-box', function(e){ + e.stopPropagation(); + }).on('click', '.article-share-box-input', function(){ + $(this).select(); + }).on('click', '.article-share-box-link', function(e){ + e.preventDefault(); + e.stopPropagation(); + + window.open(this.href, 'article-share-box-window-' + Date.now(), 'width=500,height=450'); + }); + + // Caption + $('.article-entry').each(function(i){ + $(this).find('img').each(function(){ + if ($(this).parent().hasClass('fancybox')) return; + + var alt = this.alt; + + if (alt) $(this).after('' + alt + ''); + + $(this).wrap(''); + }); + + $(this).find('.fancybox').each(function(){ + $(this).attr('rel', 'article' + i); + }); + }); + + if ($.fancybox){ + $('.fancybox').fancybox(); + } + + // Mobile nav + var $container = $('#container'), + isMobileNavAnim = false, + mobileNavAnimDuration = 200; + + var startMobileNavAnim = function(){ + isMobileNavAnim = true; + }; + + var stopMobileNavAnim = function(){ + setTimeout(function(){ + isMobileNavAnim = false; + }, mobileNavAnimDuration); + } + + $('#main-nav-toggle').on('click', function(){ + if (isMobileNavAnim) return; + + startMobileNavAnim(); + $container.toggleClass('mobile-nav-on'); + stopMobileNavAnim(); + }); + + $('#wrap').on('click', function(){ + if (isMobileNavAnim || !$container.hasClass('mobile-nav-on')) return; + + $container.removeClass('mobile-nav-on'); + }); +})(jQuery); \ No newline at end of file diff --git a/js/semantic-ui-algolia.js b/js/semantic-ui-algolia.js deleted file mode 100644 index d94a9ac..0000000 --- a/js/semantic-ui-algolia.js +++ /dev/null @@ -1,88 +0,0 @@ -function semanticUiAlgolia() { - - var applicationID = algolia.applicationID; - var apiKey = algolia.apiKey; - var index = algolia.indexName; - - var client = algoliasearch(applicationID, apiKey); - var helper = algoliasearchHelper(client, index); - helper.setQueryParameter('restrictSearchableAttributes', 'title,tags.name'); - helper.setQueryParameter('typoTolerance', 'true'); - helper.setQueryParameter('hitsPerPage', '10'); - - helper.on('result', function (content) { - renderHits(content); - console.log(content); - }); - - function renderHits(content) { - $('#search-results').html(function () { - return $.map(content.hits, function (hit) { - return renderHit(hit) - }); - }); - } - - function renderHit(hit) { - var result = ''; - result = result + '
'; - result = result + hit._highlightResult.title.value; - result = result + '
'; - result = result + renderTags(hit._highlightResult.tags, hit.tags); - result = result + '
'; - return result; - } - - function renderTags(tags, tagsRaw) { - var result = ''; - - for (var i = 0; i < tags.length; i++) { - var tag = tags[i]; - var tagRaw = tagsRaw[i]; - var string = tag.name.value; - if (string.indexOf('') != -1) { - var temp = string.replace('', '').replace('', ''); - result = result + '' + temp + ''; - } else { - result = result + '' + string + ''; - } - } - - return result; - } - - function reset() { - $('#search-results').empty(); - $('#search-box').val(''); - } - - $('#search-box').on('keyup', function () { - - if ($(this).val() == '') { - reset(); - } else { - helper.setQuery($(this).val()) - .search(); - } - - }); - - $('#search-input').on('focus click keyup keypress', function () { - $('#search-modal') - .modal({ - inverted: true, - observeChanges: true, - onVisible: function () { - $("#search-input").blur(); - $("#search-input").val(''); - }, - onHidden: reset - }).modal('show'); - - }) - -} - -if(algoliaEnabled) { - semanticUiAlgolia(); -} \ No newline at end of file From 5a6e609349840b9e016476a3a23dbfb90e8bd0e5 Mon Sep 17 00:00:00 2001 From: CoderShmily Date: Tue, 4 Apr 2017 11:23:25 +0800 Subject: [PATCH 021/148] Customize commit message --- categories/iOS/index.html | 279 -------------------------------------- 1 file changed, 279 deletions(-) delete mode 100644 categories/iOS/index.html diff --git a/categories/iOS/index.html b/categories/iOS/index.html deleted file mode 100644 index 5e35da9..0000000 --- a/categories/iOS/index.html +++ /dev/null @@ -1,279 +0,0 @@ - - - - - - Category: iOS | CoderShmily's Blog - - - - - - - - - - - - - - - - - - - - - - - -
-
- -
-
- - - - - - -
-
- 2015 -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - -
-
- -
- -
-
-
- - - - - - - - - - - - - - - -
- - \ No newline at end of file From 34cb0fa1088fa12c3fc4a51558a7d267795a5a12 Mon Sep 17 00:00:00 2001 From: CoderShmily Date: Tue, 4 Apr 2017 11:27:56 +0800 Subject: [PATCH 022/148] Customize commit message --- categories/iOS/index.html | 279 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 279 insertions(+) create mode 100644 categories/iOS/index.html diff --git a/categories/iOS/index.html b/categories/iOS/index.html new file mode 100644 index 0000000..5e35da9 --- /dev/null +++ b/categories/iOS/index.html @@ -0,0 +1,279 @@ + + + + + + Category: iOS | CoderShmily's Blog + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + + + + +
+
+ 2015 +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + +
+ + \ No newline at end of file From 6620c7fa5aa4c269c0fcfc8a732e7890b0136c47 Mon Sep 17 00:00:00 2001 From: CoderShmily Date: Tue, 4 Apr 2017 11:30:41 +0800 Subject: [PATCH 023/148] Customize commit message --- 2015/05/01/2015-05-01-Swift-ru-men/index.html | 2 + 2015/05/02/2015-05-02-singleton/index.html | 2 + .../2015-05-03-kvc-he-kvoshen-ru/index.html | 2 + .../index.html | 2 + .../05/2015-05-05-runtime-gai-shu/index.html | 2 + .../index.html | 2 + .../index.html | 2 + .../index.html | 2 + .../2016-11-15-Swift3.0-jie-shao/index.html | 7 + categories/iOS/index.html | 279 ------------------ 10 files changed, 23 insertions(+), 279 deletions(-) delete mode 100644 categories/iOS/index.html diff --git a/2015/05/01/2015-05-01-Swift-ru-men/index.html b/2015/05/01/2015-05-01-Swift-ru-men/index.html index 4de9e2f..642106d 100644 --- a/2015/05/01/2015-05-01-Swift-ru-men/index.html +++ b/2015/05/01/2015-05-01-Swift-ru-men/index.html @@ -75,6 +75,8 @@

+ +

特色

  • 苹果宣称 Swift 的特点是:快速、现代、安全、互动,而且明显优于 Objective-C 语言
  • 可以使用现有的 CocoaCocoa Touch 框架
  • diff --git a/2015/05/02/2015-05-02-singleton/index.html b/2015/05/02/2015-05-02-singleton/index.html index 3bcc891..f42d7ef 100644 --- a/2015/05/02/2015-05-02-singleton/index.html +++ b/2015/05/02/2015-05-02-singleton/index.html @@ -58,6 +58,8 @@

    + +

    单例在整个工程中,就相当于一个全局变量,就是不论在哪里需要用到这个类的实例变量,都可以通过单例方法来取得,而且一旦你创建了一个单例类,不论你在多少个界面中初始化调用了这个单例方法取得对象,它们所有的对象都是指向的同一块内存存储空间(即单例类保证了该类的实力对象是唯一存在的一个).

    单例模式的作用

      diff --git a/2015/05/03/2015-05-03-kvc-he-kvoshen-ru/index.html b/2015/05/03/2015-05-03-kvc-he-kvoshen-ru/index.html index 7c56a5e..e80d4e0 100644 --- a/2015/05/03/2015-05-03-kvc-he-kvoshen-ru/index.html +++ b/2015/05/03/2015-05-03-kvc-he-kvoshen-ru/index.html @@ -58,6 +58,8 @@

      + +

      KVC 和 KVO深入

      KVC概述

      1.什么是KVC?

      KVC即NSKeyValueCoding,键/值编码,一个非正式的Protocol,以字符串的形式向对象发送消息,而不是通过调用存取方法,直接或通过实例变量访问的机制。

      diff --git a/2015/05/04/2015-05-04-runtime-dui-xiang-mo-xing/index.html b/2015/05/04/2015-05-04-runtime-dui-xiang-mo-xing/index.html index f451c33..65a6550 100644 --- a/2015/05/04/2015-05-04-runtime-dui-xiang-mo-xing/index.html +++ b/2015/05/04/2015-05-04-runtime-dui-xiang-mo-xing/index.html @@ -61,6 +61,8 @@

      + +

      Objective-C语言是一门动态语言,它将很多静态语言在编译和链接时期做的事放到了运行时来处理。这种动态语言的优势在于:我们写代码时更具灵活性,如我们可以把消息转发给我们想要的对象,或者随意交换一个方法的实现等。

      这种特性意味着Objective-C不仅需要一个编译器,还需要一个运行时系统来执行编译的代码。对于Objective-C来说,这个运行时系统就像一个操作系统一样:它让所有的工作可以正常的运行。这个运行时系统即Objc Runtime。Objc Runtime其实是一个Runtime库,它基本上是用C和汇编写的,这个库使得C语言有了面向对象的能力。

      diff --git a/2015/05/05/2015-05-05-runtime-gai-shu/index.html b/2015/05/05/2015-05-05-runtime-gai-shu/index.html index b2e97e7..080469c 100644 --- a/2015/05/05/2015-05-05-runtime-gai-shu/index.html +++ b/2015/05/05/2015-05-05-runtime-gai-shu/index.html @@ -58,6 +58,8 @@

      + +

      Runtime常用方法和一些应用

      Runtime方法列表

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      # class
      class_getInstanceMethod -> Method class_getInstanceMethod(Class cls, SEL name);// 返回给定类的指定的实例方法
      class_addMethod -> BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types);// 通过方法名SEL+原来的IMP实现给类添加新方法
      class_copyPropertyList -> objc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount) // 获取类的属性列表
      # method
      method_getTypeEncoding -> const char *method_getTypeEncoding(Method m);// Returns a string describing a method's parameter and return types.
      method_getImplementation -> IMP method_getImplementation(Method m);//获取Method中的IMP
      method_exchangeImplementations -> method_exchangeImplementations(Method m1, Method m2); //Returns a string describing a method's parameter and return types.
      method_setImplementation -> IMP method_setImplementation(Method m, IMP imp); // Sets the implementation of a method.
      # 关联对象
      objc_setAssociatedObject -> objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy);//Sets an associated value for a given object using a given key and association policy.
      objc_getAssociatedObject -> id objc_getAssociatedObject(id object, const void *key);// Returns the value associated with a given object for a given key.
      objc_removeAssociatedObjects -> objc_removeAssociatedObjects(id object);// 注意:Removes all associations for a given object.
      # 类
      object_isClass -> BOOL object_isClass(id obj);//Returns whether an object is a class object.
      object_getClass -> Class object_getClass(id obj);//Returns the class of an object.
      object_getClassName -> const char *object_getClassName(id obj);//Returns the class name of a given object.
      object_setClass -> Class object_setClass(id obj, Class cls);//Sets the class of an object.
      objc_getMetaClass -> Class objc_getMetaClass(const char *name);// 原类
      # 实例变量
      object_getIvar -> id object_getIvar(id obj, Ivar ivar);//Reads the value of an instance variable in an object.
      object_setIvar -> object_setIvar(id obj, Ivar ivar, id value);//Sets the value of an instance variable in an object.
      // Changes the value of an 实例变量 of a 实例
      object_getInstanceVariable -> Ivar object_getInstanceVariable(id obj, const char *name, void **outValue)
      object_setInstanceVariable -> Ivar object_setInstanceVariable(id obj, const char *name, void *value);
      # 属性
      property_getName -> const char *property_getName(objc_property_t property) // 传入上面的数组(指针)获取每个属性的名称
      property_getAttributes -> const char *property_getAttributes(objc_property_t property) // 返回属性的名称和@encode类型字符串
      # 发送消息
      objc_msgSend -> objc_msgSend(id obj, SEL name);
      diff --git a/2015/05/06/2015-05-06-objective-c-runtime-san-xiao-xi-chuan-di/index.html b/2015/05/06/2015-05-06-objective-c-runtime-san-xiao-xi-chuan-di/index.html index a2bfbd1..891aa4f 100644 --- a/2015/05/06/2015-05-06-objective-c-runtime-san-xiao-xi-chuan-di/index.html +++ b/2015/05/06/2015-05-06-objective-c-runtime-san-xiao-xi-chuan-di/index.html @@ -58,6 +58,8 @@

      + +

      Objective-C Runtime的消息传递

      ###Objective-C – 消息传递
      Objective-C 扩展了 C 语言,并加入了面向对象特性和 Smalltalk 式的消息传递机制。而这个扩展的核心是一个用 C 和 编译语言 写的 Runtime 库。它是 Objective-C 面向对象和动态机制的基石.

      Objective-C 是一个动态语言,这意味着它不仅需要一个编译器,也需要一个运行时系统来动态得创建类和对象、进行消息传递和转发。理解 Objective-C 的 Runtime 机制可以帮我们更好的了解这个语言,适当的时候还能对语言进行扩展,从系统层面解决项目中的一些设计或技术问题。了解 Runtime ,要先了解它的核心 - 消息传递(Messaging)。

      diff --git a/2015/05/07/2015-05-07-objective-c-runtime-si-dong-tai-fang-fa-jue-yi-dynamic-method-resolution/index.html b/2015/05/07/2015-05-07-objective-c-runtime-si-dong-tai-fang-fa-jue-yi-dynamic-method-resolution/index.html index fb365e2..a27c103 100644 --- a/2015/05/07/2015-05-07-objective-c-runtime-si-dong-tai-fang-fa-jue-yi-dynamic-method-resolution/index.html +++ b/2015/05/07/2015-05-07-objective-c-runtime-si-dong-tai-fang-fa-jue-yi-dynamic-method-resolution/index.html @@ -58,6 +58,8 @@

      + +

      Objective-C Runtime之动态方法决议

      动态方法决议/动态方法解析(Dynamic Method Resolution)

      diff --git a/2015/05/15/2015-05-15-sdwebimageyuan-ma-jie-xi/index.html b/2015/05/15/2015-05-15-sdwebimageyuan-ma-jie-xi/index.html index 6ed1eac..b9c551f 100644 --- a/2015/05/15/2015-05-15-sdwebimageyuan-ma-jie-xi/index.html +++ b/2015/05/15/2015-05-15-sdwebimageyuan-ma-jie-xi/index.html @@ -58,6 +58,8 @@

      + +

      SDWebImage源码解析

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      86
      87
      88
      89
      90
      91
      92
      93
      94
      95
      96
      97
      98
      99
      100
      101
      102
      103
      104
      105
      106
      107
      108
      109
      110
      111
      112
      113
      114
      115
      116
      117
      118
      119
      120
      121
      122
      123
      124
      125
      126
      127
      128
      129
      130
      131
      132
      133
      134
      135
      136
      137
      138
      139
      140
      141
      142
      143
      144
      145
      146
      147
      148
      149
      150
      151
      152
      153
      154
      155
      156
      157
      158
      159
      160
      161
      162
      163
      164
      165
      166
      167
      168
      169
      170
      171
      172
      173
      174
      175
      176
      177
      178
      179
      180
      181
      182
      183
      184
      185
      186
      187
      188
      189
      190
      191
      192
      193
      194
      195
      196
      197
      198
      199
      200
      201
      202
      203
      204
      205
      206
      207
      208
      209
      210
      211
      212
      213
      214
      215
      216
      217
      218
      219
      220
      221
      222
      223
      224
      225
      226
      227
      228
      229
      230
      231
      232
      233
      234
      235
      236
      237
      238
      239
      240
      241
      242
      243
      244
      245
      246
      247
      248
      249
      250
      251
      252
      253
      254
      255
      256
      257
      258
      259
      260
      261
      262
      263
      264
      265
      266
      267
      268
      269
      270
      271
      272
      273
      274
      275
      276
      277
      278
      279
      280
      281
      282
      283
      284
      285
      286
      287
      288
      289
      290
      291
      292
      293
      294
      295
      296
      297
      298
      299
      300
      301
      302
      303
      304
      305
      306
      307
      308
      309
      310
      311
      312
      313
      314
      315
      316
      317
      318
      319
      320
      321
      322
      323
      324
      325
      326
      327
      328
      329
      330
      331
      332
      333
      334
      335
      336
      337
      338
      339
      340
      341
      342
      343
      344
      345
      346
      347
      348
      349
      350
      351
      352
      353
      354
      355
      356
      357
      358
      359
      360
      361
      362
      363
      364
      365
      366
      367
      368
      369
      370
      371
      372
      373
      374
      375
      376
      377
      378
      379
      380
      381
      382
      383
      /*
      * This file is part of the SDWebImage package.
      * (c) Olivier Poitrey <rs@dailymotion.com>
      *
      * For the full copyright and license information, please view the LICENSE
      * file that was distributed with this source code.
      */
      #import "SDWebImageCompat.h"
      #import "SDWebImageOperation.h"
      #import "SDWebImageDownloader.h"
      #import "SDImageCache.h"
      typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) {
      /**
      * By default, when a URL fail to be downloaded, the URL is blacklisted so the library won't keep trying.
      * This flag disable this blacklisting.
      */
      /**
      *默认情况下,如果一个url在下载的时候失败了,那么这个url会被加入黑名单并且library不会尝试再次下载,这个flag会阻止library把失败的url加入黑名单(简单来说如果选择了这个flag,那么即使某个url下载失败了,sdwebimage还是会尝试再次下载他.)
      */
      SDWebImageRetryFailed = 1 << 0,
      /**
      * By default, image downloads are started during UI interactions, this flags disable this feature,
      * leading to delayed download on UIScrollView deceleration for instance.
      */
      /**
      *默认情况下,图片会在交互发生的时候下载(例如你滑动tableview的时候),这个flag会禁止这个特性,导致的结果就是在scrollview减速的时候
      *才会开始下载(也就是你滑动的时候scrollview不下载,你手从屏幕上移走,scrollview开始减速的时候才会开始下载图片)
      */
      SDWebImageLowPriority = 1 << 1,
      /**
      * This flag disables on-disk caching
      */
      /*
      *这个flag禁止磁盘缓存,只有内存缓存
      */
      SDWebImageCacheMemoryOnly = 1 << 2,
      /**
      * This flag enables progressive download, the image is displayed progressively during download as a browser would do.
      * By default, the image is only displayed once completely downloaded.
      */
      /*
      *这个flag会在图片下载的时候就显示(就像你用浏览器浏览网页的时候那种图片下载,一截一截的显示(待确认))
      *
      */
      SDWebImageProgressiveDownload = 1 << 3,
      /**
      * Even if the image is cached, respect the HTTP response cache control, and refresh the image from remote location if needed.
      * The disk caching will be handled by NSURLCache instead of SDWebImage leading to slight performance degradation.
      * This option helps deal with images changing behind the same request URL, e.g. Facebook graph api profile pics.
      * If a cached image is refreshed, the completion block is called once with the cached image and again with the final image.
      *
      * Use this flag only if you can't make your URLs static with embeded cache busting parameter.
      */
      /*
      *这个选项的意思看的不是很懂,大意是即使一个图片缓存了,还是会重新请求.并且缓存侧略依据NSURLCache而不是SDWebImage.
      *
      */
      SDWebImageRefreshCached = 1 << 4,
      /**
      * In iOS 4+, continue the download of the image if the app goes to background. This is achieved by asking the system for
      * extra time in background to let the request finish. If the background task expires the operation will be cancelled.
      */
      /*
      *启动后台下载,加入你进入一个页面,有一张图片正在下载这时候你让app进入后台,图片还是会继续下载(这个估计要开backgroundfetch才有用)
      */
      SDWebImageContinueInBackground = 1 << 5,
      /**
      * Handles cookies stored in NSHTTPCookieStore by setting
      * NSMutableURLRequest.HTTPShouldHandleCookies = YES;
      */
      /*
      *可以控制存在NSHTTPCookieStore的cookies.(我没用过,等用过的人过来解释一下)
      */
      SDWebImageHandleCookies = 1 << 6,
      /**
      * Enable to allow untrusted SSL ceriticates.
      * Useful for testing purposes. Use with caution in production.
      */
      /*
      *允许不安全的SSL证书,在正式环境中慎用
      */
      SDWebImageAllowInvalidSSLCertificates = 1 << 7,
      /**
      * By default, image are loaded in the order they were queued. This flag move them to
      * the front of the queue and is loaded immediately instead of waiting for the current queue to be loaded (which
      * could take a while).
      */
      /*
      *默认情况下,image在装载的时候是按照他们在队列中的顺序装载的(就是先进先出).这个flag会把他们移动到队列的前端,并且立刻装载
      *而不是等到当前队列装载的时候再装载.
      */
      SDWebImageHighPriority = 1 << 8,
      /**
      * By default, placeholder images are loaded while the image is loading. This flag will delay the loading
      * of the placeholder image until after the image has finished loading.
      */
      /*
      *默认情况下,占位图会在图片下载的时候显示.这个flag开启会延迟占位图显示的时间,等到图片下载完成之后才会显示占位图.(等图片显示完了我干嘛还显示占位图?或许是我理解错了?)
      */
      SDWebImageDelayPlaceholder = 1 << 9,
      /**
      * We usually don't call transformDownloadedImage delegate method on animated images,
      * as most transformation code would mangle it.
      * Use this flag to transform them anyway.
      */
      /*
      *是否transform图片(没用过,还要再看,但是据我估计,是否是图片有可能方向不对需要调整方向,例如采用iPhone拍摄的照片如果不纠正方向,那么图片是向左旋转90度的.可能很多人不知道iPhone的摄像头并不是竖直的,而是向左偏了90度.具体请google.)
      */
      SDWebImageTransformAnimatedImage = 1 << 10,
      };
      typedef void(^SDWebImageCompletionBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL);
      typedef void(^SDWebImageCompletionWithFinishedBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL);
      typedef NSString *(^SDWebImageCacheKeyFilterBlock)(NSURL *url);
      @class SDWebImageManager;
      @protocol SDWebImageManagerDelegate <NSObject>
      @optional
      /**
      * Controls which image should be downloaded when the image is not found in the cache.
      *
      * @param imageManager The current `SDWebImageManager`
      * @param imageURL The url of the image to be downloaded
      *
      * @return Return NO to prevent the downloading of the image on cache misses. If not implemented, YES is implied.
      */
      /*
      *主要作用是当缓存里没有发现某张图片的缓存时,是否选择下载这张图片(默认是yes),可以选择no,那么sdwebimage在缓存中没有找到这张图片的时候不会选择下载
      */
      - (BOOL)imageManager:(SDWebImageManager *)imageManager shouldDownloadImageForURL:(NSURL *)imageURL;
      /**
      * Allows to transform the image immediately after it has been downloaded and just before to cache it on disk and memory.
      * NOTE: This method is called from a global queue in order to not to block the main thread.
      *
      * @param imageManager The current `SDWebImageManager`
      * @param image The image to transform
      * @param imageURL The url of the image to transform
      *
      * @return The transformed image object.
      */
      /**
      *在图片下载完成并且还没有加入磁盘缓存或者内存缓存的时候就transform这个图片.这个方法是在异步线程执行的,防治阻塞主线程.
      *至于为什么在异步执行很简单,对一张图片纠正方向(也就是transform)是很耗资源的,一张2M大小的图片纠正方向你可以用instrument测试一下耗时.
      *很恐怖
      */
      - (UIImage *)imageManager:(SDWebImageManager *)imageManager transformDownloadedImage:(UIImage *)image withURL:(NSURL *)imageURL;
      @end
      /**
      * The SDWebImageManager is the class behind the UIImageView+WebCache category and likes.
      * It ties the asynchronous downloader (SDWebImageDownloader) with the image cache store (SDImageCache).
      * You can use this class directly to benefit from web image downloading with caching in another context than
      * a UIView.
      *
      * Here is a simple example of how to use SDWebImageManager:
      *
      * @code
      SDWebImageManager *manager = [SDWebImageManager sharedManager];
      [manager downloadImageWithURL:imageURL
      options:0
      progress:nil
      completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
      if (image) {
      // do something with image
      }
      }];
      * @endcode
      */
      /*
      *这一段是阐述SDWebImageManager是干嘛的.其实UIImageView+WebCache这个category背后执行操作的就是这个SDWebImageManager.他会绑定一个下载器也就是SDWebImageDownloader和一个缓存SDImageCache.后面的大意应该是讲你可以直接使用一个其他上下文环境的SDWebImageManager,而不是仅仅限于一个UIView.
      */
      @interface SDWebImageManager : NSObject
      @property (weak, nonatomic) id <SDWebImageManagerDelegate> delegate;
      /**
      *如同上文所说,一个SDWebImageManager会绑定一个imageCache和一个下载器.
      */
      @property (strong, nonatomic, readonly) SDImageCache *imageCache;
      @property (strong, nonatomic, readonly) SDWebImageDownloader *imageDownloader;
      /**
      * The cache filter is a block used each time SDWebImageManager need to convert an URL into a cache key. This can
      * be used to remove dynamic part of an image URL.
      *
      * The following example sets a filter in the application delegate that will remove any query-string from the
      * URL before to use it as a cache key:
      *
      * @code
      [[SDWebImageManager sharedManager] setCacheKeyFilter:^(NSURL *url) {
      url = [[NSURL alloc] initWithScheme:url.scheme host:url.host path:url.path];
      return [url absoluteString];
      }];
      * @endcode
      */
      /*
      * 这个cacheKeyFilter是干嘛的呢?很简单.1他是一个block.2.这个block的作用就是生成一个image的key.因为sdwebimage的缓存原理你可以当成是一个字典,每一个字典的value就是一张image,那么这个value对应的key是什么呢?就是cacheKeyFilter根据某个规则对这个图片的url做一些操作生成的.上面的示例就显示了怎么利用这个block把image的url重新组合生成一个key.以后当sdwebimage检测到你
      */
      @property (nonatomic, copy) SDWebImageCacheKeyFilterBlock cacheKeyFilter;
      /**
      * Returns global SDWebImageManager instance.
      *
      * @return SDWebImageManager shared instance
      */
      /*
      *这个不用我解释了吧,生成一个SDWebImagemanager的单例.
      */
      + (SDWebImageManager *)sharedManager;
      /**
      * Downloads the image at the given URL if not present in cache or return the cached version otherwise.
      * 从给定的URL中下载一个之前没有被缓存的Image.
      *
      * @param url The URL to the image
      * @param options A mask to specify options to use for this request
      * @param progressBlock A block called while image is downloading
      * @param completedBlock A block called when operation has been completed.
      *
      * This parameter is required.
      *
      * This block has no return value and takes the requested UIImage as first parameter.
      * In case of error the image parameter is nil and the second parameter may contain an NSError.
      *
      * The third parameter is an `SDImageCacheType` enum indicating if the image was retrived from the local cache
      * or from the memory cache or from the network.
      *
      * The last parameter is set to NO when the SDWebImageProgressiveDownload option is used and the image is
      * downloading. This block is thus called repetidly with a partial image. When image is fully downloaded, the
      * block is called a last time with the full image and the last parameter set to YES.
      *
      * @return Returns an NSObject conforming to SDWebImageOperation. Should be an instance of SDWebImageDownloaderOperation
      */
      /*
      * 这个方法主要就是SDWebImage下载图片的方法了.
      * 第一个参数是必须要的,就是image的url
      * 第二个参数就是我们上面的Options,你可以定制化各种各样的操作.详情参上.
      * 第三个参数是一个回调block,用于图片在下载过程中的回调.(英文注释应该是有问题的.)
      * 第四个参数是一个下载完成的回调.会在图片下载完成后回调.
      * 返回值是一个NSObject类,并且这个NSObject类是conforming一个协议这个协议叫做SDWebImageOperation,这个协议很简单,就是一个cancel掉operation的协议.
      */
      - (id <SDWebImageOperation>)downloadImageWithURL:(NSURL *)url
      options:(SDWebImageOptions)options
      progress:(SDWebImageDownloaderProgressBlock)progressBlock
      completed:(SDWebImageCompletionWithFinishedBlock)completedBlock;
      /**
      * Saves image to cache for given URL
      *
      * @param image The image to cache
      * @param url The URL to the image
      *
      */
      /*
      * 将图片存入cache的方法,类似于字典的setValue: forKey:
      */
      - (void)saveImageToCache:(UIImage *)image forURL:(NSURL *)url;
      /**
      * Cancel all current opreations
      */
      /*
      *取消掉当前所有的下载图片的operation
      */
      - (void)cancelAll;
      /**
      * Check one or more operations running
      */
      /*
      * check一下是否有一个或者多个operation正在执行(简单来说就是check是否有图片在下载)
      */
      - (BOOL)isRunning;
      /**
      * Check if image has already been cached
      *
      * @param url image url
      *
      * @return if the image was already cached
      */
      /*
      * 通过一个image的url是否已经存在,如果存在返回yes,否则返回no
      */
      - (BOOL)cachedImageExistsForURL:(NSURL *)url;
      /**
      * Check if image has already been cached on disk only
      *
      * @param url image url
      *
      * @return if the image was already cached (disk only)
      */
      /*
      * 检测一个image是否已经被缓存到磁盘(是否存且仅存在disk里).
      */
      - (BOOL)diskImageExistsForURL:(NSURL *)url;
      /**
      * Async check if image has already been cached
      *
      * @param url image url
      * @param completionBlock the block to be executed when the check is finished
      *
      * @note the completion block is always executed on the main queue
      */
      /*
      * 如果检测到图片已经被缓存,那么执行回调block.这个block会永远执行在主线程.也就是你可以在这个回调block里更新ui.
      */
      - (void)cachedImageExistsForURL:(NSURL *)url
      completion:(SDWebImageCheckCacheCompletionBlock)completionBlock;
      /**
      * Async check if image has already been cached on disk only
      *
      * @param url image url
      * @param completionBlock the block to be executed when the check is finished
      *
      * @note the completion block is always executed on the main queue
      */
      /*
      * 如果检测到图片已经被缓存在磁盘(存且仅存在disk),那么执行回调block.这个block会永远执行在主线程.也就是你可以在这个回调block里更新ui.
      */
      - (void)diskImageExistsForURL:(NSURL *)url
      completion:(SDWebImageCheckCacheCompletionBlock)completionBlock;
      /**
      *Return the cache key for a given URL
      */
      /*
      * 通过image的url返回image存在缓存里的key.有人会问了,为什么不直接把图片的url当做image的key来使用呢?而是非要对url做一些处理才能当做key.我的解释是,我也不太清楚.可能为了防止重复吧.
      */
      - (NSString *)cacheKeyForURL:(NSURL *)url;
      @end
      #pragma mark - Deprecated
      typedef void(^SDWebImageCompletedBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType) __deprecated_msg("Block type deprecated. Use `SDWebImageCompletionBlock`");
      typedef void(^SDWebImageCompletedWithFinishedBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished) __deprecated_msg("Block type deprecated. Use `SDWebImageCompletionWithFinishedBlock`");
      // 已被废弃
      @interface SDWebImageManager (Deprecated)
      /**
      * Downloads the image at the given URL if not present in cache or return the cached version otherwise.
      *
      * @deprecated This method has been deprecated. Use `downloadImageWithURL:options:progress:completed:`
      */
      - (id <SDWebImageOperation>)downloadWithURL:(NSURL *)url
      options:(SDWebImageOptions)options
      progress:(SDWebImageDownloaderProgressBlock)progressBlock
      completed:(SDWebImageCompletedWithFinishedBlock)completedBlock __deprecated_msg("Method deprecated. Use `downloadImageWithURL:options:progress:completed:`");
      @end
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      86
      87
      88
      89
      90
      91
      92
      93
      94
      95
      96
      97
      98
      99
      100
      101
      102
      103
      104
      105
      106
      107
      108
      109
      110
      111
      112
      113
      114
      115
      116
      117
      118
      119
      120
      121
      122
      123
      124
      125
      126
      127
      128
      129
      130
      131
      132
      133
      134
      135
      136
      137
      138
      139
      140
      141
      142
      143
      144
      145
      146
      147
      148
      149
      150
      151
      152
      153
      154
      155
      156
      157
      158
      159
      160
      161
      162
      163
      164
      165
      166
      167
      168
      169
      170
      171
      172
      173
      174
      175
      176
      177
      178
      179
      180
      181
      182
      183
      184
      185
      186
      187
      188
      189
      190
      191
      192
      193
      194
      195
      196
      197
      198
      199
      200
      201
      202
      203
      204
      205
      206
      207
      208
      209
      210
      211
      212
      213
      214
      215
      216
      217
      218
      219
      220
      221
      222
      223
      224
      225
      226
      227
      228
      229
      230
      231
      232
      233
      234
      235
      236
      237
      238
      239
      240
      241
      242
      243
      244
      245
      246
      247
      248
      249
      250
      251
      252
      253
      254
      255
      256
      257
      258
      259
      260
      261
      262
      263
      264
      265
      266
      267
      268
      269
      270
      271
      272
      273
      274
      275
      276
      277
      278
      279
      280
      281
      282
      283
      284
      285
      286
      287
      288
      289
      290
      291
      292
      293
      294
      295
      296
      297
      298
      299
      300
      301
      302
      303
      304
      305
      306
      307
      308
      309
      310
      311
      312
      313
      314
      315
      316
      317
      318
      319
      320
      321
      322
      323
      324
      325
      326
      327
      328
      329
      330
      331
      332
      333
      334
      335
      336
      337
      338
      339
      340
      341
      342
      343
      344
      345
      346
      347
      348
      349
      350
      351
      352
      353
      354
      355
      356
      357
      358
      359
      360
      361
      362
      363
      364
      365
      366
      367
      368
      369
      370
      371
      372
      373
      374
      375
      376
      377
      378
      379
      380
      381
      382
      383
      384
      385
      386
      387
      388
      389
      390
      #import <Foundation/Foundation.h>
      /*
      * This file is part of the SDWebImage package.
      *
      * For the full copyright and license information, please view the LICENSE
      * file that was distributed with this source code.
      */
      #import "SDWebImageManager.h"
      #import <objc/message.h>
      // 内部类.
      @interface SDWebImageCombinedOperation : NSObject <SDWebImageOperation>
      @property (assign, nonatomic, getter = isCancelled) BOOL cancelled;
      @property (copy, nonatomic) SDWebImageNoParamsBlock cancelBlock;
      @property (strong, nonatomic) NSOperation *cacheOperation;
      @end
      @interface SDWebImageManager ()
      @property (strong, nonatomic, readwrite) SDImageCache *imageCache;
      @property (strong, nonatomic, readwrite) SDWebImageDownloader *imageDownloader;
      @property (strong, nonatomic) NSMutableSet *failedURLs;
      @property (strong, nonatomic) NSMutableArray *runningOperations;
      @end
      @implementation SDWebImageManager
      // 利用disptach_once 特性生成一个单例,用烂了的方法.不赘述.
      + (id)sharedManager {
      static dispatch_once_t once;
      static id instance;
      dispatch_once(&once, ^{
      instance = [self new];
      });
      return instance;
      }
      // 初始化方法.
      // 1.获得一个SDImageCache的单例.2.获取一个SDWebImageDownloader的单例.3.新建一个MutableSet来存储下载失败的url.
      // 4.新建一个用来存储下载operation的可变数组.
      // 为什么不用MutableArray储存下载失败的URL?
      // 因为NSSet类有一个特性,就是Hash.实际上NSSet是一个哈希表,哈希表比数组优秀的地方是什么呢?就是查找速度快.查找同样一个元素,哈希表只需要通过key
      // 即可取到,而数组至少需要遍历依次.因为SDWebImage里有关失败URL的业务需求是,一个失败的URL只需要储存一次.这样的话Set自然比Array更合适.
      - (id)init {
      if ((self = [super init])) {
      _imageCache = [self createCache];
      _imageDownloader = [SDWebImageDownloader sharedDownloader];
      _failedURLs = [NSMutableSet new];
      _runningOperations = [NSMutableArray new];
      }
      return self;
      }
      // 获取一个cache的单例
      - (SDImageCache *)createCache {
      return [SDImageCache sharedImageCache];
      }
      // 利用Image的URL生成一个缓存时需要的key.
      // 这里有两种情况,第一种是如果检测到cacheKeyFilter不为空时,利用cacheKeyFilter来处理URL生成一个key.
      // 如果为空,那么直接返回URL的string内容,当做key.
      - (NSString *)cacheKeyForURL:(NSURL *)url {
      if (self.cacheKeyFilter) {
      return self.cacheKeyFilter(url);
      }
      else {
      return [url absoluteString];
      }
      }
      // 检测一张图片是否已被缓存.
      // 首先检测内存缓存是否存在这张图片,如果已有,直接返回yes.
      // 如果内存缓存里没有这张图片,那么调用diskImageExistsWithKey这个方法去硬盘缓存里找
      - (BOOL)cachedImageExistsForURL:(NSURL *)url {
      NSString *key = [self cacheKeyForURL:url];
      if ([self.imageCache imageFromMemoryCacheForKey:key] != nil) return YES;
      return [self.imageCache diskImageExistsWithKey:key];
      }
      // 检测硬盘里是否缓存了图片
      - (BOOL)diskImageExistsForURL:(NSURL *)url {
      NSString *key = [self cacheKeyForURL:url];
      return [self.imageCache diskImageExistsWithKey:key];
      }
      // 首先生成一个用来cache 住Image的key(利用key的url生成)
      // 然后检测内存缓存里是否已经有这张图片
      // 如果已经被缓存,那么再主线程里回调block
      // 如果没有检测到,那么调用diskImageExistsWithKey,这个方法会在异步线程里,将图片存到硬盘,当然在存图之前也会检测是否已在硬盘缓存图片.
      - (void)cachedImageExistsForURL:(NSURL *)url
      completion:(SDWebImageCheckCacheCompletionBlock)completionBlock {
      NSString *key = [self cacheKeyForURL:url];
      BOOL isInMemoryCache = ([self.imageCache imageFromMemoryCacheForKey:key] != nil);
      if (isInMemoryCache) {
      // making sure we call the completion block on the main queue
      dispatch_async(dispatch_get_main_queue(), ^{
      if (completionBlock) {
      completionBlock(YES);
      }
      });
      return;
      }
      [self.imageCache diskImageExistsWithKey:key completion:^(BOOL isInDiskCache) {
      // the completion block of checkDiskCacheForImageWithKey:completion: is always called on the main queue, no need to further dispatch
      if (completionBlock) {
      completionBlock(isInDiskCache);
      }
      }];
      }
      //将图片存入硬盘
      - (void)diskImageExistsForURL:(NSURL *)url
      completion:(SDWebImageCheckCacheCompletionBlock)completionBlock {
      NSString *key = [self cacheKeyForURL:url];
      [self.imageCache diskImageExistsWithKey:key completion:^(BOOL isInDiskCache) {
      // the completion block of checkDiskCacheForImageWithKey:completion: is always called on the main queue, no need to further dispatch
      if (completionBlock) {
      completionBlock(isInDiskCache);
      }
      }];
      }
      // 通过url建立一个operation用来下载图片.
      - (id <SDWebImageOperation>)downloadImageWithURL:(NSURL *)url
      options:(SDWebImageOptions)options
      progress:(SDWebImageDownloaderProgressBlock)progressBlock
      completed:(SDWebImageCompletionWithFinishedBlock)completedBlock {
      // Invoking this method without a completedBlock is pointless
      NSAssert(completedBlock != nil, @"If you mean to prefetch the image, use -[SDWebImagePrefetcher prefetchURLs] instead");
      // Very common mistake is to send the URL using NSString object instead of NSURL. For some strange reason, XCode won't
      // throw any warning for this type mismatch. Here we failsafe this error by allowing URLs to be passed as NSString.
      if ([url isKindOfClass:NSString.class]) {
      url = [NSURL URLWithString:(NSString *)url];
      }
      // Prevents app crashing on argument type error like sending NSNull instead of NSURL
      if (![url isKindOfClass:NSURL.class]) {
      url = nil;
      }
      __block SDWebImageCombinedOperation *operation = [SDWebImageCombinedOperation new];
      __weak SDWebImageCombinedOperation *weakOperation = operation;
      BOOL isFailedUrl = NO;
      // 创建一个互斥锁防止现在有别的线程修改failedURLs.
      // 判断这个url是否是fail过的.如果url failed过的那么isFailedUrl就是true
      @synchronized (self.failedURLs) {
      isFailedUrl = [self.failedURLs containsObject:url];
      }
      // 如果url不存在那么直接返回一个block,如果url存在.那么继续进行判断.
      // options与SDWebImageRetryFailed这个option进行按位与操作.判断用户的options里是否有retry这个option.
      // 如果用户的options里没有retry这个选项并且isFaileUrl 是true.那么就回调一个error的block.
      if (!url || (!(options & SDWebImageRetryFailed) && isFailedUrl)) {
      dispatch_main_sync_safe(^{
      NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorFileDoesNotExist userInfo:nil];
      completedBlock(nil, error, SDImageCacheTypeNone, YES, url);
      });
      return operation;
      }
      // 创建一个互斥锁防止现在有别的线程修改runningOperations.
      @synchronized (self.runningOperations) {
      [self.runningOperations addObject:operation];
      }
      NSString *key = [self cacheKeyForURL:url];
      // cacheOperation应该是一个用来下载图片并且缓存的operation
      operation.cacheOperation = [self.imageCache queryDiskCacheForKey:key done:^(UIImage *image, SDImageCacheType cacheType) {
      // 判断operation这时候有没有执行cancel操作,如果cancel掉了就把这个operation从我们的operation数组里remove掉然后return
      if (operation.isCancelled) {
      @synchronized (self.runningOperations) {
      [self.runningOperations removeObject:operation];
      }
      return;
      }
      if ((!image || options & SDWebImageRefreshCached) && (![self.delegate respondsToSelector:@selector(imageManager:shouldDownloadImageForURL:)] || [self.delegate imageManager:self shouldDownloadImageForURL:url])) {
      if (image && options & SDWebImageRefreshCached) {
      dispatch_main_sync_safe(^{
      // If image was found in the cache bug SDWebImageRefreshCached is provided, notify about the cached image
      // AND try to re-download it in order to let a chance to NSURLCache to refresh it from server.
      completedBlock(image, nil, cacheType, YES, url);
      });
      }
      // download if no image or requested to refresh anyway, and download allowed by delegate
      // 下面都是判断我们的options里包含哪些SDWebImageOptions,然后给我们的downloaderOptions相应的添加对应的SDWebImageDownloaderOptions. downloaderOptions |= SDWebImageDownloaderLowPriority这种表达式的意思等同于
      // downloaderOptions = downloaderOptions | SDWebImageDownloaderLowPriority
      SDWebImageDownloaderOptions downloaderOptions = 0;
      if (options & SDWebImageLowPriority) downloaderOptions |= SDWebImageDownloaderLowPriority;
      if (options & SDWebImageProgressiveDownload) downloaderOptions |= SDWebImageDownloaderProgressiveDownload;
      if (options & SDWebImageRefreshCached) downloaderOptions |= SDWebImageDownloaderUseNSURLCache;
      if (options & SDWebImageContinueInBackground) downloaderOptions |= SDWebImageDownloaderContinueInBackground;
      if (options & SDWebImageHandleCookies) downloaderOptions |= SDWebImageDownloaderHandleCookies;
      if (options & SDWebImageAllowInvalidSSLCertificates) downloaderOptions |= SDWebImageDownloaderAllowInvalidSSLCertificates;
      if (options & SDWebImageHighPriority) downloaderOptions |= SDWebImageDownloaderHighPriority;
      if (image && options & SDWebImageRefreshCached) {
      // force progressive off if image already cached but forced refreshing
      downloaderOptions &= ~SDWebImageDownloaderProgressiveDownload;
      // ignore image read from NSURLCache if image if cached but force refreshing
      downloaderOptions |= SDWebImageDownloaderIgnoreCachedResponse;
      }
      // 调用imageDownloader去下载image并且返回执行这个request的download的operation
      id <SDWebImageOperation> subOperation = [self.imageDownloader downloadImageWithURL:url options:downloaderOptions progress:progressBlock completed:^(UIImage *downloadedImage, NSData *data, NSError *error, BOOL finished) {
      if (weakOperation.isCancelled) {
      // Do nothing if the operation was cancelled
      // See #699 for more details
      // if we would call the completedBlock, there could be a race condition between this block and another completedBlock for the same object, so if this one is called second, we will overwrite the new data
      }
      else if (error) {
      dispatch_main_sync_safe(^{
      if (!weakOperation.isCancelled) {
      completedBlock(nil, error, SDImageCacheTypeNone, finished, url);
      }
      });
      if (error.code != NSURLErrorNotConnectedToInternet && error.code != NSURLErrorCancelled && error.code != NSURLErrorTimedOut) {
      @synchronized (self.failedURLs) {
      [self.failedURLs addObject:url];
      }
      }
      }
      else {
      if ((options & SDWebImageRetryFailed)) {
      @synchronized (self.failedURLs) {
      [self.failedURLs removeObject:url];
      }
      }
      BOOL cacheOnDisk = !(options & SDWebImageCacheMemoryOnly);
      if (options & SDWebImageRefreshCached && image && !downloadedImage) {
      // Image refresh hit the NSURLCache cache, do not call the completion block
      }
      else if (downloadedImage && (!downloadedImage.images || (options & SDWebImageTransformAnimatedImage)) && [self.delegate respondsToSelector:@selector(imageManager:transformDownloadedImage:withURL:)]) {
      dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
      UIImage *transformedImage = [self.delegate imageManager:self transformDownloadedImage:downloadedImage withURL:url];
      if (transformedImage && finished) {
      BOOL imageWasTransformed = ![transformedImage isEqual:downloadedImage];
      [self.imageCache storeImage:transformedImage recalculateFromImage:imageWasTransformed imageData:data forKey:key toDisk:cacheOnDisk];
      }
      dispatch_main_sync_safe(^{
      if (!weakOperation.isCancelled) {
      completedBlock(transformedImage, nil, SDImageCacheTypeNone, finished, url);
      }
      });
      });
      }
      else {
      if (downloadedImage && finished) {
      [self.imageCache storeImage:downloadedImage recalculateFromImage:NO imageData:data forKey:key toDisk:cacheOnDisk];
      }
      dispatch_main_sync_safe(^{
      if (!weakOperation.isCancelled) {
      completedBlock(downloadedImage, nil, SDImageCacheTypeNone, finished, url);
      }
      });
      }
      }
      if (finished) {
      @synchronized (self.runningOperations) {
      [self.runningOperations removeObject:operation];
      }
      }
      }];
      operation.cancelBlock = ^{
      [subOperation cancel];
      @synchronized (self.runningOperations) {
      [self.runningOperations removeObject:weakOperation];
      }
      };
      }
      else if (image) {
      dispatch_main_sync_safe(^{
      if (!weakOperation.isCancelled) {
      completedBlock(image, nil, cacheType, YES, url);
      }
      });
      @synchronized (self.runningOperations) {
      [self.runningOperations removeObject:operation];
      }
      }
      else {
      // Image not in cache and download disallowed by delegate
      dispatch_main_sync_safe(^{
      if (!weakOperation.isCancelled) {
      completedBlock(nil, nil, SDImageCacheTypeNone, YES, url);
      }
      });
      @synchronized (self.runningOperations) {
      [self.runningOperations removeObject:operation];
      }
      }
      }];
      return operation;
      }
      - (void)saveImageToCache:(UIImage *)image forURL:(NSURL *)url {
      if (image && url) {
      NSString *key = [self cacheKeyForURL:url];
      [self.imageCache storeImage:image forKey:key toDisk:YES];
      }
      }
      // cancel掉所有正在执行的operation
      - (void)cancelAll {
      @synchronized (self.runningOperations) {
      NSArray *copiedOperations = [self.runningOperations copy];
      [copiedOperations makeObjectsPerformSelector:@selector(cancel)];
      [self.runningOperations removeObjectsInArray:copiedOperations];
      }
      }
      // 判断是否有正在运行的operation
      - (BOOL)isRunning {
      return self.runningOperations.count > 0;
      }
      @end
      @implementation SDWebImageCombinedOperation
      - (void)setCancelBlock:(SDWebImageNoParamsBlock)cancelBlock {
      // check if the operation is already cancelled, then we just call the cancelBlock
      if (self.isCancelled) {
      if (cancelBlock) {
      cancelBlock();
      }
      _cancelBlock = nil; // don't forget to nil the cancelBlock, otherwise we will get crashes
      } else {
      _cancelBlock = [cancelBlock copy];
      }
      }
      - (void)cancel {
      self.cancelled = YES;
      if (self.cacheOperation) {
      [self.cacheOperation cancel];
      self.cacheOperation = nil;
      }
      if (self.cancelBlock) {
      self.cancelBlock();
      // TODO: this is a temporary fix to #809.
      // Until we can figure the exact cause of the crash, going with the ivar instead of the setter
      // self.cancelBlock = nil;
      _cancelBlock = nil;
      }
      }
      @end
      @implementation SDWebImageManager (Deprecated)
      // deprecated method, uses the non deprecated method
      // adapter for the completion block
      - (id <SDWebImageOperation>)downloadWithURL:(NSURL *)url options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletedWithFinishedBlock)completedBlock {
      return [self downloadImageWithURL:url
      options:options
      progress:progressBlock
      completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
      if (completedBlock) {
      completedBlock(image, error, cacheType, finished);
      }
      }];
      }
      @end
      diff --git a/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html b/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html index 3826256..85aa9d4 100644 --- a/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html +++ b/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html @@ -58,6 +58,13 @@

      + + +
      + 文章目录 +
      1. 1. Any AnyObject NSObject
      2. 2. 条件判断
        1. 2.1. 1. if的使用
        2. 2.2. 2. 三目运算符
        3. 2.3. 3. guard
        4. 2.4. 4. switch的用法
          1. 2.4.1. 1. switch与基本数据
          2. 2.4.2. 2. switch与区间
          3. 2.4.3. 3. switch与枚举
          4. 2.4.4. 4. switch与元组
      3. 3. 循环
        1. 3.1. 1. for循环
        2. 3.2. 2. while循环
          1. 3.2.1. 1. while循环
          2. 3.2.2. 2. repeat~while循环
      4. 4. 字符串处理
      5. 5. 数组
      6. 6. 字典
      7. 7. 元组
      8. 8. 可选类型
        1. 8.1. 2. 可选类型 (才能赋值为nil)
        2. 8.2. 3. 四种方式使用可选类型的值
          1. 8.2.1. 1. 判断 + 直接解包
          2. 8.2.2. 2. 可选绑定
          3. 8.2.3. 3. guard守护
          4. 8.2.4. 4. 空合运算符
      9. 9. 类型转换
      10. 10. 函数
        1. 10.1. 1. 函数的四种类型
          1. 10.1.1. 1. 无参数,无返回值
          2. 10.1.2. 2. 无参数,有返回值
          3. 10.1.3. 3. 有参数,无返回值
          4. 10.1.4. 4. 有参数,有返回值
        2. 10.2. 函数其他注意
          1. 10.2.1. 1. 省略第一个外部参数的名字
          2. 10.2.2. 2. 设置参数默认值
          3. 10.2.3. 3. 设置可变参数
          4. 10.2.4. 4. 修改内部参数的值
          5. 10.2.5. 5. 设置参数为地址传递
          6. 10.2.6. 6. 函数嵌套
          7. 10.2.7. 7. 函数的类型
          8. 10.2.8. 8. 区分不同函数
      11. 11. 枚举
      12. 12. 结构体
        1. 12.1. 1. 结构体基本使用
        2. 12.2. 2. 结构体扩充构造函数
      13. 13.
        1. 13.1. 1. 类的声明初始化
        2. 13.2. 2. 类的属性和方法
        3. 13.3. 3. 类的继承之KVC使用
        4. 13.4. 4. 类的循环引用
        5. 13.5. 5. 结构体和类的区别
        6. 13.6. 6. OC中使用Swift的类和结构体
        7. 13.7. 7. Swift中调用OC
      14. 14. 三大特性
      15. 15. 可选链
      16. 16. 协议
        1. 16.1. 1.协议的基本使用
        2. 16.2. 2. 协议中使用代理
        3. 16.3. 3. 协议中的可选
      17. 17. 闭包
        1. 17.1. 1.闭包的基本使用
        2. 17.2. 2. 尾随闭包和逃逸闭包
        3. 17.3. 3. 闭包的循环引用(4中解决方式)
      18. 18. 懒加载
      19. 19. 注释
      20. 20. 访问权限
        1. 20.1. 访问修饰符
      21. 21. 方法抛出异常
      22. 22. Playground
        1. 22.1. 1. Playground异步执行
        2. 22.2. 2. MarkDown语法
        3. 22.3. 3. TimeLine使用
        4. 22.4. 4. Playground的Sources目录
      +
      +

      总结一些 Swift3.0学习笔记

      Any AnyObject NSObject

      Int Double String struct都是结构体

      diff --git a/categories/iOS/index.html b/categories/iOS/index.html deleted file mode 100644 index 5e35da9..0000000 --- a/categories/iOS/index.html +++ /dev/null @@ -1,279 +0,0 @@ - - - - - - Category: iOS | CoderShmily's Blog - - - - - - - - - - - - - - - - - - - - - - - -
      -
      - -
      -
      - - - - - - -
      -
      - 2015 -
      -
      - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      - - - -
      - - - -
      -
      - -
      - -
      -
      -
      - - - - - - - - - - - - - - - -
      - - \ No newline at end of file From 84e4086839482bf3442392317fd1928d4f7b7906 Mon Sep 17 00:00:00 2001 From: CoderShmily Date: Tue, 4 Apr 2017 11:30:57 +0800 Subject: [PATCH 024/148] Customize commit message --- categories/iOS/index.html | 279 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 279 insertions(+) create mode 100644 categories/iOS/index.html diff --git a/categories/iOS/index.html b/categories/iOS/index.html new file mode 100644 index 0000000..5e35da9 --- /dev/null +++ b/categories/iOS/index.html @@ -0,0 +1,279 @@ + + + + + + Category: iOS | CoderShmily's Blog + + + + + + + + + + + + + + + + + + + + + + + +
      +
      + +
      +
      + + + + + + +
      +
      + 2015 +
      +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + +
      +
      + +
      + +
      +
      +
      + + + + + + + + + + + + + + + +
      + + \ No newline at end of file From 49f30bdb221deeddc3cbb270b3f30f44dec6bd63 Mon Sep 17 00:00:00 2001 From: CoderShmily Date: Tue, 4 Apr 2017 11:39:20 +0800 Subject: [PATCH 025/148] Customize commit message --- categories/iOS/index.html | 279 -------------------------------------- 1 file changed, 279 deletions(-) delete mode 100644 categories/iOS/index.html diff --git a/categories/iOS/index.html b/categories/iOS/index.html deleted file mode 100644 index 5e35da9..0000000 --- a/categories/iOS/index.html +++ /dev/null @@ -1,279 +0,0 @@ - - - - - - Category: iOS | CoderShmily's Blog - - - - - - - - - - - - - - - - - - - - - - - -
      -
      - -
      -
      - - - - - - -
      -
      - 2015 -
      -
      - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      - - - -
      - - - -
      -
      - -
      - -
      -
      -
      - - - - - - - - - - - - - - - -
      - - \ No newline at end of file From 0dbac23ad111f7355cd249bfe3c5e6a57157ee24 Mon Sep 17 00:00:00 2001 From: CoderShmily Date: Tue, 4 Apr 2017 11:40:33 +0800 Subject: [PATCH 026/148] Customize commit message --- categories/iOS/index.html | 279 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 279 insertions(+) create mode 100644 categories/iOS/index.html diff --git a/categories/iOS/index.html b/categories/iOS/index.html new file mode 100644 index 0000000..5e35da9 --- /dev/null +++ b/categories/iOS/index.html @@ -0,0 +1,279 @@ + + + + + + Category: iOS | CoderShmily's Blog + + + + + + + + + + + + + + + + + + + + + + + +
      +
      + +
      +
      + + + + + + +
      +
      + 2015 +
      +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + +
      +
      + +
      + +
      +
      +
      + + + + + + + + + + + + + + + +
      + + \ No newline at end of file From b555daf1bb177dd9345f0fcfeb398b9e194114e2 Mon Sep 17 00:00:00 2001 From: shmily Date: Fri, 5 May 2017 10:23:37 +0800 Subject: [PATCH 027/148] Customize commit message --- .../index.html | 26 +- categories/iOS/index.html | 279 ------------------ 2 files changed, 18 insertions(+), 287 deletions(-) delete mode 100644 categories/iOS/index.html diff --git a/2015/05/04/2015-05-04-runtime-dui-xiang-mo-xing/index.html b/2015/05/04/2015-05-04-runtime-dui-xiang-mo-xing/index.html index 65a6550..13620f1 100644 --- a/2015/05/04/2015-05-04-runtime-dui-xiang-mo-xing/index.html +++ b/2015/05/04/2015-05-04-runtime-dui-xiang-mo-xing/index.html @@ -13,11 +13,13 @@ - + + + @@ -72,14 +74,17 @@

      在这一系列文章中,我们将介绍runtime的基本工作原理,以及如何利用它让我们的程序变得更加灵活。在本文中,我们先来介绍一下类与对象,这是面向对象的基础,我们看看在Runtime中,类是如何实现的。


      类与对象基础数据结构

      Class

      -

      Objective-C类是由Class类型来表示的,它实际上是一个指向objc_class结构体的指针。它的定义如下:

      1
      typedef struct objc_class *Class;

      -

      查看objc/runtime.h中objc_class结构体的定义如下:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      struct objc_class {
      Class isa OBJC_ISA_AVAILABILITY;
      #if !__OBJC2__
      Class super_class OBJC2_UNAVAILABLE; // 父类
      const char *name OBJC2_UNAVAILABLE; // 类名
      long version OBJC2_UNAVAILABLE; // 类的版本信息,默认为0
      long info OBJC2_UNAVAILABLE; // 类信息,供运行期使用的一些位标识
      long instance_size OBJC2_UNAVAILABLE; // 该类的实例变量大小
      struct objc_ivar_list *ivars OBJC2_UNAVAILABLE; // 该类的成员变量链表
      struct objc_method_list **methodLists OBJC2_UNAVAILABLE; // 方法定义的链表
      struct objc_cache *cache OBJC2_UNAVAILABLE; // 方法缓存
      struct objc_protocol_list *protocols OBJC2_UNAVAILABLE; // 协议链表
      #endif
      } OBJC2_UNAVAILABLE;

      +

      Objective-C类是由Class类型来表示的,它实际上是一个指向objc_class结构体的指针。它的定义如下:

      +
      1
      typedef struct objc_class *Class;
      +

      查看objc/runtime.h中objc_class结构体的定义如下:

      +
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      struct objc_class {
      Class isa OBJC_ISA_AVAILABILITY;
      #if !__OBJC2__
      Class super_class OBJC2_UNAVAILABLE; // 父类
      const char *name OBJC2_UNAVAILABLE; // 类名
      long version OBJC2_UNAVAILABLE; // 类的版本信息,默认为0
      long info OBJC2_UNAVAILABLE; // 类信息,供运行期使用的一些位标识
      long instance_size OBJC2_UNAVAILABLE; // 该类的实例变量大小
      struct objc_ivar_list *ivars OBJC2_UNAVAILABLE; // 该类的成员变量链表
      struct objc_method_list **methodLists OBJC2_UNAVAILABLE; // 方法定义的链表
      struct objc_cache *cache OBJC2_UNAVAILABLE; // 方法缓存
      struct objc_protocol_list *protocols OBJC2_UNAVAILABLE; // 协议链表
      #endif
      } OBJC2_UNAVAILABLE;

      在这个定义中,下面几个字段是我们感兴趣的

      1.isa:需要注意的是在Objective-C中,所有的类自身也是一个对象,这个对象的Class里面也有一个isa指针,它指向metaClass(元类),我们会在后面介绍它。

      2.super_class:指向该类的父类,如果该类已经是最顶层的根类(如NSObject或NSProxy),则super_class为NULL。

      3.cache:用于缓存最近使用的方法。一个接收者对象接收到一个消息时,它会根据isa指针去查找能够响应这个消息的对象。在实际使用中,这个对象只有一部分方法是常用的,很多方法其实很少用或者根本用不上。这种情况下,如果每次消息来时,我们都是methodLists中遍历一遍,性能势必很差。这时,cache就派上用场了。在我们每次调用过一个方法后,这个方法就会被缓存到cache列表中,下次调用的时候runtime就会优先去cache中查找,如果cache没有,才去methodLists中查找方法。这样,对于那些经常用到的方法的调用,但提高了调用的效率。

      4.version:我们可以使用这个字段来提供类的版本信息。这对于对象的序列化非常有用,它可是让我们识别出不同类定义版本中实例变量布局的改变。

      -

      针对cache,我们用下面例子来说明其执行过程:

      1
      NSArray *array = [[NSArray alloc] init];

      +

      针对cache,我们用下面例子来说明其执行过程:

      +
      1
      NSArray *array = [[NSArray alloc] init];

      其流程是:

      1.[NSArray alloc]先被执行。因为NSArray没有+alloc方法,于是去父类NSObject去查找。

      2.检测NSObject是否响应+alloc方法,发现响应,于是检测NSArray类,并根据其所需的内存空间大小开始分配内存空间,然后把isa指针指向NSArray类。同时,+alloc也被加进cache列表里面。

      @@ -87,20 +92,24 @@

      1
      2
      3
      4
      5
      6
      7
      struct objc_object {
      Class isa OBJC_ISA_AVAILABILITY;
      };
      typedef struct objc_object *id;

      +

      objc_object是表示一个类的实例的结构体,它的定义如下(objc/objc.h):

      +
      1
      2
      3
      4
      5
      6
      7
      struct objc_object {
      Class isa OBJC_ISA_AVAILABILITY;
      };
      typedef struct objc_object *id;

      可以看到,这个结构体只有一个字体,即指向其类的isa指针。这样,当我们向一个Objective-C对象发送消息时,运行时库会根据实例对象的isa指针找到这个实例对象所属的类。Runtime库会在类的方法列表及父类的方法列表中去寻找与消息对应的selector指向的方法。找到后即运行这个方法。

      当创建一个特定类的实例对象时,分配的内存包含一个objc_object数据结构,然后是类的实例变量的数据。NSObject类的alloc和allocWithZone:方法使用函数class_createInstance来创建objc_object数据结构。

      另外还有我们常见的id,它是一个objc_object结构类型的指针。它的存在可以让我们实现类似于C++中泛型的一些操作。该类型的对象可以转换为任何一种对象,有点类似于C语言中void *指针类型的作用。


      ###objc_cache

      -

      上面提到了objc_class结构体中的cache字段,它用于缓存调用过的方法。这个字段是一个指向objc_cache结构体的指针,其定义如下:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      struct objc_cache {
      unsigned int mask /* total = mask + 1 */ OBJC2_UNAVAILABLE;
      unsigned int occupied OBJC2_UNAVAILABLE;
      Method buckets[1] OBJC2_UNAVAILABLE;
      };

      +

      上面提到了objc_class结构体中的cache字段,它用于缓存调用过的方法。这个字段是一个指向objc_cache结构体的指针,其定义如下:

      +
      1
      2
      3
      4
      5
      6
      7
      8
      9
      struct objc_cache {
      unsigned int mask /* total = mask + 1 */ OBJC2_UNAVAILABLE;
      unsigned int occupied OBJC2_UNAVAILABLE;
      Method buckets[1] OBJC2_UNAVAILABLE;
      };

      该结构体的字段描述如下:

      1.mask:一个整数,指定分配的缓存bucket的总数。在方法查找过程中,Objective-C runtime使用这个字段来确定开始线性查找数组的索引位置。指向方法selector的指针与该字段做一个AND位操作(index = (mask & selector))。这可以作为一个简单的hash散列算法。

      2.occupied:一个整数,指定实际占用的缓存bucket的总数。

      3.buckets:指向Method数据结构指针的数组。这个数组可能包含不超过mask+1个元素。需要注意的是,指针可能是NULL,表示这个缓存bucket没有被占用,另外被占用的bucket可能是不连续的。这个数组可能会随着时间而增长。

      ###元类(Meta Class)

      -

      在上面我们提到,所有的类自身也是一个对象,我们可以向这个对象发送消息(即调用类方法)。如:

      1
      NSArray *array = [NSArray array];

      -

      这个例子中,+array消息发送给了NSArray类,而这个NSArray也是一个对象。既然是对象,那么它也是一个objc_object指针,它包含一个指向其类的一个isa指针。那么这些就有一个问题了,这个isa指针指向什么呢?为了调用+array方法,这个类的isa指针必须指向一个包含这些类方法的一个objc_class结构体。这就引出了meta-class的概念

      1
      meta-class是一个类对象的类。

      +

      在上面我们提到,所有的类自身也是一个对象,我们可以向这个对象发送消息(即调用类方法)。如:

      +
      1
      NSArray *array = [NSArray array];
      +

      这个例子中,+array消息发送给了NSArray类,而这个NSArray也是一个对象。既然是对象,那么它也是一个objc_object指针,它包含一个指向其类的一个isa指针。那么这些就有一个问题了,这个isa指针指向什么呢?为了调用+array方法,这个类的isa指针必须指向一个包含这些类方法的一个objc_class结构体。这就引出了meta-class的概念

      +
      1
      meta-class是一个类对象的类。

      当我们向一个对象发送消息时,runtime会在这个对象所属的这个类的方法列表中查找方法;而向一个类发送消息时,会在这个类的meta-class的方法列表中查找。

      meta-class之所以重要,是因为它存储着一个类的所有类方法。每个类都会有一个单独的meta-class,因为每个类的类方法基本不可能完全相同。

      再深入一下,meta-class也是一个类,也可以向它发送一个消息,那么它的isa又是指向什么呢?为了不让这种结构无限延伸下去,Objective-C的设计者让所有的meta-class的isa指向基类的meta-class,以此作为它们的所属类。即,任何NSObject继承体系下的meta-class都使用NSObject的meta-class作为自己的所属类,而基类的meta-class的isa指针是指向它自己。这样就形成了一个完美的闭环。

      @@ -118,6 +127,7 @@

      diff --git a/categories/iOS/index.html b/categories/iOS/index.html deleted file mode 100644 index 5e35da9..0000000 --- a/categories/iOS/index.html +++ /dev/null @@ -1,279 +0,0 @@ - - - - - - Category: iOS | CoderShmily's Blog - - - - - - - - - - - - - - - - - - - - - - - -
      -
      - -
      -
      - - - - - - -
      - -
      - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      - - - -
      - - - -
      -
      - -
      - -
      -
      -
      - - - - - - - - - - - - - - - -
      - - \ No newline at end of file From c127af2e4eba7fc621beb93bed67ca165234e3e7 Mon Sep 17 00:00:00 2001 From: shmily Date: Fri, 5 May 2017 10:31:40 +0800 Subject: [PATCH 028/148] Customize commit message --- .../index.html | 9 +- categories/iOS/index.html | 279 ++++++++++++++++++ 2 files changed, 283 insertions(+), 5 deletions(-) create mode 100644 categories/iOS/index.html diff --git a/2015/05/04/2015-05-04-runtime-dui-xiang-mo-xing/index.html b/2015/05/04/2015-05-04-runtime-dui-xiang-mo-xing/index.html index 13620f1..46671ad 100644 --- a/2015/05/04/2015-05-04-runtime-dui-xiang-mo-xing/index.html +++ b/2015/05/04/2015-05-04-runtime-dui-xiang-mo-xing/index.html @@ -13,13 +13,13 @@ - - + + - + @@ -126,8 +126,7 @@

      +

      NSObject的元类对象(metaclass object)指向了自己,这也满足上面结论4。
      Snip20170406_4

      diff --git a/categories/iOS/index.html b/categories/iOS/index.html new file mode 100644 index 0000000..5e35da9 --- /dev/null +++ b/categories/iOS/index.html @@ -0,0 +1,279 @@ + + + + + + Category: iOS | CoderShmily's Blog + + + + + + + + + + + + + + + + + + + + + + + +
      +
      + +
      +
      + + + + + + +
      + +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + +
      +
      + +
      + +
      +
      +
      + + + + + + + + + + + + + + + +
      + + \ No newline at end of file From 9c8f39853838a42efe84017abaf0db8d490d7008 Mon Sep 17 00:00:00 2001 From: shmily Date: Fri, 5 May 2017 10:34:22 +0800 Subject: [PATCH 029/148] Customize commit message --- 2015/05/01/2015-05-01-Swift-ru-men/index.html | 2 +- 2015/05/02/2015-05-02-singleton/index.html | 2 +- .../2015-05-03-kvc-he-kvoshen-ru/index.html | 2 +- .../index.html | 8 +- .../05/2015-05-05-runtime-gai-shu/index.html | 4 +- .../index.html | 6 +- .../index.html" | 235 ++++++++++++++++++ .../index.html | 2 +- .../index.html | 2 +- .../2016-11-15-Swift3.0-jie-shao/index.html | 2 +- archives/2015/05/index.html | 21 +- archives/2015/index.html | 21 +- archives/2016/11/index.html | 2 +- archives/2016/index.html | 2 +- archives/index.html | 21 +- categories/Swift/index.html | 2 +- categories/iOS/index.html | 21 +- index.html | 47 +++- 18 files changed, 378 insertions(+), 24 deletions(-) create mode 100644 "2015/05/06/\346\210\221\346\230\257\346\265\213\350\257\225/index.html" diff --git a/2015/05/01/2015-05-01-Swift-ru-men/index.html b/2015/05/01/2015-05-01-Swift-ru-men/index.html index 642106d..f5d10cf 100644 --- a/2015/05/01/2015-05-01-Swift-ru-men/index.html +++ b/2015/05/01/2015-05-01-Swift-ru-men/index.html @@ -403,7 +403,7 @@

      最新文章

    1. - Objective-C Runtime(一) 概述 + Objective-C Runtime(三) 消息传递

diff --git a/2015/05/02/2015-05-02-singleton/index.html b/2015/05/02/2015-05-02-singleton/index.html index f42d7ef..ca8e62e 100644 --- a/2015/05/02/2015-05-02-singleton/index.html +++ b/2015/05/02/2015-05-02-singleton/index.html @@ -173,7 +173,7 @@

最新文章

  • - Objective-C Runtime(一) 概述 + Objective-C Runtime(三) 消息传递
  • diff --git a/2015/05/03/2015-05-03-kvc-he-kvoshen-ru/index.html b/2015/05/03/2015-05-03-kvc-he-kvoshen-ru/index.html index e80d4e0..c9ecd52 100644 --- a/2015/05/03/2015-05-03-kvc-he-kvoshen-ru/index.html +++ b/2015/05/03/2015-05-03-kvc-he-kvoshen-ru/index.html @@ -211,7 +211,7 @@

    最新文章

  • - Objective-C Runtime(一) 概述 + Objective-C Runtime(三) 消息传递
  • diff --git a/2015/05/04/2015-05-04-runtime-dui-xiang-mo-xing/index.html b/2015/05/04/2015-05-04-runtime-dui-xiang-mo-xing/index.html index 46671ad..d337dc6 100644 --- a/2015/05/04/2015-05-04-runtime-dui-xiang-mo-xing/index.html +++ b/2015/05/04/2015-05-04-runtime-dui-xiang-mo-xing/index.html @@ -13,13 +13,11 @@ - - + - @@ -126,7 +124,7 @@

    +

    NSObject的元类对象(metaclass object)指向了自己,这也满足上面结论4。

    @@ -212,7 +210,7 @@

    最新文章

  • - Objective-C Runtime(一) 概述 + Objective-C Runtime(三) 消息传递
  • diff --git a/2015/05/05/2015-05-05-runtime-gai-shu/index.html b/2015/05/05/2015-05-05-runtime-gai-shu/index.html index 080469c..8fd114a 100644 --- a/2015/05/05/2015-05-05-runtime-gai-shu/index.html +++ b/2015/05/05/2015-05-05-runtime-gai-shu/index.html @@ -134,7 +134,7 @@

    - + Newer
    @@ -206,7 +206,7 @@

    最新文章

  • - Objective-C Runtime(一) 概述 + Objective-C Runtime(三) 消息传递
  • diff --git a/2015/05/06/2015-05-06-objective-c-runtime-san-xiao-xi-chuan-di/index.html b/2015/05/06/2015-05-06-objective-c-runtime-san-xiao-xi-chuan-di/index.html index 891aa4f..a8d842c 100644 --- a/2015/05/06/2015-05-06-objective-c-runtime-san-xiao-xi-chuan-di/index.html +++ b/2015/05/06/2015-05-06-objective-c-runtime-san-xiao-xi-chuan-di/index.html @@ -126,9 +126,9 @@

    + Older -
    Objective-C Runtime(一) 概述
    +
    Objective-C Runtime(三) 消息传递
    @@ -188,7 +188,7 @@

    最新文章

  • - Objective-C Runtime(一) 概述 + Objective-C Runtime(三) 消息传递
  • diff --git "a/2015/05/06/\346\210\221\346\230\257\346\265\213\350\257\225/index.html" "b/2015/05/06/\346\210\221\346\230\257\346\265\213\350\257\225/index.html" new file mode 100644 index 0000000..13a5384 --- /dev/null +++ "b/2015/05/06/\346\210\221\346\230\257\346\265\213\350\257\225/index.html" @@ -0,0 +1,235 @@ + + + + + + Objective-C Runtime(三) 消息传递 | CoderShmily's Blog + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    +
    + +
    + + +
    + + +

    + Objective-C Runtime(三) 消息传递 +

    + + +
    + +
    + + + +

    Objective-C Runtime的消息传递

    +

    ###Objective-C – 消息传递
    Objective-C 扩展了 C 语言,并加入了面向对象特性和 Smalltalk 式的消息传递机制。而这个扩展的核心是一个用 C 和 编译语言 写的 Runtime 库。它是 Objective-C 面向对象和动态机制的基石.

    +

    Objective-C 是一个动态语言,这意味着它不仅需要一个编译器,也需要一个运行时系统来动态得创建类和对象、进行消息传递和转发。理解 Objective-C 的 Runtime 机制可以帮我们更好的了解这个语言,适当的时候还能对语言进行扩展,从系统层面解决项目中的一些设计或技术问题。了解 Runtime ,要先了解它的核心 - 消息传递(Messaging)。

    +
    +

    消息传递

    在很多语言,比如 C ,调用一个方法其实就是跳到内存中的某一点并开始执行一段代码。没有任何动态的特性,因为这在编译时就决定好了。而在 Objective-C 中,[object foo] 语法并不会立即执行 foo 这个方法的代码。它是在运行时给 object 发送一条叫 foo 的消息。这个消息,也许会由 object 来处理,也许会被转发给另一个对象,或者不予理睬假装没收到这个消息。多条不同的消息也可以对应同一个方法实现。这些都是在程序运行的时候决定的。

    +

    事实上,在编译时你写的 Objective-C 函数调用的语法都会被翻译成一个 C 的函数调用- objc_msgSend() 。比如,下面两行代码就是等价的:

    +
    1
    2
    3
    [array insertObject:foo atIndex:5];
    objc_msgSend(array, @selector(insertObject:atIndex:), foo, 5);
    +

    消息传递的关键藏于 objc_object 中的 isa 指针和 objc_class 中的 class dispatch table。

    +

    objc_object, objc_class以及Ojbc_method

    在 Objective-C 中,类、对象和方法都是一个 C 的结构体,从 objc/objc.h 头文件中,我们可以找到他们的定义:

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    struct objc_object {
    Class isa OBJC_ISA_AVAILABILITY;
    };
    struct objc_class {
    Class isa OBJC_ISA_AVAILABILITY;
    #if !__OBJC2__
    Class super_class;
    const char *name;
    long version;
    long info;
    long instance_size;
    struct objc_ivar_list *ivars;
    **struct objc_method_list **methodLists**;
    **struct objc_cache *cache**;
    struct objc_protocol_list *protocols;
    #endif
    };
    struct objc_method_list {
    struct objc_method_list *obsolete;
    int method_count;
    #ifdef __LP64__
    int space;
    #endif
    /* variable length structure */
    struct objc_method method_list[1];
    };
    struct objc_method {
    SEL method_name;
    char *method_types; /* a string representing argument/return types */
    IMP method_imp;
    };
    +

    objc_method_list 本质是一个有 objc_method 元素的可变长度的数组。一个 objc_method 结构体中有函数名,也就是SEL,有表示函数类型的字符串 (见 Type Encoding) ,以及函数的实现IMP。

    +

    从这些定义中可以看出发送一条消息也就 objc_msgSend 做了什么事。举 objc_msgSend(obj, foo) 这个例子来说:

    +

    1.首先,通过 obj 的 isa 指针找到它的 class ;

    +

    2.在 class 的 method list 找 foo ;

    +

    3.如果 class 中没到 foo,继续往它的 superclass 中找 ;

    +

    4.一旦找到 foo 这个函数,就去执行它的实现IMP .

    +

    但这种实现有个问题,效率低。但一个 class 往往只有 20% 的函数会被经常调用,可能占总调用次数的 80% 。每个消息都需要遍历一次 objc_method_list 并不合理。如果把经常被调用的函数缓存下来,那可以大大提高函数查询的效率。这也就是 objc_class 中另一个重要成员 objc_cache 做的事情 - 再找到 foo 之后,把 foo 的 method_name 作为 key ,method_imp 作为 value 给存起来。当再次收到 foo 消息的时候,可以直接在 cache 里找到,避免去遍历 objc_method_list.

    +
    +

    动态方法解析和转发

    在上面的例子中,如果 foo 没有找到会发生什么?通常情况下,程序会在运行时挂掉并抛出 unrecognized selector sent to …的异常。但在异常抛出前,Objective-C 的运行时会给你三次拯救程序的机会:

    +
      +
    • Method resolution
    • +
    • Fast forwarding
    • +
    • Normal forwarding
    • +
    +

    ###Method Resolution

    +

    首先,Objective-C 运行时会调用+resolveInstanceMethod: 或者 +resolveClassMethod:,让你有机会提供一个函数实现。如果你添加了函数并返回 YES, 那运行时系统就会重新启动一次消息发送的过程。还是以 foo 为例,你可以这么实现:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    void fooMethod(id obj, SEL _cmd)
    {
    NSLog(@"Doing foo");
    }
    + (BOOL)resolveInstanceMethod:(SEL)aSEL
    {
    if(aSEL == @selector(foo:)){
    class_addMethod([self class], aSEL, (IMP)fooMethod, "v@:");
    return YES;
    }
    return [super resolveInstanceMethod];
    }

    +

    Core Data 有用到这个方法。NSManagedObjects 中 properties 的 getter 和 setter 就是在运行时动态添加的。

    +

    如果 resolve 方法返回 NO ,运行时就会移到下一步:消息转发(Message Forwarding)

    +

    上面的例子可以重写成:

    1
    2
    3
    4
    5
    IMP fooIMP = imp_implementationWithBlock(^(id _self) {
    NSLog(@"Doing foo");
    });
    class_addMethod([self class], aSEL, fooIMP, "v@:");

    +

    Fast forwarding

    如果目标对象实现了 -forwardingTargetForSelector: ,Runtime 这时就会调用这个方法,给你把这个消息转发给其他对象的机会。

    1
    2
    3
    4
    5
    6
    7
    - (id)forwardingTargetForSelector:(SEL)aSelector
    {
    if(aSelector == @selector(foo:)){
    return alternateObject;
    }
    return [super forwardingTargetForSelector:aSelector];
    }

    +

    只要这个方法返回的不是 nil 和 self,整个消息发送的过程就会被重启,当然发送的对象会变成你返回的那个对象。否则,就会继续 Normal Fowarding 。

    +

    这里叫 Fast ,只是为了区别下一步的转发机制。因为这一步不会创建任何新的对象,但下一步转发会创建一个 NSInvocation 对象,所以相对更快点。

    +

    ###Normal forwarding
    这一步是 Runtime 最后一次给你挽救的机会。首先它会发送 -methodSignatureForSelector:消息获得函数的参数和返回值类型。如果 -methodSignatureForSelector:返回 nil ,Runtime 则会发出 -doesNotRecognizeSelector: 消息,程序这时也就挂掉了。如果返回了一个函数签名,Runtime 就会创建一个 NSInvocation 对象并发送 -forwardInvocation:消息给目标对象。

    +

    NSInvocation 实际上就是对一个消息的描述,包括selector 以及参数等信息。所以你可以在-forwardInvocation:里修改传进来的 NSInvocation 对象,然后发送-invokeWithTarget: 消息给它,传进去一个新的目标:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    - (NSMethodSignature*)methodSignatureForSelector:(SEL)selector
    {
    NSMethodSignature* signature = [super methodSignatureForSelector:selector];
    if (!signature)
    signature = [alternateObject methodSignatureForSelector:selector];
    return signature;
    }

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    - (void)forwardInvocation:(NSInvocation *)invocation
    {
    SEL sel = invocation.selector;
    if([alternateObject respondsToSelector:sel]) {
    [invocation invokeWithTarget:alternateObject];
    }
    else {
    [self doesNotRecognizeSelector:sel];
    }
    }
    +

    Cocoa 里很多地方都利用到了消息传递机制来对语言进行扩展,如 Proxies、NSUndoManager 跟 Responder Chain。NSProxy 就是专门用来作为代理转发消息的;NSUndoManager 截取一个消息之后再发送;而 Responder Chain 保证一个消息转发给合适的响应者。

    +
    +

    ##总结
    Objective-C 中给一个对象发送消息会经过以下几个步骤:

    +

    1.在对象类的 dispatch table 中尝试找到该消息。如果找到了,跳到相应的函数IMP去执行实现代码;

    +

    2.如果没有找到,Runtime 会发送 +resolveInstanceMethod:或者 +resolveClassMethod:尝试去 resolve 这个消息;

    +

    3.如果 resolve 方法返回 NO,Runtime 就发送-forwardingTargetForSelector: 允许你把这个消息转发给另一个对象;

    +

    4.如果没有新的目标对象返回, Runtime 就会发送-methodSignatureForSelector:-forwardInvocation:消息。你可以发送 -invokeWithTarget: 消息来手动转发消息或者发送-doesNotRecognizeSelector:抛出异常。

    +

    利用 Objective-C 的 runtime特性,我们可以自己来对语言进行扩展,解决项目开发中的一些设计和技术问题。下一篇文章,我会介绍 Method Swizzling 技术以及如何利用 Method Swizzling 做 Logging。

    + + +
    + +
    + + + + + +
    + +
    + + + +
    +
    + +
    + +
    +
    +
    + + + + + + + + + + + + + + + +
    + + \ No newline at end of file diff --git a/2015/05/07/2015-05-07-objective-c-runtime-si-dong-tai-fang-fa-jue-yi-dynamic-method-resolution/index.html b/2015/05/07/2015-05-07-objective-c-runtime-si-dong-tai-fang-fa-jue-yi-dynamic-method-resolution/index.html index a27c103..3e64fbe 100644 --- a/2015/05/07/2015-05-07-objective-c-runtime-si-dong-tai-fang-fa-jue-yi-dynamic-method-resolution/index.html +++ b/2015/05/07/2015-05-07-objective-c-runtime-si-dong-tai-fang-fa-jue-yi-dynamic-method-resolution/index.html @@ -206,7 +206,7 @@

    最新文章

  • - Objective-C Runtime(一) 概述 + Objective-C Runtime(三) 消息传递
  • diff --git a/2015/05/15/2015-05-15-sdwebimageyuan-ma-jie-xi/index.html b/2015/05/15/2015-05-15-sdwebimageyuan-ma-jie-xi/index.html index b9c551f..477c38a 100644 --- a/2015/05/15/2015-05-15-sdwebimageyuan-ma-jie-xi/index.html +++ b/2015/05/15/2015-05-15-sdwebimageyuan-ma-jie-xi/index.html @@ -148,7 +148,7 @@

    最新文章

  • - Objective-C Runtime(一) 概述 + Objective-C Runtime(三) 消息传递
  • diff --git a/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html b/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html index 85aa9d4..dcab9f3 100644 --- a/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html +++ b/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html @@ -252,7 +252,7 @@

    最新文章

  • - Objective-C Runtime(一) 概述 + Objective-C Runtime(三) 消息传递
  • diff --git a/archives/2015/05/index.html b/archives/2015/05/index.html index c768c13..b956a2d 100644 --- a/archives/2015/05/index.html +++ b/archives/2015/05/index.html @@ -101,6 +101,25 @@

    + + + +
    @@ -251,7 +270,7 @@

    最新文章

  • - Objective-C Runtime(一) 概述 + Objective-C Runtime(三) 消息传递
  • diff --git a/archives/2015/index.html b/archives/2015/index.html index b4ee781..72eb1d0 100644 --- a/archives/2015/index.html +++ b/archives/2015/index.html @@ -101,6 +101,25 @@

    + + + +
    @@ -251,7 +270,7 @@

    最新文章

  • - Objective-C Runtime(一) 概述 + Objective-C Runtime(三) 消息传递
  • diff --git a/archives/2016/11/index.html b/archives/2016/11/index.html index 9919988..8ffb465 100644 --- a/archives/2016/11/index.html +++ b/archives/2016/11/index.html @@ -118,7 +118,7 @@

    最新文章

  • - Objective-C Runtime(一) 概述 + Objective-C Runtime(三) 消息传递
  • diff --git a/archives/2016/index.html b/archives/2016/index.html index 4ef9afa..903f60c 100644 --- a/archives/2016/index.html +++ b/archives/2016/index.html @@ -118,7 +118,7 @@

    最新文章

  • - Objective-C Runtime(一) 概述 + Objective-C Runtime(三) 消息传递
  • diff --git a/archives/index.html b/archives/index.html index 7a5d502..0d3c0f2 100644 --- a/archives/index.html +++ b/archives/index.html @@ -130,6 +130,25 @@

    + + + +
    @@ -280,7 +299,7 @@

    最新文章

  • - Objective-C Runtime(一) 概述 + Objective-C Runtime(三) 消息传递
  • diff --git a/categories/Swift/index.html b/categories/Swift/index.html index 44ff482..c24fc24 100644 --- a/categories/Swift/index.html +++ b/categories/Swift/index.html @@ -147,7 +147,7 @@

    最新文章

  • - Objective-C Runtime(一) 概述 + Objective-C Runtime(三) 消息传递
  • diff --git a/categories/iOS/index.html b/categories/iOS/index.html index 5e35da9..85c23ad 100644 --- a/categories/iOS/index.html +++ b/categories/iOS/index.html @@ -101,6 +101,25 @@

    + + + +
    @@ -232,7 +251,7 @@

    最新文章

  • - Objective-C Runtime(一) 概述 + Objective-C Runtime(三) 消息传递
  • diff --git a/index.html b/index.html index a1f6a75..04427cc 100644 --- a/index.html +++ b/index.html @@ -213,6 +213,51 @@

    + + + +
    diff --git a/2015/05/02/2015-05-02-singleton/index.html b/2015/05/02/2015-05-02-singleton/index.html index ca8e62e..12518d9 100644 --- a/2015/05/02/2015-05-02-singleton/index.html +++ b/2015/05/02/2015-05-02-singleton/index.html @@ -144,7 +144,7 @@

    分类

    @@ -156,6 +156,10 @@

    最新文章

    diff --git a/2015/05/03/2015-05-03-kvc-he-kvoshen-ru/index.html b/2015/05/03/2015-05-03-kvc-he-kvoshen-ru/index.html index c9ecd52..4b3578a 100644 --- a/2015/05/03/2015-05-03-kvc-he-kvoshen-ru/index.html +++ b/2015/05/03/2015-05-03-kvc-he-kvoshen-ru/index.html @@ -182,7 +182,7 @@

    分类

    @@ -194,6 +194,10 @@

    最新文章

    diff --git a/2015/05/04/2015-05-04-runtime-dui-xiang-mo-xing/index.html b/2015/05/04/2015-05-04-runtime-dui-xiang-mo-xing/index.html index d337dc6..146347a 100644 --- a/2015/05/04/2015-05-04-runtime-dui-xiang-mo-xing/index.html +++ b/2015/05/04/2015-05-04-runtime-dui-xiang-mo-xing/index.html @@ -181,7 +181,7 @@

    分类

    @@ -193,6 +193,10 @@

    最新文章

    diff --git a/2015/05/05/2015-05-05-runtime-gai-shu/index.html b/2015/05/05/2015-05-05-runtime-gai-shu/index.html index 8fd114a..a87b96f 100644 --- a/2015/05/05/2015-05-05-runtime-gai-shu/index.html +++ b/2015/05/05/2015-05-05-runtime-gai-shu/index.html @@ -134,7 +134,7 @@
    - + Newer
    @@ -177,7 +177,7 @@

    分类

    @@ -189,6 +189,10 @@

    最新文章

    diff --git a/2015/05/06/2015-05-06-objective-c-runtime-san-xiao-xi-chuan-di/index.html b/2015/05/06/2015-05-06-objective-c-runtime-san-xiao-xi-chuan-di/index.html index a8d842c..e3b6841 100644 --- a/2015/05/06/2015-05-06-objective-c-runtime-san-xiao-xi-chuan-di/index.html +++ b/2015/05/06/2015-05-06-objective-c-runtime-san-xiao-xi-chuan-di/index.html @@ -126,9 +126,9 @@

    + Older -
    Objective-C Runtime(三) 消息传递
    +
    Objective-C Runtime(一) 概述
    @@ -159,7 +159,7 @@

    分类

    @@ -171,6 +171,10 @@

    最新文章

    diff --git a/2015/05/07/2015-05-07-objective-c-runtime-si-dong-tai-fang-fa-jue-yi-dynamic-method-resolution/index.html b/2015/05/07/2015-05-07-objective-c-runtime-si-dong-tai-fang-fa-jue-yi-dynamic-method-resolution/index.html index 3e64fbe..2801242 100644 --- a/2015/05/07/2015-05-07-objective-c-runtime-si-dong-tai-fang-fa-jue-yi-dynamic-method-resolution/index.html +++ b/2015/05/07/2015-05-07-objective-c-runtime-si-dong-tai-fang-fa-jue-yi-dynamic-method-resolution/index.html @@ -177,7 +177,7 @@

    分类

    @@ -189,6 +189,10 @@

    最新文章

    diff --git a/2015/05/15/2015-05-15-sdwebimageyuan-ma-jie-xi/index.html b/2015/05/15/2015-05-15-sdwebimageyuan-ma-jie-xi/index.html index 477c38a..80e89dd 100644 --- a/2015/05/15/2015-05-15-sdwebimageyuan-ma-jie-xi/index.html +++ b/2015/05/15/2015-05-15-sdwebimageyuan-ma-jie-xi/index.html @@ -119,7 +119,7 @@

    分类

    @@ -131,6 +131,10 @@

    最新文章

    diff --git a/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html b/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html index dcab9f3..32017bb 100644 --- a/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html +++ b/2016/11/15/2016-11-15-Swift3.0-jie-shao/index.html @@ -189,6 +189,15 @@

    + + Newer +
    + + Objective-C Runtime(三) 消息传递 + +
    +
    + Older @@ -223,7 +232,7 @@

    分类

    @@ -235,6 +244,10 @@

    最新文章

    diff --git "a/2015/05/06/\346\210\221\346\230\257\346\265\213\350\257\225/index.html" "b/2017/01/01/\346\210\221\346\230\257\346\265\213\350\257\225/index.html" similarity index 95% rename from "2015/05/06/\346\210\221\346\230\257\346\265\213\350\257\225/index.html" rename to "2017/01/01/\346\210\221\346\230\257\346\265\213\350\257\225/index.html" index 13a5384..2709d5e 100644 --- "a/2015/05/06/\346\210\221\346\230\257\346\265\213\350\257\225/index.html" +++ "b/2017/01/01/\346\210\221\346\230\257\346\265\213\350\257\225/index.html" @@ -8,10 +8,10 @@ - + - + @@ -34,8 +34,8 @@
    diff --git a/archives/2016/index.html b/archives/2016/index.html index 903f60c..ca33531 100644 --- a/archives/2016/index.html +++ b/archives/2016/index.html @@ -89,7 +89,7 @@

    分类

    @@ -101,6 +101,10 @@

    最新文章

    diff --git a/archives/2017/01/index.html b/archives/2017/01/index.html new file mode 100644 index 0000000..685b40a --- /dev/null +++ b/archives/2017/01/index.html @@ -0,0 +1,165 @@ + + + + + + 归档: 2017/1 | CoderShmily's Blog + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    +
    + + + + + + +
    +
    + 2017 +
    +
    + + + + +
    + + + +
    + + + +
    +
    + +
    + +
    +
    +
    + + + + + + + + + + + + + + + +
    + + \ No newline at end of file diff --git a/archives/2017/index.html b/archives/2017/index.html new file mode 100644 index 0000000..937bcb5 --- /dev/null +++ b/archives/2017/index.html @@ -0,0 +1,165 @@ + + + + + + 归档: 2017 | CoderShmily's Blog + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    +
    + + + + + + +
    +
    + 2017 +
    +
    + + + + +
    + + + +
    + + + +
    +
    + +
    + +
    +
    +
    + + + + + + + + + + + + + + + +
    + + \ No newline at end of file diff --git a/archives/index.html b/archives/index.html index 0d3c0f2..fffcbdc 100644 --- a/archives/index.html +++ b/archives/index.html @@ -40,20 +40,20 @@
    - 2016 + 2017
    -

    - Swift3.0学习笔记 + Objective-C Runtime(三) 消息传递

    @@ -69,20 +69,20 @@

    - 2015 + 2016
    + + +
    +
    + 2015 +
    +
    +
    -

    - Objective-C Runtime(四) 动态方法决议 + SDWebImage源码解析

    @@ -114,13 +124,13 @@

    -

    - Objective-C Runtime(三) 消息传递 + Objective-C Runtime(四) 动态方法决议

    @@ -133,13 +143,13 @@

    -

    - Objective-C Runtime(三) 消息传递 + Objective-C Runtime(三) 消息传递

    @@ -270,7 +280,7 @@

    分类

    @@ -282,6 +292,10 @@

    最新文章

    diff --git a/categories/Swift/index.html b/categories/Swift/index.html index c24fc24..5854f23 100644 --- a/categories/Swift/index.html +++ b/categories/Swift/index.html @@ -118,7 +118,7 @@

    分类

    @@ -130,6 +130,10 @@

    最新文章

    diff --git a/categories/iOS/index.html b/categories/iOS/index.html index 85c23ad..6f5d19c 100644 --- a/categories/iOS/index.html +++ b/categories/iOS/index.html @@ -40,20 +40,20 @@
    - 2015 + 2017
    + + +
    +
    + 2015 +
    +
    +
    -

    - Objective-C Runtime(四) 动态方法决议 + SDWebImage源码解析

    @@ -85,13 +95,13 @@

    -

    - Objective-C Runtime(三) 消息传递 + Objective-C Runtime(四) 动态方法决议

    @@ -104,13 +114,13 @@

    -

    - Objective-C Runtime(三) 消息传递 + Objective-C Runtime(三) 消息传递

    @@ -222,7 +232,7 @@

    分类

    @@ -234,6 +244,10 @@

    最新文章

    diff --git a/index.html b/index.html index 04427cc..345a453 100644 --- a/index.html +++ b/index.html @@ -33,14 +33,14 @@
    -
    +
    @@ -51,7 +51,7 @@

    - Swift3.0学习笔记 + Objective-C Runtime(三) 消息传递

    @@ -59,16 +59,16 @@

    -

    总结一些 Swift3.0学习笔记

    +

    Objective-C Runtime的消息传递

    - Read More + Read More

    @@ -78,14 +78,14 @@

    -
    +
    @@ -96,7 +96,7 @@

    - SDWebImage源码解析 + Swift3.0学习笔记

    @@ -104,16 +104,16 @@

    -

    SDWebImage源码解析
    +

    总结一些 Swift3.0学习笔记

    - Read More + Read More

    @@ -123,10 +123,10 @@

    -
    +

    + + + +
    +
    + + + + + + +
    + + +
    +
    + + + + +
    -

    + + - -

    -
    + + +
    +
    + + +
    + + +
    + +
    - -

    - - + + + + + + + + + + + + + - + + - - + - + + -
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - \ No newline at end of file + diff --git "a/2015/05/04/Objective-C Runtime(\344\272\214) \345\257\271\350\261\241\346\250\241\345\236\213/index.html" "b/2015/05/04/Objective-C Runtime(\344\272\214) \345\257\271\350\261\241\346\250\241\345\236\213/index.html" index fa5e9ef..8b40a64 100644 --- "a/2015/05/04/Objective-C Runtime(\344\272\214) \345\257\271\350\261\241\346\250\241\345\236\213/index.html" +++ "b/2015/05/04/Objective-C Runtime(\344\272\214) \345\257\271\350\261\241\346\250\241\345\236\213/index.html" @@ -1,11 +1,96 @@ - - + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - Objective-C Runtime(二) 对象模型 | CoderShmily's Blog - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -18,51 +103,244 @@ + + + + + + + + + + + + + + Objective-C Runtime(二) 对象模型 | CoderShmily's Blog + + + + - - - - + + + + + + + + + + + + + + - + - - - -
    -
    - -
    -
    -
    + -

    + + + +
    +
    - - + + - + + +
    +
    + + + + + - -
    -

    归档

    -
    - + +
    + + + +
    +
    + + + + + + +
    + + +
    +
    + + + + + - + + - - -
    + + +
    +
    + + +
    + + +
    + + -
    - - - + + + + + + + + + + + + + - + + - - + - + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - \ No newline at end of file + diff --git "a/2015/05/05/Objective-C Runtime(\344\270\200) \346\246\202\350\277\260/index.html" "b/2015/05/05/Objective-C Runtime(\344\270\200) \346\246\202\350\277\260/index.html" index ffcb369..7c0ad96 100644 --- "a/2015/05/05/Objective-C Runtime(\344\270\200) \346\246\202\350\277\260/index.html" +++ "b/2015/05/05/Objective-C Runtime(\344\270\200) \346\246\202\350\277\260/index.html" @@ -1,11 +1,96 @@ - - + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - Objective-C Runtime(一) 概述 | CoderShmily's Blog - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -15,51 +100,244 @@ + + + + + + + + + + + + + + Objective-C Runtime(一) 概述 | CoderShmily's Blog + + + + - - - - + + + + + + + + + + + + + + - + - - - -
    -
    - -
    -
    -
    + -
    + + - -
    -

    归档

    - -
    + + +
    +
    + + +
    + + +
    + +
    - -
    - - + + + + + + + + + + + + + - + + - - + - + + -
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - \ No newline at end of file + diff --git "a/2015/05/06/Objective-C Runtime(\344\270\211) \346\266\210\346\201\257\344\274\240\351\200\222/index.html" "b/2015/05/06/Objective-C Runtime(\344\270\211) \346\266\210\346\201\257\344\274\240\351\200\222/index.html" index 68ff2f2..8008464 100644 --- "a/2015/05/06/Objective-C Runtime(\344\270\211) \346\266\210\346\201\257\344\274\240\351\200\222/index.html" +++ "b/2015/05/06/Objective-C Runtime(\344\270\211) \346\266\210\346\201\257\344\274\240\351\200\222/index.html" @@ -1,65 +1,343 @@ - - + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - Objective-C Runtime(三) 消息传递 | CoderShmily's Blog - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + Objective-C Runtime(三) 消息传递 | CoderShmily's Blog + + + + - - - - + + + + + + + + + + + + + + - + - - - -
    -
    - -
    -
    -
    + -
    + + - -
    -

    归档

    -
    - + + + - -
    -
    + + +
    +
    + + +
    + + +
    + +
    - -
    - - + + + + + + + + + + + + + - + + - - + - + + -
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - \ No newline at end of file + diff --git "a/2015/05/07/Objective-C Runtime(\345\233\233) \345\212\250\346\200\201\346\226\271\346\263\225\345\206\263\350\256\256/index.html" "b/2015/05/07/Objective-C Runtime(\345\233\233) \345\212\250\346\200\201\346\226\271\346\263\225\345\206\263\350\256\256/index.html" index c60a995..a5f6892 100644 --- "a/2015/05/07/Objective-C Runtime(\345\233\233) \345\212\250\346\200\201\346\226\271\346\263\225\345\206\263\350\256\256/index.html" +++ "b/2015/05/07/Objective-C Runtime(\345\233\233) \345\212\250\346\200\201\346\226\271\346\263\225\345\206\263\350\256\256/index.html" @@ -1,11 +1,96 @@ - - + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - Objective-C Runtime(四) 动态方法决议 | CoderShmily's Blog - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + Objective-C Runtime(四) 动态方法决议 | CoderShmily's Blog + + + + - - - - + + + + + + + + + + + + + + - + - - - -
    -
    - -
    -
    -
    + + + + + +
    +
    - - +
    + - + + +
    +
    + + +
    + + - -
    -

    归档

    -
    - + + + - -
    -
    + + +
    +
    + + +
    + + +
    + +
    - - - - + - + + + + + + + + + + + + + + - - + - + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - \ No newline at end of file + diff --git "a/2015/05/10/Objective-C Runtime(\344\272\224) \345\205\266\344\273\226\345\272\224\347\224\250/index.html" "b/2015/05/10/Objective-C Runtime(\344\272\224) \345\205\266\344\273\226\345\272\224\347\224\250/index.html" index 2e03c5a..aa24535 100644 --- "a/2015/05/10/Objective-C Runtime(\344\272\224) \345\205\266\344\273\226\345\272\224\347\224\250/index.html" +++ "b/2015/05/10/Objective-C Runtime(\344\272\224) \345\205\266\344\273\226\345\272\224\347\224\250/index.html" @@ -1,11 +1,96 @@ - - + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - Objective-C Runtime(五) 其他应用 | CoderShmily's Blog - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -21,51 +106,244 @@ + + + + + + + + + + + + + + Objective-C Runtime(五) 其他应用 | CoderShmily's Blog + + + + - - - - + + + + + + + + + + + + + + - + - - - -
    -
    - -
    -
    -
    + -
    + + - -
    -

    归档

    -
    - + + + - -
    -
    + + +
    +
    + + +
    + + +
    + +
    - -
    - - + + + + + + + + + + + + + - + + - - + - + + -
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - \ No newline at end of file + diff --git "a/2015/05/15/SDWebImage\346\272\220\347\240\201\350\247\243\346\236\220/index.html" "b/2015/05/15/SDWebImage\346\272\220\347\240\201\350\247\243\346\236\220/index.html" index b6f85c8..6afba7e 100644 --- "a/2015/05/15/SDWebImage\346\272\220\347\240\201\350\247\243\346\236\220/index.html" +++ "b/2015/05/15/SDWebImage\346\272\220\347\240\201\350\247\243\346\236\220/index.html" @@ -1,11 +1,96 @@ - - + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - SDWebImage源码解析 | CoderShmily's Blog - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -15,181 +100,569 @@ + + + + + + + + + + + + + + SDWebImage源码解析 | CoderShmily's Blog + + + + - - - - + + + + + + + + + + + + + + - + - - - -
    -
    - -
    -
    -
    + -
    + + - -
    -

    归档

    -
    - + +
    + + - -
    -
    + + +
    +
    + + +
    + + +
    + +
    - -
    - - + + + + + + + + + + - + + - - + - + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - \ No newline at end of file + diff --git "a/2015/06/03/const,static,extern\347\256\200\344\273\213/index.html" "b/2015/06/03/const,static,extern\347\256\200\344\273\213/index.html" index ee28e79..1b43acb 100644 --- "a/2015/06/03/const,static,extern\347\256\200\344\273\213/index.html" +++ "b/2015/06/03/const,static,extern\347\256\200\344\273\213/index.html" @@ -1,11 +1,96 @@ - - + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - const,static,extern简介 | CoderShmily's Blog - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -15,51 +100,244 @@ + + + + + + + + + + + + + + const,static,extern简介 | CoderShmily's Blog + + + + - - - - + + + + + + + + + + + + + + - + - - - -
    -
    - -
    -
    -
    + -
    + + - -
    -

    归档

    -
    - + + + - -
    -
    + + +
    +
    + + +
    + + +
    + +
    - -
    - - + + + + + + + + + + + + + - + + - - + - + + -
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - \ No newline at end of file + diff --git "a/2015/06/10/React Native\344\273\213\347\273\215/index.html" "b/2015/06/10/React Native\344\273\213\347\273\215/index.html" index 32a3163..3da3b61 100644 --- "a/2015/06/10/React Native\344\273\213\347\273\215/index.html" +++ "b/2015/06/10/React Native\344\273\213\347\273\215/index.html" @@ -1,11 +1,96 @@ - - + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - React Native介绍 | CoderShmily's Blog - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -15,56 +100,244 @@ + + + + + + + + + + + + + + React Native介绍 | CoderShmily's Blog + + + + - - - - + + + + + + + + + + + + + + - + - - - -
    -
    - -
    -
    -
    + + + + + +
    +
    - - +
    + - + + +
    +
    + + +
    + + - -
    -

    归档

    -
    - + + + - -
    -
    + + +
    +
    + + +
    + + +
    + +
    - - - - + - + + + + + + + - - + - + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - \ No newline at end of file + diff --git "a/2015/06/10/\345\260\217\347\237\245\350\257\206\347\202\271\346\200\273\347\273\223/index.html" "b/2015/06/10/\345\260\217\347\237\245\350\257\206\347\202\271\346\200\273\347\273\223/index.html" index e532992..9f0c3aa 100644 --- "a/2015/06/10/\345\260\217\347\237\245\350\257\206\347\202\271\346\200\273\347\273\223/index.html" +++ "b/2015/06/10/\345\260\217\347\237\245\350\257\206\347\202\271\346\200\273\347\273\223/index.html" @@ -1,11 +1,96 @@ - - + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - 小知识点总结 | CoderShmily's Blog - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -15,56 +100,244 @@ + + + + + + + + + + + + + + 小知识点总结 | CoderShmily's Blog + + + + - - - - + + + + + + + + + + + + + + - + - - - -
    -
    - -
    -
    -
    + + + + + +
    +
    - - +
    + - + + +
    +
    + + +
    + + - -
    -

    归档

    -
    - + + + - -
    -
    + + +
    +
    + + +
    + + +
    + +
    - - - - + - + + + + + + + - - + - + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - \ No newline at end of file + diff --git "a/2016/11/15/Swift3.0\345\255\246\344\271\240\347\254\224\350\256\260/index.html" "b/2016/11/15/Swift3.0\345\255\246\344\271\240\347\254\224\350\256\260/index.html" index 80cd0c4..5ee3836 100644 --- "a/2016/11/15/Swift3.0\345\255\246\344\271\240\347\254\224\350\256\260/index.html" +++ "b/2016/11/15/Swift3.0\345\255\246\344\271\240\347\254\224\350\256\260/index.html" @@ -1,70 +1,343 @@ - - + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - Swift3.0学习笔记 | CoderShmily's Blog - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + Swift3.0学习笔记 | CoderShmily's Blog + + + + - - - - + + + + + + + + + + + + + + - + - - - -
    -
    - -
    -
    -
    + + + + + +
    +
    - - +
    + - + + +
    +
    + + +
    + + - -
    -

    归档

    -
    - + + + - -
    -
    + + +
    +
    + + +
    + + +
    + +
    - - - - + - + + + + + + + - - + - + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - \ No newline at end of file + diff --git "a/2016/12/03/iOS9\346\226\260\347\211\271\346\200\247\344\271\213\345\270\270\350\247\201\345\205\263\351\224\256\345\255\227/index.html" "b/2016/12/03/iOS9\346\226\260\347\211\271\346\200\247\344\271\213\345\270\270\350\247\201\345\205\263\351\224\256\345\255\227/index.html" index c3de76d..40038f9 100644 --- "a/2016/12/03/iOS9\346\226\260\347\211\271\346\200\247\344\271\213\345\270\270\350\247\201\345\205\263\351\224\256\345\255\227/index.html" +++ "b/2016/12/03/iOS9\346\226\260\347\211\271\346\200\247\344\271\213\345\270\270\350\247\201\345\205\263\351\224\256\345\255\227/index.html" @@ -1,11 +1,96 @@ - - + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - iOS9新特性之常见关键字 | CoderShmily's Blog - - + + + + + + + + + + + + + + + + + + + + + @@ -24,56 +109,244 @@ 迎合swift 提高我们开发人员开发规范,减少程序员之间的交流"> + + + + + + + + + + + + + + iOS9新特性之常见关键字 | CoderShmily's Blog + + + + - - - - + + + + + + + + + + + + + + - + - - - -
    -
    - -
    -
    -
    +
    + + + + +
    -
    +
    + -
    + - + + +
    +
    + + +
    + + - -
    -

    归档

    -
    - + + + - -
    -
    + + +
    +
    + + +
    + + +
    + +
    - -
    - - + - + + + + + + + - - + - + + -
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - \ No newline at end of file + diff --git a/archives/2015/05/index.html b/archives/2015/05/index.html index 5f03580..975345d 100644 --- a/archives/2015/05/index.html +++ b/archives/2015/05/index.html @@ -1,11 +1,96 @@ - - + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + - 归档: 2015/5 | CoderShmily's Blog - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -14,304 +99,759 @@ + + + + + + + + + + + + + + Archive | CoderShmily's Blog + + + + - + + + + + + + + + + + + + + - + + + - - - - + - + + + + - - + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - \ No newline at end of file + diff --git a/archives/2015/06/index.html b/archives/2015/06/index.html index 2b3f7b7..42ef107 100644 --- a/archives/2015/06/index.html +++ b/archives/2015/06/index.html @@ -1,11 +1,96 @@ - - + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - 归档: 2015/6 | CoderShmily's Blog - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -14,190 +99,537 @@ + + + + + + + + + + + + + + Archive | CoderShmily's Blog + + + + - + + + + + + + + + + + + + + - + + + - - - - + + + + + + + + + + + + + - + + - - + - + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - \ No newline at end of file + diff --git a/archives/2015/index.html b/archives/2015/index.html index 81bbd81..2387288 100644 --- a/archives/2015/index.html +++ b/archives/2015/index.html @@ -1,341 +1,898 @@ - - - - + + + + - 归档: 2015 | CoderShmily's Blog - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + - - - - - -
    -
    - -
    -
    - - - - -
    -
    - 2015 -
    -
    - - - - -
    -
    -
    - - + -

    - const,static,extern简介 -

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Archive | CoderShmily's Blog + + + + -
    -
    -
    + + + + + + + + + + + + + - - - - - + - - - - - - - -
    - - - - - - - - - - -
    - + + +
    +

    2015

    +
    + + + - + - - - - - - -
    -

    最新文章

    - -
    + - - - + -
    - -
    - -
    -
    -
    - + + + + + + - + + + + + - - + + -
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - \ No newline at end of file + diff --git a/archives/2015/page/2/index.html b/archives/2015/page/2/index.html index ee9fd21..2a72e65 100644 --- a/archives/2015/page/2/index.html +++ b/archives/2015/page/2/index.html @@ -1,11 +1,96 @@ - - + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - 归档: 2015 | CoderShmily's Blog - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -14,176 +99,504 @@ + + + + + + + + + + + + + + Archive | CoderShmily's Blog + + + + - + + + + + + + + + + + + + + - + + + - - - - + - + + + + - - + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - \ No newline at end of file + diff --git a/archives/2016/11/index.html b/archives/2016/11/index.html index e8ab065..04d2daf 100644 --- a/archives/2016/11/index.html +++ b/archives/2016/11/index.html @@ -1,11 +1,96 @@ - - + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - 归档: 2016/11 | CoderShmily's Blog - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -14,152 +99,463 @@ + + + + + + + + + + + + + + Archive | CoderShmily's Blog + + + + - - - - + + + + + + + + + + + + + + - + - - - -
    -
    + - - - -
    - +
    +
    +
    +
    + + +
    + -
    + + + + -
    + + + + + +
    + + - -
    -

    归档

    -
    - + +
    + + - -
    -
    +
    + +
    +
    + + +
    + + +
    + +
    - - - - + + + + + + + + + + + + + - + + - - + - + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - \ No newline at end of file + diff --git a/archives/2016/12/index.html b/archives/2016/12/index.html index e37fe83..8b54c59 100644 --- a/archives/2016/12/index.html +++ b/archives/2016/12/index.html @@ -1,11 +1,96 @@ - - + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - 归档: 2016/12 | CoderShmily's Blog - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -14,152 +99,463 @@ + + + + + + + + + + + + + + Archive | CoderShmily's Blog + + + + - - - - + + + + + + + + + + + + + + - + - - - -
    -
    + - - - -
    - +
    +
    +
    +
    + + +
    + -
    + + + + -
    + + + + + +
    + + - -
    -

    归档

    -
    - + +
    + + - -
    -
    +
    + +
    +
    + + +
    + + +
    + +
    - - - - + + + + + + + + + + + + + - + + - - + - + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - \ No newline at end of file + diff --git a/archives/2016/index.html b/archives/2016/index.html index e6e64a4..5082175 100644 --- a/archives/2016/index.html +++ b/archives/2016/index.html @@ -1,11 +1,96 @@ - - + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - 归档: 2016 | CoderShmily's Blog - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -14,171 +99,500 @@ + + + + + + + + + + + + + + Archive | CoderShmily's Blog + + + + - + + + + + + + + + + + + + + - + + + - - - - + - + + + + - - + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - \ No newline at end of file + diff --git a/archives/index.html b/archives/index.html index 1691be7..1b74c74 100644 --- a/archives/index.html +++ b/archives/index.html @@ -1,11 +1,96 @@ - - + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - 归档 | CoderShmily's Blog - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -14,338 +99,805 @@ + + + + + + + + + + + + + + Archive | CoderShmily's Blog + + + + + + + + + + + + + + + + + + + + - + + + + + + - + + + - - - - - -
    + + -
    - -
    -
    - - - - - - - + + + + + + - - \ No newline at end of file + diff --git a/archives/page/2/index.html b/archives/page/2/index.html index 3230fd4..51559cb 100644 --- a/archives/page/2/index.html +++ b/archives/page/2/index.html @@ -1,11 +1,96 @@ - - + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - 归档 | CoderShmily's Blog - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -14,214 +99,578 @@ + + + + + + + + + + + + + + Archive | CoderShmily's Blog + + + + - + + + + + + + + + + + + + + - + + + - - - - + - + + + + - - + + + + - + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - \ No newline at end of file + diff --git a/categories/Swift/index.html b/categories/Swift/index.html index 5f2c6c9..72c99ee 100644 --- a/categories/Swift/index.html +++ b/categories/Swift/index.html @@ -1,11 +1,96 @@ - - + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - Category: Swift | CoderShmily's Blog - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -14,181 +99,464 @@ - - - - - - - - - - + + + + + + + + + + + + + + Category: Swift | CoderShmily's Blog - -
    -
    - -
    -
    + + + + + + + + + + + + + + + + + + + + + +
    + + + + -
    -
    - 2015 -
    -
    - -
    - - - -
    - +
    +
    +
    +
    + + +
    +
    +

    SwiftCategory +

    +
    + + + -
    + + + -
    -

    分类

    -
    - -
    -
    + + + - + - + + + +
    + + + + + +
    + + - -
    -

    归档

    -
    - + +
    + + - -
    -
    +
    + +
    +
    + + +
    + + +
    + +
    - - - - + + + + + + + + + + - + + + + - - + - + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - \ No newline at end of file + diff --git a/categories/iOS/index.html b/categories/iOS/index.html new file mode 100644 index 0000000..933dc55 --- /dev/null +++ b/categories/iOS/index.html @@ -0,0 +1,790 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Category: iOS | CoderShmily's Blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/categories/iOS/page/2/index.html b/categories/iOS/page/2/index.html index a140042..4cfb41f 100644 --- a/categories/iOS/page/2/index.html +++ b/categories/iOS/page/2/index.html @@ -1,11 +1,96 @@ - - + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - Category: iOS | CoderShmily's Blog - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -14,176 +99,468 @@ + + + + + + + + + + + + + + Category: iOS | CoderShmily's Blog + + + + - - - - + + + + + + + + + + + + + + - + - - - -
    -
    + - - - + +
    +
    +
    +
    + + +
    +
    +

    iOSCategory +

    +
    + - - - -
    - + - + + + - + - + + + + + +
    + + + + + +
    + + - -
    -

    归档

    -
    - + +
    + + - -
    -
    +
    + +
    +
    + + +
    + + +
    + +
    - -
    - - + - + + + + - - + - + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - \ No newline at end of file + diff --git a/css/fonts/FontAwesome.otf b/css/fonts/FontAwesome.otf deleted file mode 100644 index 8b0f54e47e1d356dcf1496942a50e228e0f1ee14..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 62856 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 - - -
    - -
    - + + +
    + + +
    +
    +
    +
    + +
    -
    - + + + + + -

    - React Native介绍 -

    -
    +
    + + + + + + -
    - -

    简介

    2015年9月15日,Facebook发布了 React Native for Android,把 Web 和原生平台的 JavaScript 开发技术扩展到了 Google 的流行移动平台

    +
    + -

    - Read More -

    - -
    - -
    - -
    +

    + +

    + + +
    + +
    - - + - -
    - -
    - - -
    - -

    - Objective-C Runtime(五) 其他应用 -

    + + +
    + + + + + + + +
    + + + +

    + +

    + + +
    -
    + +
    + + + + -
      -
    • 动态添加方法
    • -
    • 给分类添加属性
    • -
    • 字典转模型
    • -
    -

    - Read More -

    +

    总结一些 Swift3.0学习笔记

    + +
    + + Read more » + +
    +
    - -
    - -
    +
    +
    + +
    - -
    - -
    - - -
    - - -

    - Objective-C Runtime(四) 动态方法决议 -

    - + -
    - -
    - - - -

    动态方法决议/动态方法解析(Dynamic Method Resolution)

    -

    在声明property属性后,有2种实现选择

    -
      -
    • @synthesize
    • -
    -

    编译器期间,让编译器自动生成getter/setter方法。当有自定义的存或取方法时,自定义会屏蔽自动生成该方法

    -
      -
    • @dynamic
    • -
    -

    告诉编译器,不自动生成getter/setter方法,避免编译期间产生警告,然后由自己实现存取方法或存取方法在运行时动态创建绑定。

    -

    由于使用@dynamic,我们需要自己提供setter和getter方法。一般有两种方法:

    -

    1). 自己提供setter和getter方法,将编译器自动生成的setter和getter方法手动再写一遍;
    注意:需要在类中显式提供实例变量,因为@dynamic不能像@synthesize那样向实现文件(.m)提供实例变量。

    -
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    #import <Foundation/Foundation.h>
    @interface Person : NSObject
    {
    // must provide a ivar for our setter and getter
    NSString *_name;
    }
    @property (copy) NSString *name;
    @end
    @implementation Person
    // @dynamic tells compiler don't generate setter and getter automatically
    @dynamic name;
    // We provide setter and getter here
    - (void) setName:(NSString *)name
    {
    if (_name != name) {
    [_name release];
    _name = [name copy];
    }
    }
    - (NSString *) name
    {
    return _name;
    }
    @end // Person
    int main(int argc, const char * argv[])
    {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    Person *a = [[Person alloc] init];
    a.name = @"Hello"; // Ok, use our setter
    a.name = @"Hello, world";
    NSLog(@"%@", a.name); // Ok, use our getter
    [a release];
    [pool drain];
    return 0;
    } // main
    -

    2). 动态方法决议(DynamicMethod Resolution),在运行时提供setter和getter对应实现的C函数。

    -

    第二种方法,在运行时决定setter和getter对应实现的C函数,使用了NSObject提供的resolveInstanceMethod:方法。在C函数中不能直接使用实例变量,需要将ObjC对象self转成C中的结构体,因此在Person类同样需要显式声明实例变量而且访问级别是@public,为了隐藏该实例变量,将声明放在扩展(extension)中

    -
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    #import <Foundation/Foundation.h>
    #import <objc/objc-runtime.h> // for class_addMethod()
    // ------------------------------------------------------
    // A .h file
    @interface Person : NSObject
    @property (copy) NSString *name;
    - (void) hello;
    @end
    // ------------------------------------------------------
    // A .m file
    // Use extension to override the access level of _name ivar
    @interface Person ()
    {
    @public
    NSString *_name;
    }
    @end
    @implementation Person
    // @dynamic implies compiler to look for setName: and name method in runtime
    @dynamic name;
    // Only resolve unrecognized methods, and only load methods dynamically once
    + (BOOL) resolveInstanceMethod:(SEL)sel
    {
    // Capture setName: and name method
    if (sel == @selector(setName:)) {
    class_addMethod([self class], sel, (IMP)setName, "v@:@");
    /*
    @encode()可以接受任何类型,Objective-C 中用这个指令做类型编码,它可以把任何一个类型转换为字符串,譬如:void 类型被编码之后为v,对象类型为@,SEL 类型为:等,具体的你可以参看Apple 官方页面关于Type Encoding 的描述:
    http://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html#//apple_ref/doc/uid/TP40008048-CH100-SW
    现在我们来正式的看以下第四个参数v@:f 的含义,它描述了IMP 指向的函数的描述信息,按照@encode指令编译之后的字符说明,第一个字符v 表示返回值为void,剩余的字符为dynamicMethod函数的参数描述,@表示第一个参数id,:自然就是第二个参数SEL,f就是第三个参数float。由于前面说过动态方法的实现的前两个参数必须是id、SEL,所以第四个参数中的字符串的第二、三个字符一定是@:。
    */
    return YES;
    }
    else if (sel == @selector(name)) {
    class_addMethod([self class], sel, (IMP)getName, "@@:");
    return YES;
    }
    return [super resolveInstanceMethod:sel];
    }
    //+ (BOOL)resolveClassMethod:(SEL)name
    //{
    // NSLog(@" >> Class resolving %@", NSStringFromSelector(name));
    //
    // return [super resolveClassMethod:name];
    //}
    void setName(id self, SEL _cmd, NSString* name)
    {
    // Implement @property (copy)
    if (((Person *)self)->_name != name) {
    [((Person *)self)->_name release];
    ((Person *)self)->_name = [name copy];
    }
    }
    NSString* getName(id self, SEL _cmd)
    {
    return ((Person *)self)->_name;
    }
    - (void) hello
    {
    NSLog(@"Hello, world");
    }
    @end // Person
    int main(int argc, const char * argv[])
    {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    Person *a = [[Person alloc] init];
    [a hello]; // never call resolveInstanceMethod
    a.name = @"hello1";
    NSLog(@"%@", a.name);
    a.name = @"hello2";
    NSLog(@"%@", a.name);
    [a release];
    [pool drain];
    return 0;
    } // main
    -

    Objective-C 的运行时只要发现你调用了@dynamic标注的属性的
    setter、getter 方法,就会自动到resolveInstanceMethod 里去寻找真实的实现。实际上除了@dynamic标注的属性之外,如果你调用了类型中不存在的方法,也会被resolveInstanceMethod或者
    resolveClassMethod截获,但由于你没有处理,所以会报告不能识别的消息的错误。一般Objective-C的运行时编程用到的并不多,除非你想设计一个动态化的功能,譬如:从网络下载一个升级包,不需要退出原有的程序,就可以动态的替换掉旧的功能等类似的需求。

    -
    -

    ####动态方法决议

    -

    研究运行时系统是如何进行动态方法决议的,下面的代码来自苹果官方公开的源码 objc-class.mm,我在其中添加了中文注释:

    -

    1,首先是判断是不是要进行类方法决议,如果不是或决议失败,则进行实例方法决议

    -
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    /**********************************************************
    * _class_resolveMethod
    * Call +resolveClassMethod or +resolveInstanceMethod and return
    * the method added or NULL.
    * Assumes the method doesn't exist already.
    ***********************************************************/
    __private_extern__ Method _class_resolveMethod(Class cls, SEL sel)
    {
    Method meth = NULL;
    if (_class_isMetaClass(cls)) {
    meth = _class_resolveClassMethod(cls, sel);
    }
    if (!meth) {
    meth = _class_resolveInstanceMethod(cls, sel);
    }
    if (PrintResolving && meth) {
    _objc_inform("RESOLVE: method %c[%s %s] dynamically resolved to %p",
    class_isMetaClass(cls) ? '+' : '-',
    class_getName(cls), sel_getName(sel),
    method_getImplementation(meth));
    }
    return meth;
    }
    -

    2,类方法决议与实例方法决议大体相似,在这里就只看实例方法决议部分了:

    -
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    /***********************************************************************
    * _class_resolveInstanceMethod
    * Call +resolveInstanceMethod and return the method added or NULL.
    * cls should be a non-meta class.
    * Assumes the method doesn't exist already.
    **********************************************************************/
    static Method _class_resolveInstanceMethod(Class cls, SEL sel)
    {
    BOOL resolved;
    Method meth = NULL;
    // 是否实现了 resolveInstanceMethod,如果没有返回 NULL
    if (!look_up_method(((id)cls)->isa, SEL_resolveInstanceMethod,
    YES /*cache*/, NO /*resolver*/))
    {
    return NULL;
    }
    // 调用 resolveInstanceMethod,并获取返回值
    resolved = ((BOOL(*)(id, SEL, SEL))objc_msgSend)((id)cls, SEL_resolveInstanceMethod, sel);
    if (resolved) {
    // 返回值为 YES,表示 resolveInstanceMethod 声称它已经成功添加实现,则再次查找 method list
    // +resolveClassMethod adds to self
    meth = look_up_method(cls, sel, YES/*cache*/, NO/*resolver*/);
    if (!meth) {
    // resolveInstanceMethod 使诈了,它声称成功添加实现了,但实际没有,给出警告信息,并返回 NULL
    // Method resolver didn't add anything?
    _objc_inform("+[%s resolveInstanceMethod:%s] returned YES, but "
    "no new implementation of %c[%s %s] was found",
    class_getName(cls),
    sel_getName(sel),
    class_isMetaClass(cls) ? '+' : '-',
    class_getName(cls),
    sel_getName(sel));
    return NULL;
    }
    }
    // 其他情况下返回 NULL
    return meth;
    }
    -

    这段代码很容易理解:

    -
      -
    1. 首先判断是否实现了 resolveInstanceMethod,如果没有实现,返回 NULL,进入下一步处理;
    2. -
    3. 如果实现了,调用 resolveInstanceMethod,获取返回值;
    4. -
    5. 如果返回值为 YES,表示 resolveInstanceMethod 声称它已经提供了 selector 的实现,因此再次查找 method list,如果找到对应的IMP,则返回该实现,否则提示警告信息,返回 NULL,进入下一步处理;
    6. -
    7. 如果返回值为 NO,返回 NULL,进入下一步处理;
    8. -
    -

    加入消息转发

    在前文《深入浅出Cocoa之消息》,我演示了一个消息转发的示例,下面我把动态方法决议部分去除,把消息转发部分添加进来:

    -
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    // Proxy
    @interface Proxy : NSObject
    -(void)MissMethod;
    @end
    @implementation Proxy
    -(void)MissMethod
    {
    NSLog(@" >> MissMethod() called in Proxy.");
    }
    @end
    // Foo
    @interface Foo : NSObject
    -(void)Bar;
    @end
    @implementation Foo
    - (void)forwardInvocation:(NSInvocation *)anInvocation
    {
    SEL name = [anInvocation selector];
    NSLog(@" >> forwardInvocation for selector %@", NSStringFromSelector(name));
    Proxy * proxy = [[[Proxy alloc] init] autorelease];
    if ([proxy respondsToSelector:name]) {
    [anInvocation invokeWithTarget:proxy];
    }
    else {
    [super forwardInvocation:anInvocation];
    }
    }
    - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    return [Proxy instanceMethodSignatureForSelector:aSelector];
    }
    -(void)Bar
    {
    NSLog(@" >> Bar() in Foo.");
    }
    @end
    -

    运行测试代码,输出如下:

    -
    1
    2
    3
    >> Bar() in Foo.
    >> forwardInvocation for selector MissMethod
    >> MissMethod() called in Proxy.
    -

    如果我把动态方法决议部分代码也加入进来输出又是怎样呢?下面只列出了 Foo 的实现代码,其他代码不变动。

    -
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    @implementation Foo
    +(BOOL)resolveInstanceMethod:(SEL)name
    {
    NSLog(@" >> Instance resolving %@", NSStringFromSelector(name));
    if (name == @selector(MissMethod)) {
    class_addMethod([self class], name, (IMP)dynamicMethodIMP, "v@:");
    return YES;
    }
    return [super resolveInstanceMethod:name];
    }
    +(BOOL)resolveClassMethod:(SEL)name
    {
    NSLog(@" >> Class resolving %@", NSStringFromSelector(name));
    return [super resolveClassMethod:name];
    }
    - (void)forwardInvocation:(NSInvocation *)anInvocation
    {
    SEL name = [anInvocation selector];
    NSLog(@" >> forwardInvocation for selector %@", NSStringFromSelector(name));
    Proxy * proxy = [[[Proxy alloc] init] autorelease];
    if ([proxy respondsToSelector:name]) {
    [anInvocation invokeWithTarget:proxy];
    }
    else {
    [super forwardInvocation:anInvocation];
    }
    }
    - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    return [Proxy instanceMethodSignatureForSelector:aSelector];
    }
    -(void)Bar
    {
    NSLog(@" >> Bar() in Foo.");
    }
    @end
    -

    此时,输出为:

    -
    1
    2
    3
    4
    >> Bar() in Foo.
    >> Instance resolving MissMethod
    >> dynamicMethodIMP called.
    >> Instance resolving _doZombieMe
    -

    注意到了没,消息转发没有进行!在前文中说过,消息转发只有在对象无法正常处理消息时才会调用,而在这里我在动态方法决议中为 selector 提供了实现,使得对象可以处理该消息,所以消息转发不会继续了。官方文档中说:

    -
    1
    If you implement resolveInstanceMethod: but want particular selectors to actually be forwarded via the forwarding mechanism, you return NO for those selectors.
    -

    文档里的说法其实并不准确,只有在 resolveInstanceMethod 的实现中没有真正为 selector 提供实现,并返回 NO 的情况下才会进入消息转发流程;否则绝不会进入消息转发流程,程序要么调用正确的动态方法,要么 crash。这也与前面的源码不太一致,我猜测在比上面源码的更高层次的地方,再次查找了 method list,如果提供了实现就能够找到该实现。

    -

    下面我把 resolveInstanceMethod 方法中为 selector 添加实现的那一行屏蔽了,消息转发就应该会进行:

    -
    1
    //class_addMethod([self class], name, (IMP)dynamicMethodIMP, "v@:");
    -

    再次编译运行,此时输出正如前面所推断的那样:

    -
    1
    2
    3
    4
    5
    6
    >> Bar() in Foo.
    >> Instance resolving MissMethod
    objc[1618]: +[Foo resolveInstanceMethod:MissMethod] returned YES, but no new implementation of -[Foo MissMethod] was found
    >> forwardInvocation for selector MissMethod
    >> MissMethod() called in Proxy.
    >> Instance resolving _doZombieMe
    -

    进行了消息转发!而且编译器很善意地提示(见前面源码剖析):哎呀,你不能欺骗我嘛,你说添加了实现(返回YES),其实还是没有呀!然后编译器就无奈地去看能不能消息转发了。当然如果把返回值修改为 NO 就不会有该警告出现,其他的输出不变。

    -

    总结

    从上面的示例演示可以看出,动态方法决议是先于消息转发的。

    -

    如果向一个 Objective C 对象发送它无法处理的消息(selector),那么编译器会按照如下次序进行处理:

    -

    1 首先看是否为该 selector 提供了动态方法决议机制,如果提供了则转到2;如果没有提供则转到 3;

    -
      -
    1. 如果动态方法决议真正为该selector 提供了实现,那么就调用该实现,完成消息发送流程,消息转发就不会进行了;如果没有提供,则转到 3;

      -
    2. -
    3. 其次看是否为该 selector 提供了消息转发机制,如果提供了消息了则进行消息转发,此时,无论消息转发是怎样实现的,程序均不会crash。(因为消息调用的控制权完全交给消息转发机制处理,即使消息转发并没有做任何事情,运行也不会有错误,编译器更不会有错误提示。);如果没提供消息转发机制,则转到 4;

      -
    4. -
    5. 运行报错:无法识别的 selector,程序 crash;

      -
    6. -
    -
    - -
    - -
    +
    - - +

    + +

    + + +
    + +
    - + + - + - + + + - - +
    + + + + + - - - - - - -
    - -
    - -
    -
    - - - + + + +
    + + + + + +

    简介

    2015年9月15日,Facebook发布了 React Native for Android,把 Web 和原生平台的 JavaScript 开发技术扩展到了 Google 的流行移动平台

    + +
    + + Read more » + +
    + + + +
    + +
    + +
    + +
    + +
    + +
    + +
    + +
    + + + + + + + + +
    + +
    +
    + + + + + + + + + + + +
    + + + + + + + +
    + + + +

    + +

    + + + +
    + + +
    + + + + + + +

    const,static,extern简介

    + +
    + + Read more » + +
    + + + +
    + +
    + +
    + +
    + +
    + +
    + +
    + +
    + + + + + + + + +
    + +
    +
    + + + + + + + + + + + +
    + + + + + + + +
    + + + +

    + +

    + + + +
    + + +
    + + + + + + +

    SDWebImage源码解析
    + +

    + + Read more » + +
    + + + +
    + +
    + +
    + +
    + +
    + +
    + +
    + +
    + + + + + + + + +
    + +
    +
    + + + + + + + + + + + +
    + + + + + + + +
    + + + +

    + +

    + + + +
    + + +
    + + + + + + +
      +
    • 动态添加方法
    • +
    • 给分类添加属性
    • +
    • 字典转模型
    • +
    + +
    + + Read more » + +
    + + + +
    + +
    + +
    + +
    + +
    + +
    + +
    + +
    + + + + + + + + +
    + +
    +
    + + + + + + + + + + + +
    + + + + + + + +
    + + + +

    + +

    + + + +
    + + +
    + + + + + + + + +

    动态方法决议/动态方法解析(Dynamic Method Resolution)

    +

    在声明property属性后,有2种实现选择

    +
      +
    • @synthesize
    • +
    +

    编译器期间,让编译器自动生成getter/setter方法。当有自定义的存或取方法时,自定义会屏蔽自动生成该方法

    +
      +
    • @dynamic
    • +
    +

    告诉编译器,不自动生成getter/setter方法,避免编译期间产生警告,然后由自己实现存取方法或存取方法在运行时动态创建绑定。

    +

    由于使用@dynamic,我们需要自己提供setter和getter方法。一般有两种方法:

    +

    1). 自己提供setter和getter方法,将编译器自动生成的setter和getter方法手动再写一遍;
    注意:需要在类中显式提供实例变量,因为@dynamic不能像@synthesize那样向实现文件(.m)提供实例变量。

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    #import <Foundation/Foundation.h>
    @interface Person : NSObject
    {
    // must provide a ivar for our setter and getter
    NSString *_name;
    }
    @property (copy) NSString *name;
    @end
    @implementation Person
    // @dynamic tells compiler don't generate setter and getter automatically
    @dynamic name;
    // We provide setter and getter here
    - (void) setName:(NSString *)name
    {
    if (_name != name) {
    [_name release];
    _name = [name copy];
    }
    }
    - (NSString *) name
    {
    return _name;
    }
    @end // Person
    int main(int argc, const char * argv[])
    {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    Person *a = [[Person alloc] init];
    a.name = @"Hello"; // Ok, use our setter
    a.name = @"Hello, world";
    NSLog(@"%@", a.name); // Ok, use our getter
    [a release];
    [pool drain];
    return 0;
    } // main
    +

    2). 动态方法决议(DynamicMethod Resolution),在运行时提供setter和getter对应实现的C函数。

    +

    第二种方法,在运行时决定setter和getter对应实现的C函数,使用了NSObject提供的resolveInstanceMethod:方法。在C函数中不能直接使用实例变量,需要将ObjC对象self转成C中的结构体,因此在Person类同样需要显式声明实例变量而且访问级别是@public,为了隐藏该实例变量,将声明放在扩展(extension)中

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    #import <Foundation/Foundation.h>
    #import <objc/objc-runtime.h> // for class_addMethod()
    // ------------------------------------------------------
    // A .h file
    @interface Person : NSObject
    @property (copy) NSString *name;
    - (void) hello;
    @end
    // ------------------------------------------------------
    // A .m file
    // Use extension to override the access level of _name ivar
    @interface Person ()
    {
    @public
    NSString *_name;
    }
    @end
    @implementation Person
    // @dynamic implies compiler to look for setName: and name method in runtime
    @dynamic name;
    // Only resolve unrecognized methods, and only load methods dynamically once
    + (BOOL) resolveInstanceMethod:(SEL)sel
    {
    // Capture setName: and name method
    if (sel == @selector(setName:)) {
    class_addMethod([self class], sel, (IMP)setName, "v@:@");
    /*
    @encode()可以接受任何类型,Objective-C 中用这个指令做类型编码,它可以把任何一个类型转换为字符串,譬如:void 类型被编码之后为v,对象类型为@,SEL 类型为:等,具体的你可以参看Apple 官方页面关于Type Encoding 的描述:
    http://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html#//apple_ref/doc/uid/TP40008048-CH100-SW
    现在我们来正式的看以下第四个参数v@:f 的含义,它描述了IMP 指向的函数的描述信息,按照@encode指令编译之后的字符说明,第一个字符v 表示返回值为void,剩余的字符为dynamicMethod函数的参数描述,@表示第一个参数id,:自然就是第二个参数SEL,f就是第三个参数float。由于前面说过动态方法的实现的前两个参数必须是id、SEL,所以第四个参数中的字符串的第二、三个字符一定是@:。
    */
    return YES;
    }
    else if (sel == @selector(name)) {
    class_addMethod([self class], sel, (IMP)getName, "@@:");
    return YES;
    }
    return [super resolveInstanceMethod:sel];
    }
    //+ (BOOL)resolveClassMethod:(SEL)name
    //{
    // NSLog(@" >> Class resolving %@", NSStringFromSelector(name));
    //
    // return [super resolveClassMethod:name];
    //}
    void setName(id self, SEL _cmd, NSString* name)
    {
    // Implement @property (copy)
    if (((Person *)self)->_name != name) {
    [((Person *)self)->_name release];
    ((Person *)self)->_name = [name copy];
    }
    }
    NSString* getName(id self, SEL _cmd)
    {
    return ((Person *)self)->_name;
    }
    - (void) hello
    {
    NSLog(@"Hello, world");
    }
    @end // Person
    int main(int argc, const char * argv[])
    {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    Person *a = [[Person alloc] init];
    [a hello]; // never call resolveInstanceMethod
    a.name = @"hello1";
    NSLog(@"%@", a.name);
    a.name = @"hello2";
    NSLog(@"%@", a.name);
    [a release];
    [pool drain];
    return 0;
    } // main
    +

    Objective-C 的运行时只要发现你调用了@dynamic标注的属性的
    setter、getter 方法,就会自动到resolveInstanceMethod 里去寻找真实的实现。实际上除了@dynamic标注的属性之外,如果你调用了类型中不存在的方法,也会被resolveInstanceMethod或者
    resolveClassMethod截获,但由于你没有处理,所以会报告不能识别的消息的错误。一般Objective-C的运行时编程用到的并不多,除非你想设计一个动态化的功能,譬如:从网络下载一个升级包,不需要退出原有的程序,就可以动态的替换掉旧的功能等类似的需求。

    +
    +

    ####动态方法决议

    +

    研究运行时系统是如何进行动态方法决议的,下面的代码来自苹果官方公开的源码 objc-class.mm,我在其中添加了中文注释:

    +

    1,首先是判断是不是要进行类方法决议,如果不是或决议失败,则进行实例方法决议

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    /**********************************************************
    * _class_resolveMethod
    * Call +resolveClassMethod or +resolveInstanceMethod and return
    * the method added or NULL.
    * Assumes the method doesn't exist already.
    ***********************************************************/
    __private_extern__ Method _class_resolveMethod(Class cls, SEL sel)
    {
    Method meth = NULL;
    if (_class_isMetaClass(cls)) {
    meth = _class_resolveClassMethod(cls, sel);
    }
    if (!meth) {
    meth = _class_resolveInstanceMethod(cls, sel);
    }
    if (PrintResolving && meth) {
    _objc_inform("RESOLVE: method %c[%s %s] dynamically resolved to %p",
    class_isMetaClass(cls) ? '+' : '-',
    class_getName(cls), sel_getName(sel),
    method_getImplementation(meth));
    }
    return meth;
    }
    +

    2,类方法决议与实例方法决议大体相似,在这里就只看实例方法决议部分了:

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    /***********************************************************************
    * _class_resolveInstanceMethod
    * Call +resolveInstanceMethod and return the method added or NULL.
    * cls should be a non-meta class.
    * Assumes the method doesn't exist already.
    **********************************************************************/
    static Method _class_resolveInstanceMethod(Class cls, SEL sel)
    {
    BOOL resolved;
    Method meth = NULL;
    // 是否实现了 resolveInstanceMethod,如果没有返回 NULL
    if (!look_up_method(((id)cls)->isa, SEL_resolveInstanceMethod,
    YES /*cache*/, NO /*resolver*/))
    {
    return NULL;
    }
    // 调用 resolveInstanceMethod,并获取返回值
    resolved = ((BOOL(*)(id, SEL, SEL))objc_msgSend)((id)cls, SEL_resolveInstanceMethod, sel);
    if (resolved) {
    // 返回值为 YES,表示 resolveInstanceMethod 声称它已经成功添加实现,则再次查找 method list
    // +resolveClassMethod adds to self
    meth = look_up_method(cls, sel, YES/*cache*/, NO/*resolver*/);
    if (!meth) {
    // resolveInstanceMethod 使诈了,它声称成功添加实现了,但实际没有,给出警告信息,并返回 NULL
    // Method resolver didn't add anything?
    _objc_inform("+[%s resolveInstanceMethod:%s] returned YES, but "
    "no new implementation of %c[%s %s] was found",
    class_getName(cls),
    sel_getName(sel),
    class_isMetaClass(cls) ? '+' : '-',
    class_getName(cls),
    sel_getName(sel));
    return NULL;
    }
    }
    // 其他情况下返回 NULL
    return meth;
    }
    +

    这段代码很容易理解:

    +
      +
    1. 首先判断是否实现了 resolveInstanceMethod,如果没有实现,返回 NULL,进入下一步处理;
    2. +
    3. 如果实现了,调用 resolveInstanceMethod,获取返回值;
    4. +
    5. 如果返回值为 YES,表示 resolveInstanceMethod 声称它已经提供了 selector 的实现,因此再次查找 method list,如果找到对应的IMP,则返回该实现,否则提示警告信息,返回 NULL,进入下一步处理;
    6. +
    7. 如果返回值为 NO,返回 NULL,进入下一步处理;
    8. +
    +

    加入消息转发

    在前文《深入浅出Cocoa之消息》,我演示了一个消息转发的示例,下面我把动态方法决议部分去除,把消息转发部分添加进来:

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    // Proxy
    @interface Proxy : NSObject
    -(void)MissMethod;
    @end
    @implementation Proxy
    -(void)MissMethod
    {
    NSLog(@" >> MissMethod() called in Proxy.");
    }
    @end
    // Foo
    @interface Foo : NSObject
    -(void)Bar;
    @end
    @implementation Foo
    - (void)forwardInvocation:(NSInvocation *)anInvocation
    {
    SEL name = [anInvocation selector];
    NSLog(@" >> forwardInvocation for selector %@", NSStringFromSelector(name));
    Proxy * proxy = [[[Proxy alloc] init] autorelease];
    if ([proxy respondsToSelector:name]) {
    [anInvocation invokeWithTarget:proxy];
    }
    else {
    [super forwardInvocation:anInvocation];
    }
    }
    - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    return [Proxy instanceMethodSignatureForSelector:aSelector];
    }
    -(void)Bar
    {
    NSLog(@" >> Bar() in Foo.");
    }
    @end
    +

    运行测试代码,输出如下:

    +
    1
    2
    3
    >> Bar() in Foo.
    >> forwardInvocation for selector MissMethod
    >> MissMethod() called in Proxy.
    +

    如果我把动态方法决议部分代码也加入进来输出又是怎样呢?下面只列出了 Foo 的实现代码,其他代码不变动。

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    @implementation Foo
    +(BOOL)resolveInstanceMethod:(SEL)name
    {
    NSLog(@" >> Instance resolving %@", NSStringFromSelector(name));
    if (name == @selector(MissMethod)) {
    class_addMethod([self class], name, (IMP)dynamicMethodIMP, "v@:");
    return YES;
    }
    return [super resolveInstanceMethod:name];
    }
    +(BOOL)resolveClassMethod:(SEL)name
    {
    NSLog(@" >> Class resolving %@", NSStringFromSelector(name));
    return [super resolveClassMethod:name];
    }
    - (void)forwardInvocation:(NSInvocation *)anInvocation
    {
    SEL name = [anInvocation selector];
    NSLog(@" >> forwardInvocation for selector %@", NSStringFromSelector(name));
    Proxy * proxy = [[[Proxy alloc] init] autorelease];
    if ([proxy respondsToSelector:name]) {
    [anInvocation invokeWithTarget:proxy];
    }
    else {
    [super forwardInvocation:anInvocation];
    }
    }
    - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    return [Proxy instanceMethodSignatureForSelector:aSelector];
    }
    -(void)Bar
    {
    NSLog(@" >> Bar() in Foo.");
    }
    @end
    +

    此时,输出为:

    +
    1
    2
    3
    4
    >> Bar() in Foo.
    >> Instance resolving MissMethod
    >> dynamicMethodIMP called.
    >> Instance resolving _doZombieMe
    +

    注意到了没,消息转发没有进行!在前文中说过,消息转发只有在对象无法正常处理消息时才会调用,而在这里我在动态方法决议中为 selector 提供了实现,使得对象可以处理该消息,所以消息转发不会继续了。官方文档中说:

    +
    1
    If you implement resolveInstanceMethod: but want particular selectors to actually be forwarded via the forwarding mechanism, you return NO for those selectors.
    +

    文档里的说法其实并不准确,只有在 resolveInstanceMethod 的实现中没有真正为 selector 提供实现,并返回 NO 的情况下才会进入消息转发流程;否则绝不会进入消息转发流程,程序要么调用正确的动态方法,要么 crash。这也与前面的源码不太一致,我猜测在比上面源码的更高层次的地方,再次查找了 method list,如果提供了实现就能够找到该实现。

    +

    下面我把 resolveInstanceMethod 方法中为 selector 添加实现的那一行屏蔽了,消息转发就应该会进行:

    +
    1
    //class_addMethod([self class], name, (IMP)dynamicMethodIMP, "v@:");
    +

    再次编译运行,此时输出正如前面所推断的那样:

    +
    1
    2
    3
    4
    5
    6
    >> Bar() in Foo.
    >> Instance resolving MissMethod
    objc[1618]: +[Foo resolveInstanceMethod:MissMethod] returned YES, but no new implementation of -[Foo MissMethod] was found
    >> forwardInvocation for selector MissMethod
    >> MissMethod() called in Proxy.
    >> Instance resolving _doZombieMe
    +

    进行了消息转发!而且编译器很善意地提示(见前面源码剖析):哎呀,你不能欺骗我嘛,你说添加了实现(返回YES),其实还是没有呀!然后编译器就无奈地去看能不能消息转发了。当然如果把返回值修改为 NO 就不会有该警告出现,其他的输出不变。

    +

    总结

    从上面的示例演示可以看出,动态方法决议是先于消息转发的。

    +

    如果向一个 Objective C 对象发送它无法处理的消息(selector),那么编译器会按照如下次序进行处理:

    +

    1 首先看是否为该 selector 提供了动态方法决议机制,如果提供了则转到2;如果没有提供则转到 3;

    +
      +
    1. 如果动态方法决议真正为该selector 提供了实现,那么就调用该实现,完成消息发送流程,消息转发就不会进行了;如果没有提供,则转到 3;

      +
    2. +
    3. 其次看是否为该 selector 提供了消息转发机制,如果提供了消息了则进行消息转发,此时,无论消息转发是怎样实现的,程序均不会crash。(因为消息调用的控制权完全交给消息转发机制处理,即使消息转发并没有做任何事情,运行也不会有错误,编译器更不会有错误提示。);如果没提供消息转发机制,则转到 4;

      +
    4. +
    5. 运行报错:无法识别的 selector,程序 crash;

      +
    6. +
    + + + + +
    + +
    + +
    + +
    + +
    + +
    + +
    + +
    + + + + + + + + +
    + +
    +
    + + + + + + + + + + + +
    + + + + + + + +
    + + + +

    + +

    + + + +
    + + +
    + + + + + + +

    Objective-C Runtime的消息传递
    + +

    + + Read more » + +
    + + + +
    + +
    + +
    + +
    + +
    + +
    + +
    + +
    + + + + + + + + +
    + +
    +
    + + + + + + + + + + + +
    + + + + + + + +
    + + + +

    + +

    + + + +
    + + +
    + + + + + + +

    Runtime常用方法和一些应用

    + +
    + + Read more » + +
    + + + +
    + +
    + +
    + +
    + +
    + +
    + +
    + +
    + + + + + + + + +
    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - \ No newline at end of file + diff --git a/js/script.js b/js/script.js deleted file mode 100644 index 1e58767..0000000 --- a/js/script.js +++ /dev/null @@ -1,137 +0,0 @@ -(function($){ - // Search - var $searchWrap = $('#search-form-wrap'), - isSearchAnim = false, - searchAnimDuration = 200; - - var startSearchAnim = function(){ - isSearchAnim = true; - }; - - var stopSearchAnim = function(callback){ - setTimeout(function(){ - isSearchAnim = false; - callback && callback(); - }, searchAnimDuration); - }; - - $('#nav-search-btn').on('click', function(){ - if (isSearchAnim) return; - - startSearchAnim(); - $searchWrap.addClass('on'); - stopSearchAnim(function(){ - $('.search-form-input').focus(); - }); - }); - - $('.search-form-input').on('blur', function(){ - startSearchAnim(); - $searchWrap.removeClass('on'); - stopSearchAnim(); - }); - - // Share - $('body').on('click', function(){ - $('.article-share-box.on').removeClass('on'); - }).on('click', '.article-share-link', function(e){ - e.stopPropagation(); - - var $this = $(this), - url = $this.attr('data-url'), - encodedUrl = encodeURIComponent(url), - id = 'article-share-box-' + $this.attr('data-id'), - offset = $this.offset(); - - if ($('#' + id).length){ - var box = $('#' + id); - - if (box.hasClass('on')){ - box.removeClass('on'); - return; - } - } else { - var html = [ - '
    ', - '', - '
    ', - '', - '', - '', - '', - '
    ', - '
    ' - ].join(''); - - var box = $(html); - - $('body').append(box); - } - - $('.article-share-box.on').hide(); - - box.css({ - top: offset.top + 25, - left: offset.left - }).addClass('on'); - }).on('click', '.article-share-box', function(e){ - e.stopPropagation(); - }).on('click', '.article-share-box-input', function(){ - $(this).select(); - }).on('click', '.article-share-box-link', function(e){ - e.preventDefault(); - e.stopPropagation(); - - window.open(this.href, 'article-share-box-window-' + Date.now(), 'width=500,height=450'); - }); - - // Caption - $('.article-entry').each(function(i){ - $(this).find('img').each(function(){ - if ($(this).parent().hasClass('fancybox')) return; - - var alt = this.alt; - - if (alt) $(this).after('' + alt + ''); - - $(this).wrap(''); - }); - - $(this).find('.fancybox').each(function(){ - $(this).attr('rel', 'article' + i); - }); - }); - - if ($.fancybox){ - $('.fancybox').fancybox(); - } - - // Mobile nav - var $container = $('#container'), - isMobileNavAnim = false, - mobileNavAnimDuration = 200; - - var startMobileNavAnim = function(){ - isMobileNavAnim = true; - }; - - var stopMobileNavAnim = function(){ - setTimeout(function(){ - isMobileNavAnim = false; - }, mobileNavAnimDuration); - } - - $('#main-nav-toggle').on('click', function(){ - if (isMobileNavAnim) return; - - startMobileNavAnim(); - $container.toggleClass('mobile-nav-on'); - stopMobileNavAnim(); - }); - - $('#wrap').on('click', function(){ - if (isMobileNavAnim || !$container.hasClass('mobile-nav-on')) return; - - $container.removeClass('mobile-nav-on'); - }); -})(jQuery); \ No newline at end of file diff --git a/js/src/affix.js b/js/src/affix.js new file mode 100644 index 0000000..11a3d39 --- /dev/null +++ b/js/src/affix.js @@ -0,0 +1,162 @@ +/* ======================================================================== + * Bootstrap: affix.js v3.3.5 + * http://getbootstrap.com/javascript/#affix + * ======================================================================== + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // AFFIX CLASS DEFINITION + // ====================== + + var Affix = function (element, options) { + this.options = $.extend({}, Affix.DEFAULTS, options) + + this.$target = $(this.options.target) + .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this)) + .on('click.bs.affix.data-api', $.proxy(this.checkPositionWithEventLoop, this)) + + this.$element = $(element) + this.affixed = null + this.unpin = null + this.pinnedOffset = null + + this.checkPosition() + } + + Affix.VERSION = '3.3.5' + + Affix.RESET = 'affix affix-top affix-bottom' + + Affix.DEFAULTS = { + offset: 0, + target: window + } + + Affix.prototype.getState = function (scrollHeight, height, offsetTop, offsetBottom) { + var scrollTop = this.$target.scrollTop() + var position = this.$element.offset() + var targetHeight = this.$target.height() + + if (offsetTop != null && this.affixed == 'top') return scrollTop < offsetTop ? 'top' : false + + if (this.affixed == 'bottom') { + if (offsetTop != null) return (scrollTop + this.unpin <= position.top) ? false : 'bottom' + return (scrollTop + targetHeight <= scrollHeight - offsetBottom) ? false : 'bottom' + } + + var initializing = this.affixed == null + var colliderTop = initializing ? scrollTop : position.top + var colliderHeight = initializing ? targetHeight : height + + if (offsetTop != null && scrollTop <= offsetTop) return 'top' + if (offsetBottom != null && (colliderTop + colliderHeight >= scrollHeight - offsetBottom)) return 'bottom' + + return false + } + + Affix.prototype.getPinnedOffset = function () { + if (this.pinnedOffset) return this.pinnedOffset + this.$element.removeClass(Affix.RESET).addClass('affix') + var scrollTop = this.$target.scrollTop() + var position = this.$element.offset() + return (this.pinnedOffset = position.top - scrollTop) + } + + Affix.prototype.checkPositionWithEventLoop = function () { + setTimeout($.proxy(this.checkPosition, this), 1) + } + + Affix.prototype.checkPosition = function () { + if (!this.$element.is(':visible')) return + + var height = this.$element.height() + var offset = this.options.offset + var offsetTop = offset.top + var offsetBottom = offset.bottom + var scrollHeight = Math.max($(document).height(), $(document.body).height()) + + if (typeof offset != 'object') offsetBottom = offsetTop = offset + if (typeof offsetTop == 'function') offsetTop = offset.top(this.$element) + if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element) + + var affix = this.getState(scrollHeight, height, offsetTop, offsetBottom) + + if (this.affixed != affix) { + if (this.unpin != null) this.$element.css('top', '') + + var affixType = 'affix' + (affix ? '-' + affix : '') + var e = $.Event(affixType + '.bs.affix') + + this.$element.trigger(e) + + if (e.isDefaultPrevented()) return + + this.affixed = affix + this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null + + this.$element + .removeClass(Affix.RESET) + .addClass(affixType) + .trigger(affixType.replace('affix', 'affixed') + '.bs.affix') + } + + if (affix == 'bottom') { + this.$element.offset({ + top: scrollHeight - height - offsetBottom + }) + } + } + + + // AFFIX PLUGIN DEFINITION + // ======================= + + function Plugin(option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.affix') + var options = typeof option == 'object' && option + + if (!data) $this.data('bs.affix', (data = new Affix(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + var old = $.fn.affix + + $.fn.affix = Plugin + $.fn.affix.Constructor = Affix + + + // AFFIX NO CONFLICT + // ================= + + $.fn.affix.noConflict = function () { + $.fn.affix = old + return this + } + + + // AFFIX DATA-API + // ============== + + $(window).on('load', function () { + $('[data-spy="affix"]').each(function () { + var $spy = $(this) + var data = $spy.data() + + data.offset = data.offset || {} + + if (data.offsetBottom != null) data.offset.bottom = data.offsetBottom + if (data.offsetTop != null) data.offset.top = data.offsetTop + + Plugin.call($spy, data) + }) + }) + +}(jQuery); diff --git a/js/src/algolia-search.js b/js/src/algolia-search.js new file mode 100644 index 0000000..9787e2a --- /dev/null +++ b/js/src/algolia-search.js @@ -0,0 +1,115 @@ +/* global instantsearch: true */ +/*jshint camelcase: false */ + +$(document).ready(function () { + var algoliaSettings = CONFIG.algolia; + var isAlgoliaSettingsValid = algoliaSettings.applicationID && + algoliaSettings.apiKey && + algoliaSettings.indexName; + + if (!isAlgoliaSettingsValid) { + window.console.error('Algolia Settings are invalid.'); + return; + } + + var search = instantsearch({ + appId: algoliaSettings.applicationID, + apiKey: algoliaSettings.apiKey, + indexName: algoliaSettings.indexName, + searchFunction: function (helper) { + var searchInput = $('#algolia-search-input').find('input'); + + if (searchInput.val()) { + helper.search(); + } + } + }); + + // Registering Widgets + [ + instantsearch.widgets.searchBox({ + container: '#algolia-search-input', + placeholder: algoliaSettings.labels.input_placeholder + }), + + instantsearch.widgets.hits({ + container: '#algolia-hits', + hitsPerPage: algoliaSettings.hits.per_page || 10, + templates: { + item: function (data) { + var link = data.permalink ? data.permalink : (CONFIG.root + data.path); + return ( + '' + + data._highlightResult.title.value + + '' + ); + }, + empty: function (data) { + return ( + '
    ' + + algoliaSettings.labels.hits_empty.replace(/\$\{query}/, data.query) + + '
    ' + ); + } + }, + cssClasses: { + item: 'algolia-hit-item' + } + }), + + instantsearch.widgets.stats({ + container: '#algolia-stats', + templates: { + body: function (data) { + var stats = algoliaSettings.labels.hits_stats + .replace(/\$\{hits}/, data.nbHits) + .replace(/\$\{time}/, data.processingTimeMS); + return ( + stats + + '' + + ' Algolia' + + '' + + '
    ' + ); + } + } + }), + + instantsearch.widgets.pagination({ + container: '#algolia-pagination', + scrollTo: false, + showFirstLast: false, + labels: { + first: '', + last: '', + previous: '', + next: '' + }, + cssClasses: { + root: 'pagination', + item: 'pagination-item', + link: 'page-number', + active: 'current', + disabled: 'disabled-item' + } + }) + ].forEach(search.addWidget, search); + + search.start(); + + $('.popup-trigger').on('click', function(e) { + e.stopPropagation(); + $('body') + .append('
    ') + .css('overflow', 'hidden'); + $('.popup').toggle(); + $('#algolia-search-input').find('input').focus(); + }); + + $('.popup-btn-close').click(function(){ + $('.popup').hide(); + $('.algolia-pop-overlay').remove(); + $('body').css('overflow', ''); + }); + +}); diff --git a/js/src/bootstrap.js b/js/src/bootstrap.js new file mode 100644 index 0000000..a8f34c2 --- /dev/null +++ b/js/src/bootstrap.js @@ -0,0 +1,46 @@ +/* global NexT: true */ + +$(document).ready(function () { + + $(document).trigger('bootstrap:before'); + + NexT.utils.isMobile() && window.FastClick.attach(document.body); + + NexT.utils.lazyLoadPostsImages(); + + NexT.utils.registerESCKeyEvent(); + + NexT.utils.registerBackToTop(); + + $('.site-nav-toggle button').on('click', function () { + var $siteNav = $('.site-nav'); + var ON_CLASS_NAME = 'site-nav-on'; + var isSiteNavOn = $siteNav.hasClass(ON_CLASS_NAME); + var animateAction = isSiteNavOn ? 'slideUp' : 'slideDown'; + var animateCallback = isSiteNavOn ? 'removeClass' : 'addClass'; + + $siteNav.stop()[animateAction]('fast', function () { + $siteNav[animateCallback](ON_CLASS_NAME); + }); + }); + + + CONFIG.fancybox && NexT.utils.wrapImageWithFancyBox(); + NexT.utils.embeddedVideoTransformer(); + NexT.utils.addActiveClassToMenuItem(); + + + // Define Motion Sequence. + NexT.motion.integrator + .add(NexT.motion.middleWares.logo) + .add(NexT.motion.middleWares.menu) + .add(NexT.motion.middleWares.postList) + .add(NexT.motion.middleWares.sidebar); + + $(document).trigger('motion:before'); + + // Bootstrap Motion. + CONFIG.motion && NexT.motion.integrator.bootstrap(); + + $(document).trigger('bootstrap:after'); +}); diff --git a/js/src/exturl.js b/js/src/exturl.js new file mode 100644 index 0000000..b85062a --- /dev/null +++ b/js/src/exturl.js @@ -0,0 +1,15 @@ +/* global NexT: true */ + +$(document).ready(function () { + + // Create Base64 Object + var Base64={_keyStr:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",encode:function(e){var t="";var n,r,i,s,o,u,a;var f=0;e=Base64._utf8_encode(e);while(f>2;o=(n&3)<<4|r>>4;u=(r&15)<<2|i>>6;a=i&63;if(isNaN(r)){u=a=64}else if(isNaN(i)){a=64}t=t+this._keyStr.charAt(s)+this._keyStr.charAt(o)+this._keyStr.charAt(u)+this._keyStr.charAt(a)}return t},decode:function(e){var t="";var n,r,i;var s,o,u,a;var f=0;e=e.replace(/[^A-Za-z0-9+/=]/g,"");while(f>4;r=(o&15)<<4|u>>2;i=(u&3)<<6|a;t=t+String.fromCharCode(n);if(u!=64){t=t+String.fromCharCode(r)}if(a!=64){t=t+String.fromCharCode(i)}}t=Base64._utf8_decode(t);return t},_utf8_encode:function(e){e=e.replace(/rn/g,"n");var t="";for(var n=0;n127&&r<2048){t+=String.fromCharCode(r>>6|192);t+=String.fromCharCode(r&63|128)}else{t+=String.fromCharCode(r>>12|224);t+=String.fromCharCode(r>>6&63|128);t+=String.fromCharCode(r&63|128)}}return t},_utf8_decode:function(e){var t="";var n=0;var r=c1=c2=0;while(n191&&r<224){c2=e.charCodeAt(n+1);t+=String.fromCharCode((r&31)<<6|c2&63);n+=2}else{c2=e.charCodeAt(n+1);c3=e.charCodeAt(n+2);t+=String.fromCharCode((r&15)<<12|(c2&63)<<6|c3&63);n+=3}}return t}}; + + $('.exturl').on('click', function () { + var $exturl = $(this).attr('data-url'); + var $decurl = Base64.decode($exturl); + window.open($decurl, '_blank'); + return false; + }); + +}); diff --git a/js/src/hook-duoshuo.js b/js/src/hook-duoshuo.js new file mode 100644 index 0000000..ca64dbd --- /dev/null +++ b/js/src/hook-duoshuo.js @@ -0,0 +1,115 @@ +/* global DUOSHUO: true */ +/* jshint camelcase: false */ + +typeof DUOSHUO !== 'undefined' ? + hookTemplate() : + ($('#duoshuo-script')[0].onload = hookTemplate); + + +function hookTemplate() { + var post = DUOSHUO.templates.post; + + DUOSHUO.templates.post = function (e, t) { + var rs = post(e, t); + var agent = e.post.agent; + var userId = e.post.author.user_id; + var admin = ''; + + if (userId && (userId == CONFIG.duoshuo.userId)) { + admin = '' + CONFIG.duoshuo.author + ''; + } + + if (agent && /^Mozilla/.test(agent)) { + rs = rs.replace(/<\/div>

    /, admin + getAgentInfo(agent) + '

    '); + } + + return rs; + }; +} + +function getAgentInfo(string) { + $.ua.set(string); + + var UNKNOWN = 'Unknown'; + var sua = $.ua; + var separator = isMobile() ? '

    ' : ''; + var osName = sua.os.name || UNKNOWN; + var osVersion = sua.os.version || UNKNOWN; + var browserName = sua.browser.name || UNKNOWN; + var browserVersion = sua.browser.version || UNKNOWN; + var iconMapping = { + os: { + android : 'android', + linux : 'linux', + windows : 'windows', + ios : 'apple', + 'mac os': 'apple', + unknown : 'desktop' + }, + browser: { + chrome : 'chrome', + chromium : 'chrome', + firefox : 'firefox', + opera : 'opera', + safari : 'safari', + ie : 'internet-explorer', + wechat : 'wechat', + qq : 'qq', + unknown : 'globe' + } + }; + var osIcon = iconMapping.os[osName.toLowerCase()]; + var browserIcon = iconMapping.browser[getBrowserKey()]; + + return separator + + '' + + '' + + osName + ' ' + osVersion + + '' + separator + + '' + + '' + + browserName + ' ' + browserVersion + + ''; + + function getBrowserKey () { + var key = browserName.toLowerCase(); + + if (key.match(/WeChat/i)) { + return 'wechat'; + } + + if (key.match(/QQBrowser/i)) { + return 'qq'; + } + + return key; + } + + function isMobile() { + var userAgent = window.navigator.userAgent; + + var isiPad = userAgent.match(/iPad/i) !== null; + var mobileUA = [ + 'iphone', 'android', 'phone', 'mobile', + 'wap', 'netfront', 'x11', 'java', 'opera mobi', + 'opera mini', 'ucweb', 'windows ce', 'symbian', + 'symbianos', 'series', 'webos', 'sony', + 'blackberry', 'dopod', 'nokia', 'samsung', + 'palmsource', 'xda', 'pieplus', 'meizu', + 'midp' ,'cldc' , 'motorola', 'foma', + 'docomo', 'up.browser', 'up.link', 'blazer', + 'helio', 'hosin', 'huawei', 'novarra', + 'coolpad', 'webos', 'techfaith', 'palmsource', + 'alcatel', 'amoi', 'ktouch', 'nexian', + 'ericsson', 'philips', 'sagem', 'wellcom', + 'bunjalloo', 'maui', 'smartphone', 'iemobile', + 'spice', 'bird', 'zte-', 'longcos', + 'pantech', 'gionee', 'portalmmm', 'jig browser', + 'hiptop', 'benq', 'haier', '^lct', + '320x320', '240x320', '176x220' + ]; + var pattern = new RegExp(mobileUA.join('|'), 'i'); + + return !isiPad && userAgent.match(pattern); + } +} diff --git a/js/src/js.cookie.js b/js/src/js.cookie.js new file mode 100644 index 0000000..c6c3975 --- /dev/null +++ b/js/src/js.cookie.js @@ -0,0 +1,165 @@ +/*! + * JavaScript Cookie v2.1.4 + * https://github.com/js-cookie/js-cookie + * + * Copyright 2006, 2015 Klaus Hartl & Fagner Brack + * Released under the MIT license + */ +;(function (factory) { + var registeredInModuleLoader = false; + if (typeof define === 'function' && define.amd) { + define(factory); + registeredInModuleLoader = true; + } + if (typeof exports === 'object') { + module.exports = factory(); + registeredInModuleLoader = true; + } + if (!registeredInModuleLoader) { + var OldCookies = window.Cookies; + var api = window.Cookies = factory(); + api.noConflict = function () { + window.Cookies = OldCookies; + return api; + }; + } +}(function () { + function extend () { + var i = 0; + var result = {}; + for (; i < arguments.length; i++) { + var attributes = arguments[ i ]; + for (var key in attributes) { + result[key] = attributes[key]; + } + } + return result; + } + + function init (converter) { + function api (key, value, attributes) { + var result; + if (typeof document === 'undefined') { + return; + } + + // Write + + if (arguments.length > 1) { + attributes = extend({ + path: '/' + }, api.defaults, attributes); + + if (typeof attributes.expires === 'number') { + var expires = new Date(); + expires.setMilliseconds(expires.getMilliseconds() + attributes.expires * 864e+5); + attributes.expires = expires; + } + + // We're using "expires" because "max-age" is not supported by IE + attributes.expires = attributes.expires ? attributes.expires.toUTCString() : ''; + + try { + result = JSON.stringify(value); + if (/^[\{\[]/.test(result)) { + value = result; + } + } catch (e) {} + + if (!converter.write) { + value = encodeURIComponent(String(value)) + .replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g, decodeURIComponent); + } else { + value = converter.write(value, key); + } + + key = encodeURIComponent(String(key)); + key = key.replace(/%(23|24|26|2B|5E|60|7C)/g, decodeURIComponent); + key = key.replace(/[\(\)]/g, escape); + + var stringifiedAttributes = ''; + + for (var attributeName in attributes) { + if (!attributes[attributeName]) { + continue; + } + stringifiedAttributes += '; ' + attributeName; + if (attributes[attributeName] === true) { + continue; + } + stringifiedAttributes += '=' + attributes[attributeName]; + } + return (document.cookie = key + '=' + value + stringifiedAttributes); + } + + // Read + + if (!key) { + result = {}; + } + + // To prevent the for loop in the first place assign an empty array + // in case there are no cookies at all. Also prevents odd result when + // calling "get()" + var cookies = document.cookie ? document.cookie.split('; ') : []; + var rdecode = /(%[0-9A-Z]{2})+/g; + var i = 0; + + for (; i < cookies.length; i++) { + var parts = cookies[i].split('='); + var cookie = parts.slice(1).join('='); + + if (cookie.charAt(0) === '"') { + cookie = cookie.slice(1, -1); + } + + try { + var name = parts[0].replace(rdecode, decodeURIComponent); + cookie = converter.read ? + converter.read(cookie, name) : converter(cookie, name) || + cookie.replace(rdecode, decodeURIComponent); + + if (this.json) { + try { + cookie = JSON.parse(cookie); + } catch (e) {} + } + + if (key === name) { + result = cookie; + break; + } + + if (!key) { + result[name] = cookie; + } + } catch (e) {} + } + + return result; + } + + api.set = api; + api.get = function (key) { + return api.call(api, key); + }; + api.getJSON = function () { + return api.apply({ + json: true + }, [].slice.call(arguments)); + }; + api.defaults = {}; + + api.remove = function (key, attributes) { + api(key, '', extend(attributes, { + expires: -1 + })); + }; + + api.withConverter = init; + + return api; + } + + return init(function () {}); +})); diff --git a/js/src/motion.js b/js/src/motion.js new file mode 100644 index 0000000..cbfb824 --- /dev/null +++ b/js/src/motion.js @@ -0,0 +1,291 @@ +/* global NexT: true */ + +$(document).ready(function () { + NexT.motion = {}; + + var sidebarToggleLines = { + lines: [], + push: function (line) { + this.lines.push(line); + }, + init: function () { + this.lines.forEach(function (line) { + line.init(); + }); + }, + arrow: function () { + this.lines.forEach(function (line) { + line.arrow(); + }); + }, + close: function () { + this.lines.forEach(function (line) { + line.close(); + }); + } + }; + + function SidebarToggleLine(settings) { + this.el = $(settings.el); + this.status = $.extend({}, { + init: { + width: '100%', + opacity: 1, + left: 0, + rotateZ: 0, + top: 0 + } + }, settings.status); + } + + SidebarToggleLine.prototype.init = function () { + this.transform('init'); + }; + SidebarToggleLine.prototype.arrow = function () { + this.transform('arrow'); + }; + SidebarToggleLine.prototype.close = function () { + this.transform('close'); + }; + SidebarToggleLine.prototype.transform = function (status) { + this.el.velocity('stop').velocity(this.status[status]); + }; + + var sidebarToggleLine1st = new SidebarToggleLine({ + el: '.sidebar-toggle-line-first', + status: { + arrow: {width: '50%', rotateZ: '-45deg', top: '2px'}, + close: {width: '100%', rotateZ: '-45deg', top: '5px'} + } + }); + var sidebarToggleLine2nd = new SidebarToggleLine({ + el: '.sidebar-toggle-line-middle', + status: { + arrow: {width: '90%'}, + close: {opacity: 0} + } + }); + var sidebarToggleLine3rd = new SidebarToggleLine({ + el: '.sidebar-toggle-line-last', + status: { + arrow: {width: '50%', rotateZ: '45deg', top: '-2px'}, + close: {width: '100%', rotateZ: '45deg', top: '-5px'} + } + }); + + sidebarToggleLines.push(sidebarToggleLine1st); + sidebarToggleLines.push(sidebarToggleLine2nd); + sidebarToggleLines.push(sidebarToggleLine3rd); + + var SIDEBAR_WIDTH = '320px'; + var SIDEBAR_DISPLAY_DURATION = 200; + + var sidebarToggleMotion = { + toggleEl: $('.sidebar-toggle'), + sidebarEl: $('.sidebar'), + isSidebarVisible: false, + init: function () { + this.toggleEl.on('click', this.clickHandler.bind(this)); + this.toggleEl.on('mouseenter', this.mouseEnterHandler.bind(this)); + this.toggleEl.on('mouseleave', this.mouseLeaveHandler.bind(this)); + + $(document) + .on('sidebar.isShowing', function () { + NexT.utils.isDesktop() && $('body').velocity('stop').velocity( + {paddingRight: SIDEBAR_WIDTH}, + SIDEBAR_DISPLAY_DURATION + ); + }) + .on('sidebar.isHiding', function () { + }); + }, + clickHandler: function () { + this.isSidebarVisible ? this.hideSidebar() : this.showSidebar(); + this.isSidebarVisible = !this.isSidebarVisible; + }, + mouseEnterHandler: function () { + if (this.isSidebarVisible) { + return; + } + sidebarToggleLines.arrow(); + }, + mouseLeaveHandler: function () { + if (this.isSidebarVisible) { + return; + } + sidebarToggleLines.init(); + }, + showSidebar: function () { + var self = this; + + sidebarToggleLines.close(); + + this.sidebarEl.velocity('stop').velocity({ + width: SIDEBAR_WIDTH + }, { + display: 'block', + duration: SIDEBAR_DISPLAY_DURATION, + begin: function () { + $('.sidebar .motion-element').velocity( + 'transition.slideRightIn', + { + stagger: 50, + drag: true, + complete: function () { + self.sidebarEl.trigger('sidebar.motion.complete'); + } + } + ); + }, + complete: function () { + self.sidebarEl.addClass('sidebar-active'); + self.sidebarEl.trigger('sidebar.didShow'); + } + } + ); + + this.sidebarEl.trigger('sidebar.isShowing'); + }, + hideSidebar: function () { + NexT.utils.isDesktop() && $('body').velocity('stop').velocity({paddingRight: 0}); + this.sidebarEl.find('.motion-element').velocity('stop').css('display', 'none'); + this.sidebarEl.velocity('stop').velocity({width: 0}, {display: 'none'}); + + sidebarToggleLines.init(); + + this.sidebarEl.removeClass('sidebar-active'); + this.sidebarEl.trigger('sidebar.isHiding'); + + //在 post 页面下按下隐藏 sidebar 时如果当前选中的是“站点概览”,将 toc 去除 motion 效果 + //防止再次打开时会出现在“站点概览”下的 bug + if (!!$('.post-toc-wrap')) { + if ($('.site-overview').css('display') === 'block') { + $('.post-toc-wrap').removeClass('motion-element'); + } + } + } + }; + sidebarToggleMotion.init(); + + NexT.motion.integrator = { + queue: [], + cursor: -1, + add: function (fn) { + this.queue.push(fn); + return this; + }, + next: function () { + this.cursor++; + var fn = this.queue[this.cursor]; + $.isFunction(fn) && fn(NexT.motion.integrator); + }, + bootstrap: function () { + this.next(); + } + }; + + NexT.motion.middleWares = { + logo: function (integrator) { + var sequence = []; + var $brand = $('.brand'); + var $title = $('.site-title'); + var $subtitle = $('.site-subtitle'); + var $logoLineTop = $('.logo-line-before i'); + var $logoLineBottom = $('.logo-line-after i'); + + $brand.size() > 0 && sequence.push({ + e: $brand, + p: {opacity: 1}, + o: {duration: 200} + }); + + NexT.utils.isMist() && hasElement([$logoLineTop, $logoLineBottom]) && + sequence.push( + getMistLineSettings($logoLineTop, '100%'), + getMistLineSettings($logoLineBottom, '-100%') + ); + + hasElement($title) && sequence.push({ + e: $title, + p: {opacity: 1, top: 0}, + o: { duration: 200 } + }); + + hasElement($subtitle) && sequence.push({ + e: $subtitle, + p: {opacity: 1, top: 0}, + o: {duration: 200} + }); + + if (sequence.length > 0) { + sequence[sequence.length - 1].o.complete = function () { + integrator.next(); + }; + $.Velocity.RunSequence(sequence); + } else { + integrator.next(); + } + + + function getMistLineSettings (element, translateX) { + return { + e: $(element), + p: {translateX: translateX}, + o: { + duration: 500, + sequenceQueue: false + } + }; + } + + /** + * Check if $elements exist. + * @param {jQuery|Array} $elements + * @returns {boolean} + */ + function hasElement ($elements) { + $elements = Array.isArray($elements) ? $elements : [$elements]; + return $elements.every(function ($element) { + return $.isFunction($element.size) && $element.size() > 0; + }); + } + }, + + menu: function (integrator) { + $('.menu-item').velocity('transition.slideDownIn', { + display: null, + duration: 200, + complete: function () { + integrator.next(); + } + }); + }, + + postList: function (integrator) { + var $post = $('.post'); + var hasPost = $post.size() > 0; + + hasPost ? postMotion() : integrator.next(); + + function postMotion () { + var postMotionOptions = window.postMotionOptions || { + stagger: 100, + drag: true + }; + postMotionOptions.complete = function () { + integrator.next(); + }; + + $post.velocity('transition.slideDownIn', postMotionOptions); + } + }, + + sidebar: function (integrator) { + if (CONFIG.sidebar.display === 'always') { + NexT.utils.displaySidebar(); + } + integrator.next(); + } + }; + +}); diff --git a/js/src/post-details.js b/js/src/post-details.js new file mode 100644 index 0000000..dbdc41c --- /dev/null +++ b/js/src/post-details.js @@ -0,0 +1,147 @@ +/* global NexT: true */ + +$(document).ready(function () { + + initScrollSpy(); + NexT.utils.needAffix() && initAffix(); + initTOCDimension(); + + function initScrollSpy () { + var tocSelector = '.post-toc'; + var $tocElement = $(tocSelector); + var activeCurrentSelector = '.active-current'; + + $tocElement + .on('activate.bs.scrollspy', function () { + var $currentActiveElement = $(tocSelector + ' .active').last(); + + removeCurrentActiveClass(); + $currentActiveElement.addClass('active-current'); + }) + .on('clear.bs.scrollspy', removeCurrentActiveClass); + + $('body').scrollspy({ target: tocSelector }); + + function removeCurrentActiveClass () { + $(tocSelector + ' ' + activeCurrentSelector) + .removeClass(activeCurrentSelector.substring(1)); + } + } + + // Sidebar float + function initAffix () { + var headerHeight = $('.header-inner').height(); + var footerOffset = parseInt($('.main').css('padding-bottom'), 10); + + /*jshint camelcase: false */ + var sidebarTop = (CONFIG.sidebar.offset_float === 0) ? + headerHeight + CONFIG.sidebar.offset : + headerHeight; + /*jshint camelcase: true */ + + $('.sidebar-inner').affix({ + offset: { + top: sidebarTop, + bottom: footerOffset + } + }); + + $(document) + .on('affixed.bs.affix', function () { + updateTOCHeight(document.body.clientHeight - 100); + }); + } + + function initTOCDimension () { + var updateTOCHeightTimer; + + $(window).on('resize', function () { + updateTOCHeightTimer && clearTimeout(updateTOCHeightTimer); + + updateTOCHeightTimer = setTimeout(function () { + var tocWrapperHeight = document.body.clientHeight - 100; + + updateTOCHeight(tocWrapperHeight); + }, 0); + }); + + // Initialize TOC Height. + updateTOCHeight(document.body.clientHeight - 100); + + // Initialize TOC Width. + var scrollbarWidth = NexT.utils.getScrollbarWidth(); + $('.post-toc').css('width', 'calc(100% + ' + scrollbarWidth + 'px)'); + } + + function updateTOCHeight (height) { + height = height || 'auto'; + $('.post-toc').css('max-height', height); + } + +}); + +$(document).ready(function () { + var html = $('html'); + var TAB_ANIMATE_DURATION = 200; + var hasVelocity = $.isFunction(html.velocity); + + $('.sidebar-nav li').on('click', function () { + var item = $(this); + var activeTabClassName = 'sidebar-nav-active'; + var activePanelClassName = 'sidebar-panel-active'; + if (item.hasClass(activeTabClassName)) { + return; + } + + var currentTarget = $('.' + activePanelClassName); + var target = $('.' + item.data('target')); + + hasVelocity ? + currentTarget.velocity('transition.slideUpOut', TAB_ANIMATE_DURATION, function () { + target + .velocity('stop') + .velocity('transition.slideDownIn', TAB_ANIMATE_DURATION) + .addClass(activePanelClassName); + }) : + currentTarget.animate({ opacity: 0 }, TAB_ANIMATE_DURATION, function () { + currentTarget.hide(); + target + .stop() + .css({'opacity': 0, 'display': 'block'}) + .animate({ opacity: 1 }, TAB_ANIMATE_DURATION, function () { + currentTarget.removeClass(activePanelClassName); + target.addClass(activePanelClassName); + }); + }); + + item.siblings().removeClass(activeTabClassName); + item.addClass(activeTabClassName); + }); + + $('.post-toc a').on('click', function (e) { + e.preventDefault(); + var targetSelector = NexT.utils.escapeSelector(this.getAttribute('href')); + var offset = $(targetSelector).offset().top; + + hasVelocity ? + html.velocity('stop').velocity('scroll', { + offset: offset + 'px', + mobileHA: false + }) : + $('html, body').stop().animate({ + scrollTop: offset + }, 500); + }); + + // Expand sidebar on post detail page by default, when post has a toc. + var $tocContent = $('.post-toc-content'); + var isSidebarCouldDisplay = CONFIG.sidebar.display === 'post' || + CONFIG.sidebar.display === 'always'; + var hasTOC = $tocContent.length > 0 && $tocContent.html().trim().length > 0; + if (isSidebarCouldDisplay && hasTOC) { + CONFIG.motion ? + (NexT.motion.middleWares.sidebar = function () { + NexT.utils.displaySidebar(); + }) : NexT.utils.displaySidebar(); + } +}); diff --git a/js/src/schemes/pisces.js b/js/src/schemes/pisces.js new file mode 100644 index 0000000..d4125b6 --- /dev/null +++ b/js/src/schemes/pisces.js @@ -0,0 +1,17 @@ +$(document).ready(function () { + var $headerInner = $('.header-inner'); + var $sidebar = $('#sidebar'); + var getSidebarTop = function(){ + return $headerInner.height() + CONFIG.sidebar.offset; + }; + var setSidebarMarginTop = function(sidebarTop){ + return $sidebar.css({ 'margin-top': sidebarTop }); + }; + var mql = window.matchMedia('(min-width: 991px)'); + setSidebarMarginTop(getSidebarTop()).show(); + mql.addListener(function(e){ + if(e.matches){ + setSidebarMarginTop(getSidebarTop()); + } + }); +}); diff --git a/js/src/scroll-cookie.js b/js/src/scroll-cookie.js new file mode 100644 index 0000000..34ff200 --- /dev/null +++ b/js/src/scroll-cookie.js @@ -0,0 +1,23 @@ +$(document).ready(function() { + + // Set relative link path (without domain) + var rpath = window.location.href.replace(window.location.origin, ""); + + // Write position in cookie + var timeout; + $(window).on("scroll", function() { + clearTimeout(timeout); + timeout = setTimeout(function () { + Cookies.set("scroll-cookie", ($(window).scrollTop() + "|" + rpath), { expires: 365, path: '' }); + }, 250); + }); + + // Read position from cookie + if (Cookies.get("scroll-cookie") !== undefined) { + var cvalues = Cookies.get("scroll-cookie").split('|'); + if (cvalues[1] == rpath) { + $(window).scrollTop(cvalues[0]); + } + } + +}); diff --git a/js/src/scrollspy.js b/js/src/scrollspy.js new file mode 100644 index 0000000..f5c5c6c --- /dev/null +++ b/js/src/scrollspy.js @@ -0,0 +1,182 @@ +/* ======================================================================== +* Bootstrap: scrollspy.js v3.3.2 +* http://getbootstrap.com/javascript/#scrollspy +* ======================================================================== +* Copyright 2011-2015 Twitter, Inc. +* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) +* ======================================================================== */ + +/** + * Custom by iissnan + * + * - Add a `clear.bs.scrollspy` event. + * - Esacpe targets selector. + */ + + ++function ($) { + 'use strict'; + + // SCROLLSPY CLASS DEFINITION + // ========================== + + function ScrollSpy(element, options) { + this.$body = $(document.body) + this.$scrollElement = $(element).is(document.body) ? $(window) : $(element) + this.options = $.extend({}, ScrollSpy.DEFAULTS, options) + this.selector = (this.options.target || '') + ' .nav li > a' + this.offsets = [] + this.targets = [] + this.activeTarget = null + this.scrollHeight = 0 + + this.$scrollElement.on('scroll.bs.scrollspy', $.proxy(this.process, this)) + this.refresh() + this.process() + } + + ScrollSpy.VERSION = '3.3.2' + + ScrollSpy.DEFAULTS = { + offset: 10 + } + + ScrollSpy.prototype.getScrollHeight = function () { + return this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight) + } + + ScrollSpy.prototype.refresh = function () { + var that = this + var offsetMethod = 'offset' + var offsetBase = 0 + + this.offsets = [] + this.targets = [] + this.scrollHeight = this.getScrollHeight() + + if (!$.isWindow(this.$scrollElement[0])) { + offsetMethod = 'position' + offsetBase = this.$scrollElement.scrollTop() + } + + this.$body + .find(this.selector) + .map(function () { + var $el = $(this) + var href = $el.data('target') || $el.attr('href') + var $href = /^#./.test(href) && $(NexT.utils.escapeSelector(href)) // Need to escape selector. + + return ($href + && $href.length + && $href.is(':visible') + && [[$href[offsetMethod]().top + offsetBase, href]]) || null + }) + .sort(function (a, b) { return a[0] - b[0] }) + .each(function () { + that.offsets.push(this[0]) + that.targets.push(this[1]) + }) + + + } + + ScrollSpy.prototype.process = function () { + var scrollTop = this.$scrollElement.scrollTop() + this.options.offset + var scrollHeight = this.getScrollHeight() + var maxScroll = this.options.offset + scrollHeight - this.$scrollElement.height() + var offsets = this.offsets + var targets = this.targets + var activeTarget = this.activeTarget + var i + + if (this.scrollHeight != scrollHeight) { + this.refresh() + } + + if (scrollTop >= maxScroll) { + return activeTarget != (i = targets[targets.length - 1]) && this.activate(i) + } + + if (activeTarget && scrollTop < offsets[0]) { + $(this.selector).trigger('clear.bs.scrollspy') // Add a custom event. + this.activeTarget = null + return this.clear() + } + + for (i = offsets.length; i--;) { + activeTarget != targets[i] + && scrollTop >= offsets[i] + && (!offsets[i + 1] || scrollTop <= offsets[i + 1]) + && this.activate(targets[i]) + } + } + + ScrollSpy.prototype.activate = function (target) { + this.activeTarget = target + + this.clear() + + var selector = this.selector + + '[data-target="' + target + '"],' + + this.selector + '[href="' + target + '"]' + + var active = $(selector) + .parents('li') + .addClass('active') + + if (active.parent('.dropdown-menu').length) { + active = active + .closest('li.dropdown') + .addClass('active') + } + + active.trigger('activate.bs.scrollspy') + } + + ScrollSpy.prototype.clear = function () { + $(this.selector) + .parentsUntil(this.options.target, '.active') + .removeClass('active') + } + + + // SCROLLSPY PLUGIN DEFINITION + // =========================== + + function Plugin(option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.scrollspy') + var options = typeof option == 'object' && option + + if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + var old = $.fn.scrollspy + + $.fn.scrollspy = Plugin + $.fn.scrollspy.Constructor = ScrollSpy + + + // SCROLLSPY NO CONFLICT + // ===================== + + $.fn.scrollspy.noConflict = function () { + $.fn.scrollspy = old + return this + } + + + // SCROLLSPY DATA-API + // ================== + + $(window).on('load.bs.scrollspy.data-api', function () { + $('[data-spy="scroll"]').each(function () { + var $spy = $(this) + Plugin.call($spy, $spy.data()) + }) + }) + +}(jQuery); diff --git a/js/src/utils.js b/js/src/utils.js new file mode 100644 index 0000000..80bfde3 --- /dev/null +++ b/js/src/utils.js @@ -0,0 +1,232 @@ +/* global NexT: true */ + +NexT.utils = NexT.$u = { + /** + * Wrap images with fancybox support. + */ + wrapImageWithFancyBox: function () { + $('.content img') + .not('[hidden]') + .not('.group-picture img, .post-gallery img') + .each(function () { + var $image = $(this); + var imageTitle = $image.attr('title'); + var $imageWrapLink = $image.parent('a'); + + if ($imageWrapLink.size() < 1) { + $imageWrapLink = $image.wrap('').parent('a'); + } + + $imageWrapLink.addClass('fancybox fancybox.image'); + $imageWrapLink.attr('rel', 'group'); + + if (imageTitle) { + $imageWrapLink.append('

    ' + imageTitle + '

    '); + + //make sure img title tag will show correctly in fancybox + $imageWrapLink.attr('title', imageTitle); + } + }); + + $('.fancybox').fancybox({ + helpers: { + overlay: { + locked: false + } + } + }); + }, + + lazyLoadPostsImages: function () { + $('#posts').find('img').lazyload({ + placeholder: '/images/loading.gif', + effect: 'fadeIn' + }); + }, + + registerESCKeyEvent: function () { + $(document).on('keyup', function (event) { + var shouldDismissSearchPopup = event.which === 27 && + $('.search-popup').is(':visible'); + if (shouldDismissSearchPopup) { + $('.search-popup').hide(); + $('.search-popup-overlay').remove(); + $('body').css('overflow', ''); + } + }); + }, + + registerBackToTop: function () { + var THRESHOLD = 50; + var $top = $('.back-to-top'); + + $(window).on('scroll', function () { + $top.toggleClass('back-to-top-on', window.pageYOffset > THRESHOLD); + + var scrollTop = $(window).scrollTop(); + var docHeight = $('#content').height(); + var winHeight = $(window).height(); + var contentMath = (docHeight > winHeight) ? (docHeight - winHeight) : ($(document).height() - winHeight); + var scrollPercent = (scrollTop) / (contentMath); + var scrollPercentRounded = Math.round(scrollPercent*100); + var scrollPercentMaxed = (scrollPercentRounded > 100) ? 100 : scrollPercentRounded; + $('#scrollpercent>span').html(scrollPercentMaxed); + }); + + $top.on('click', function () { + $('body').velocity('scroll'); + }); + }, + + /** + * Transform embedded video to support responsive layout. + * @see http://toddmotto.com/fluid-and-responsive-youtube-and-vimeo-videos-with-fluidvids-js/ + */ + embeddedVideoTransformer: function () { + var $iframes = $('iframe'); + + // Supported Players. Extend this if you need more players. + var SUPPORTED_PLAYERS = [ + 'www.youtube.com', + 'player.vimeo.com', + 'player.youku.com', + 'music.163.com', + 'www.tudou.com' + ]; + var pattern = new RegExp( SUPPORTED_PLAYERS.join('|') ); + + $iframes.each(function () { + var iframe = this; + var $iframe = $(this); + var oldDimension = getDimension($iframe); + var newDimension; + + if (this.src.search(pattern) > 0) { + + // Calculate the video ratio based on the iframe's w/h dimensions + var videoRatio = getAspectRadio(oldDimension.width, oldDimension.height); + + // Replace the iframe's dimensions and position the iframe absolute + // This is the trick to emulate the video ratio + $iframe.width('100%').height('100%') + .css({ + position: 'absolute', + top: '0', + left: '0' + }); + + + // Wrap the iframe in a new
    which uses a dynamically fetched padding-top property + // based on the video's w/h dimensions + var wrap = document.createElement('div'); + wrap.className = 'fluid-vids'; + wrap.style.position = 'relative'; + wrap.style.marginBottom = '20px'; + wrap.style.width = '100%'; + wrap.style.paddingTop = videoRatio + '%'; + + // Add the iframe inside our newly created
    + var iframeParent = iframe.parentNode; + iframeParent.insertBefore(wrap, iframe); + wrap.appendChild(iframe); + + // Additional adjustments for 163 Music + if (this.src.search('music.163.com') > 0) { + newDimension = getDimension($iframe); + var shouldRecalculateAspect = newDimension.width > oldDimension.width || + newDimension.height < oldDimension.height; + + // 163 Music Player has a fixed height, so we need to reset the aspect radio + if (shouldRecalculateAspect) { + wrap.style.paddingTop = getAspectRadio(newDimension.width, oldDimension.height) + '%'; + } + } + } + }); + + function getDimension($element) { + return { + width: $element.width(), + height: $element.height() + }; + } + + function getAspectRadio(width, height) { + return height / width * 100; + } + }, + + /** + * Add `menu-item-active` class name to menu item + * via comparing location.path with menu item's href. + */ + addActiveClassToMenuItem: function () { + var path = window.location.pathname; + path = path === '/' ? path : path.substring(0, path.length - 1); + $('.menu-item a[href="' + path + '"]').parent().addClass('menu-item-active'); + }, + + hasMobileUA: function () { + var nav = window.navigator; + var ua = nav.userAgent; + var pa = /iPad|iPhone|Android|Opera Mini|BlackBerry|webOS|UCWEB|Blazer|PSP|IEMobile|Symbian/g; + + return pa.test(ua); + }, + + isTablet: function () { + return window.screen.width < 992 && window.screen.width > 767 && this.hasMobileUA(); + }, + + isMobile: function () { + return window.screen.width < 767 && this.hasMobileUA(); + }, + + isDesktop: function () { + return !this.isTablet() && !this.isMobile(); + }, + + /** + * Escape meta symbols in jQuery selectors. + * + * @param selector + * @returns {string|void|XML|*} + */ + escapeSelector: function (selector) { + return selector.replace(/[!"$%&'()*+,.\/:;<=>?@[\\\]^`{|}~]/g, '\\$&'); + }, + + displaySidebar: function () { + if (!this.isDesktop() || this.isPisces()) { + return; + } + $('.sidebar-toggle').trigger('click'); + }, + + isMist: function () { + return CONFIG.scheme === 'Mist'; + }, + + isPisces: function () { + return CONFIG.scheme === 'Pisces'; + }, + + getScrollbarWidth: function () { + var $div = $('
    ').addClass('scrollbar-measure').prependTo('body'); + var div = $div[0]; + var scrollbarWidth = div.offsetWidth - div.clientWidth; + + $div.remove(); + + return scrollbarWidth; + }, + + /** + * Affix behaviour for Sidebar. + * + * @returns {Boolean} + */ + needAffix: function () { + return this.isPisces(); + } +}; diff --git a/lib/Han/dist/font/han-space.otf b/lib/Han/dist/font/han-space.otf new file mode 100644 index 0000000000000000000000000000000000000000..845b1bc2898c9924eff3e1b0bd92b6178b4908db GIT binary patch literal 1748 zcmZ`)OKclO82)G1kGN``&?+b(sD?I36;R_Oa+~0&hq!4YhC@kkF92qeUb0|z9ojRX?nL_i=e6(>MK1@%-|TK4MP!_r`TlRd z|1q;Wn{1(wr5L?VGWBH6o#SioKJ_9|*d}75+1Zx|D}OKE117YEa$RZA8!Sx}`VRK> zs;X4z?)YuskI+w5L4+T$B=FDZ{nfgCwfhGkihP0LSY5f=pjb{2t{@GiuJ+u_Uq}1} zBDvNun|9}88btmA*14A!sXx2-;Q7nlqxVS;fhPLCbz)Y`KNfHQBxbfL-NGc3BrG)e z$U~hW+F+ZWx#@4fTl0r5BGeIsA+xX9OBALq=>tiFJ>}0#Lmj^gaaas~b`QLNSyT(=hq8Zj`HLVSa4td|q8#t|`_)BAFaWi&IH^^vQrPs#a5ntG}L`<&b&O zs%e)^S3Jo-rHOEPb(R^QKz1MM}-YB33lhu(@q16}7HdOI)#SOD`>Z62r9hvf5107%9{w zl`42@CK(tfz!>N&o^67eCLK(fs$dE<51%PIPkDGP(lXVcwP=76cnV3(X_})+sAhn6 z)hGX>FT&eGW?f=)x3raG!vLQJ92P)iMwOL&(P zl=Av84Z#|L-&q=`BKj0%aT%t8W>Dw;mF5sjMRajW95t(mFKXw=Bu>Z1xrmhvtOi}f zijH%sg6E!38EAW#8Z^GA?;~u(Q`+DaJO$O;iG{sz*fxG5UJ2*C8^wT^u*y(3u{-e% z@Ov@19o}0Hu1FDj1#=9yOK3#fo_%Y-QKk^im8c6p|NC-?c&FpZebm*t-}ybr=SK-5 zcRs{P|4(BSl87-D$8E}(mgT>#f*Emp$UVl~IN=9TJ%*XD$?quU@>g;I6jT-Mi}yWBBPSG}IXU5mz@KjRNS nk3U?Ae;Ieb5q~Z5YemEtoz3At5Wb}HA2{3-L=v8l=-cgIj2C6J literal 0 HcmV?d00001 diff --git a/lib/Han/dist/font/han-space.woff b/lib/Han/dist/font/han-space.woff new file mode 100644 index 0000000000000000000000000000000000000000..6ccc84f8ea3543926a1a1e78b5c50a56c0dc8025 GIT binary patch literal 1452 zcmZvbdown3C; zDMTc#%d#solk4eV249gK88qL!g0HhnV>uu^1?sonu2P(`XL%%S6 zupex9^*BO;EE6(EC>!9L}GI4oum04OcU4ntX^Bzo645JKhv zV|^$?!AcNMsG>Y4TLdyEXaiLJFq*HXsqm@c0_p8 zW!P^K^z4KpZrlN+*b=Y2$4(t?TIuqOySagFF9IA4^Go-XaQEbIb00KI(V`UGbsxct zZpq5aAKLp%XGSX$G;F4mQ^Vh&yk%>X*4k%wnkx|lW= zy+?{C&MsKZdHoq;Au@?dnCdw3!ur6PPq|^mIDwmjBrK|vFCf}W$uwCGHdAC{ zNhWF>s^3Qaoo~=0VD~)64CU8+rZ5|Pc}K5w^!bRxyrb_aiY4RCmA$<4(>`NeUq4~d ztLyI3_)B$vwQ#$lg&{VSC5hAu0Vc}`OKm+W<)1QLuT$)*I2la}(eUw)7o`%U&`PJX zRbn;Lz5a7yJb}%!E@hg`VrmCWi*v6rvzF3sTNYEqv< z0Tx7d07HqgjmSnU;sI(I*lgz5>+-4&=`*R!N@VgqpD$CPSXNr#E$oyQ`0f#<(oW@k zekA2d$6B)1kyK>Ed{SU~gDDmptc!b29wqmx0-biXPn&fZ40bX@7fnOs<`4^bS^O?E zir9}3oMGtF(P)D(m&USe)eDn+^g zFJqMZR(|yI&^{5D6UiA&`v&q~2DaBu(Fy%Klsxa11eLZtB0F!2J8wW)`O3}wdjwlOCr-N zFMNnRJxJ+g8?^u0^2Xd!n6>=*)CRlx=>hJQaI;`Vo#>mm!WGF(es#JfD^V=TagK1V z{AoG#*v+@`tksDqTINo%-`}nQ&iy3gy|+EC4)8K&TBfyn8V8DEa*IX-qocZ<4DMR| z+u>Qv>&Dci7x`k^_0BZ;%}mu@7VJM8WAK~Pm|y)w3vgW<(faO<3-a1okkh;-;7vk#y KIOv6tgZ}`kqe+wi literal 0 HcmV?d00001 diff --git a/lib/Han/dist/font/han.otf b/lib/Han/dist/font/han.otf new file mode 100644 index 0000000000000000000000000000000000000000..2ce2f46ca183a46f1b06517b1a2a8f96bcaab1b8 GIT binary patch literal 26416 zcmb@ud0P=(!C{3(=|4|9 zd0E@0dnu(YJAy2-FAkuHB07R2I_fyCj5qa_@jEZ6qt0)BzweLl3*2|tch0%z-gEA` z=ib+)D_1UM;Vcb{!^)UDe}2ZFZZ{RMSR=YwtUrCbV8u&wUcL3&CoER}8WxLnb?J%; zlXGuv{wIsYz7z5rHSezRb<(1N(8d;Np z9t+fGu-Hsf7Rx*0N6UsgX8n`JNreIy>q7lQE13A=yW79{*E2ue&;KD&&S9l6rSOAy zI8%O_!um7Dg8C2mKO`U}>ypoY77OTrCySHv3Hvb?mxZN-Qt~06m5kZ>K*vW+V=nVZ z{xVV+x`%%+y|8)-llS0&q@beFG!T zq}eQ-oiUtFVWqJj8BTLp6WP;;)2S>GyI?rYWx3e8;WUpWN*Obp=CfK;9ve>I$+{=y z!f^U72IidX%Dmi+^0JJD*=5;^^0M-b#f4>?3d&cmo|Cm;dEVx#l5EMO@e?Ob%4E2h znJ9jIxO`Qfq_PlRP1Y}4kpayTO$*AUo65^%OvU(V6EjP*i}T8*`Qu9pb0&{}a{QCi zr%axaG4Hum&t)xLw)nXvD*^S~a)~5wlN6vWE6D?rG9-EVd6Eoid4{wgFJo?bMUA9z zbAdFYGTA62zZ@!|CcnH)njw{B=jN4WONukHrBX>@P89m`Era?bE#q0!pk*ej6zD4km`s~|pt1xY=YWiiXFZt+(^*p>Hv`_A z$9fL1KL@>A3PQFRQcIu*|9c;n0jxZL&hRfI(Tn^9?HPcH;hPjV#?&yqtYFnZi$dU7 z0hDJX-ub1^89*7siC^Af@@0vZQYg=c@ySc{L;`)ufV>p`G4OI=1b*gR2E4)avJiNY z2N=c=k7bgA|KxL0L2y8J_NAOmIh}Go<=vF`Qm&``J!OcK!b#=uIiopiGO&!18Fyzq@W8YO>L<{X z9-Fjp@zI}t0vP`d$}xa)Hs!4ZluuH==fLtY423@oW#R+23ExcOPKqUs#t zr$PK)GO%EvQ?4fiO9=5N5dIEr#zOo(gds@(J~{b0Oh2HH%+j7%-XDROpA4)=A%^}k zf%O=~V3ja|^*D4L+GH@R@py=V4kmz}Vr2ksCNQ%y2F{b31_?@iy zDR%sHO8hh@o}NkzMsbE-qATv<|L~)aOT<`#yqurv>;Ih?#lL67_&e?yG4C$wo`rXf zVQmMvfPDn(PS)>$^V3=LL0jjus-Z`XtR1Watdp!aSZ}lb#`=+sv4!k=*-x;Su}j%1 zwx7M5eVP3+`-hZ~DMZTTlzAyHq%2SQQ_9Aa(iCZmGR2farL?E)PC1rxDdnS-uT%cT zxsyY39^gFAd4iM4nZtRWvy8Kvv!0X3DdALd6dWzb!f|paP9vwCvyHQp^D5^k=QQU6 z=L+Wo&c~cDINx&OoS#y8siRZxP8Fx#oBD9-#MEi2Pp3YYnw7dD_2ty;)PmIVR9R|m zsv)&L)sq@Zjiq*__NDGgeJ%BP>bcZ6Q?I68PyICYAE~!eX>JO41ouwv@3;i_kKD(& zQ@As^v$+eoOSmh!FLO6?^SLEl30KZlbN$?A?so1W?t9#S^6uh2&YQ$r&Xe$Jcp9FW z=ivEyQC=HwC+~IMCEj)3SG?Q&QG7A~5&jJRLjF?zW`5P&<#U%a)=F7UWkvR;ysEOo zi4*5c%a%yWs~K~-BrjiDTAuswe8T?tbwO3duXDNO)n$;+FO*bDrR8OLn+gic@+#pU z7(%(fD#$Odl1K}FRUj!W+gy-clAnOTDX&bLC&|nGxsV~^=d!8_Y4)aKz`>vzPF9pu zRYFN=VOcUR&n?U^%#&=Alvh?}Z(`nLFy&-R^5kG76@Uo^t%r+#n=38M{iUj;y!w|+ z;?-mc6ei%;6qe=YRb)$~Ksy7CvAzCXmtD5`f2{;COxJ#H3rK;_nKOPDz`W#YtSG$|QPPDW4Umctk^Be1EwG$&a$FA+UCJ-={sl_W1Q>nf_s zHc6|p8G|*ESLDI;E6kM^BywQP0&_~i*o7G>16cpgmw-wAOAcn;uX56YDi|KgFV)pB zT))a?!xZ}^TUuTPv#Ib`u=8MG0Yu^CsncgCqd818e?HSuh?tH-#B>y*Daq)GWb|Y* znwpHJC8O!dXht$hz??syfjMQ;MCJvEm=_>oUVw;s0V3uFh?o~38h&AJGRN=|3ZF|x z^Aph|hQKM4CNTs;#1IG(Lm)&9fee3O&-W+y??G*fNzk*Cpl2sR&rX7#odi8Q33~Q0=ww%BC%ZB`*_Am-d~=fc<|OgW zN#dK6#5X62Z%z{590uPL^X5*hnm=*k)JciwlZoey#B)CLoCYORCc*p6Gnt;6NKY%= zAcIL*xGB4&1oUKfPPq&eWoc3qkI$E6Z~B#tjF;yBCRbhw`LgVig8vR9QCIwb)K&Z+ zb<+P{x8cdD(|;EKn*XNYn1$ru4gQOEWa@!o6X6HZw-zvon61o&THcv|l%7C}nDg zDQ4(TW)uAYMDzbQKf-_PzQHUqv%#uiTe)Dxu$>r7$6^OVtbWGSSp-{9X2ZLRrDcU! zyTD2F8C%EJvoECFpHh(0n{o<_mD`*#oRu6Er-gHXbB=Q@l>-LHlVDIB0K?&V?rGjr zyrsNsFawOdPTpzW*ZfreJ^aV{^Z4`m&-1hR1^j0ICH@fh0G5sEu}*9o_Sy*Uh|Ceb z5ntl<_zxrVM_wNF@Ti7S-;Lfj`rEYIcMx}cbQgQf9|RBHz3Og{@YAtt$Nu;`ZTjSK zI#IEB@;#I8QT^UWJV%s}lQU-hf%gaM-uv$@yYHp@pZp{1f%_gf^>$8r}Iyvj}ryhH%SWmy6b+eBqFXPd|;k+|u@lXajDonJ9d-!Q| zR$9C{jSe#Z`&iyCe#|*8Xg$uaNFG; zk=yFD*a=gE-cqM4Elb~+vt;!%i)!n%8l!GpK~`JwekYcOmZ6<&^gX)DLEp!p71~se zTA#|V=#cI${aaRgP#4uTYY$4(^-;>~7P}hk4R+G$vUs#Ui$m*IHEnz~eM?8~zBOkx zK}|sI!?Jdj7Z!@rKEu)6-JI7C3A6dT?R}x{_E0FjyC>AYSLCgC+gyZccg^;a&eE>U zp&UDw?d6|0ytX<^WU4pYEQDdn>a|O37{GXaHwTq?g?so*?5htN&R{l2z0)N+_u7&3 z9>Tkamt!laEh#Uls3|n%U^Y{|Q7_sU+T2}2gloGceYLx6&VZ5Gbh`j_`RGCwGt znYjg~Y$?j=XCFlQ05Ast_S5;iG&E^&4Ju-zT2#b|PZ_Kh#$r@Qx2RjwE{hQ{nS?46 zmu=C=WTZ@{m6VCf{99r&LKf@Lc8j~){jnIyfF;pW>`Uk=4tfl26uz-2*0SjQx$`xR zSy|7Yua=!(v^Xm&=cdt%TV#V{PigT;T}VmLN}gI(t5k=TK@zPW`jMA^qJBUGjbgI6 zu@wxAJbD$o_Ec=aGo?;prb(f{{#nJ*eV?S9e-eX zeZFYu$M^8sVJJ#oBoK;_Y2ki0n$*WZlcGYKm5W~Mr-SGp1;B`91Idb&Xqga&2Ivra zreNri%h5mmKUBCf2~D^;XIp|6&TD!tWF6`_nY>s!SK`}+?76BmDlzmAj~ zw4)iX{Tj!tCY#A5Qu@^~ErFh&!cEKg3U|h*aN^UNan;wjLF%jNRHKDc(&-sv>BrGD zu1BMFYQ+|_&1NDQ05*foY)Jsn5YR3GzySczBy>&qA>JDDM@&uQ%uO0f;lk`Dv)v-r zXw3#4iL%Cih;w6;$;bBcoKbhc z|pj5dZksR1mFHlbp~qFM23 znvK|FK1M9TGQj{6p?8IE;YN|pp>yd71r^pcid~L+yMt_XghHNn%nm~67WphblaElx zYP?c27ROWH!cFjs7G4R;8uhJ?R%bXo+}I^*lXn-JEcGDUX>@-4%6@kHO`LxJRn&(n zU}hvrko6|M9#znNuQDa{qpz~tKgD0AD^TzHp9_%nQyg7ePxsRB)=h49)!E}h1sNqQj{{f>79vEQWG2|(qS*h3t&n=@;$TzHAzJwNgCX_U>T z7o#kWZSb@ZWz$)7cB0%2nt=Y~8xF1cal<1xV3~y6Y+7=ZLq9b*Nr>F5Xg5Etk6H4D zTGC!X^U!p(5Y6hqZ{MW9JcJJ}Oohb4!JE8a>VV3R2XAtIoE2Xu9Ik|D`XM~-OGOLm z8}vdxy>Kj~;6;9#3rF)l$M3!&_~yr1gQ-F^@AeIP9)HM}O3xd-u?-h|hQ3UF10V8@ zMf2d*dHl2r{9}}Q2&ZqNFQrgU&x3aW)I7f6v%#D3*lUTl!@yr?!-3lA8k~WB1Rn&N zj{r!BX9?ecE}(frdL9BaX~Qki!q0Jr64Wb13xSe_{J4vrCB<*w7@KS;_$=-lT=+8* zrU4L?g#H`2Qs@@_r2|Jd0eA)Agf{zMV^A&>(hJcIw2%)R_(l!%(O;_ZG}PSzk6tv- zh6|2@aD5qH2c_LO8guK)xwkLk9JFU}&5Jn7Ux1?*m*CmLtU8?cB)%E{>u}jq_z)*P z_us`ssqr@-#p9`0@YwD3@8VVX&Dc$Zp?hQOPjGkRx>o-WSBr#r9#rhB-5(!$6^S( zis#4B+;0KkHMD~FcHr|iJdq_L07dS;#D(O+c?m*Jn&7*lpdm^HgZ_Bju^ zrr|?7;!_^Q5fwiw?1?=NFnj0&!dS_btjG9i0en>q&1u2~U)cp{<^MvUbz}jyn+&$>)crW>(BUW&9}srLCQm!Z%NklI)Id*4zRKdEn-2+#A+3cpaAH>M z>#I1r7qA_EgBiOs_|F|o%pAe{EC1cQ!`(yMVD9V(p1UFFZ*mN!ApV|{__T9Z5^R6yD>Me!zI-b1 z@BN-SoDXAKjBkN4oj*Lj3m{!_4!AoX`up%ZfSyhV{MYD|cbI{00X}xb_X;DiSuhJC z^lo8Hc`<7;gX~_!--h`2BCIEg@5n`5aJgM@<%6|28leB+!v)LliQ>@Fq1Ew+g`04} zwio~(Jv=o*ho2gT9g9ta(aaj!%*Y4>^>6rs7^{29zS>e){$Ft&Y^qG33hcRRSDCb2gg1p+XmBOsP|`u0^Cb^ z5h_jyvz8ajzThF-G+glH+q4VSpTU_aS zpU8TOk0NN05ddH=>NqK!f9{e$rtQeuQY_=sC+I<;@?4}RR`OofQyLln7X2bf2&e@* z?eB5hDGt=%HVgj>)kOZYw-S|_KyWI!7_9O;215MsiuA5J zzmiZhY+Scy-HR_TfBEI&O$w~mU@+NWTV->%ABb+hMBLc>_R+Ivoz8T( z`N|7NS8v-iu3%eh4cI-NK-(d0pDadh?tgLj%vTQ_-FIg9TRSgx?Ft96Am#D7MO0n1 zvW;kyRtHpKjohHBAQjpy1)Uvc!a=j*-w0RX1L1Sgn~hl0CvW(6O~%tS=iFDce=oX^~c^7)U(SSB2kCIWj+@}z0)E0x1 zl;~C&W*RZm%oi+c#l>5wn4GNc)V_LNWJ7bgdo8_&HlojQjY4US7#Mm)^C#5q2JDo5 ztD6#0>cEyD5!xd4RKs}Rjo9&O=t9PzYUnTDR9;6{zZTpOTta8SOwyZ8TGFMk)#w$K z3pdSLF%gqXbt;p{;MGReL|rs!^ohMemoG{R-slVNqF(i5ZoR``66Hu1t(i=$nY?D< znhlsrXE(dV!H)3O0rK$9L&pzZ#?E}W_4Rg9WJ`Z#l=!TX+k$u>PzS~BL4!K0yDl_b>Ri;?|;IAtvz!)e-T)-u|}_l5c!^7zuWusje1x#OufW zVVBP#3e+`AyNGUSO{fmoZZW9HYD1YR-%JY>^c__+F2RgdbruVZfzt!S}G4IJ7F! zT=|r|dkGoMds@3mT+UM)Od6BFE~X$Av5*eLBk1rnkuiUlr_XiDpT3s9>y?Qcmtj?< znre;6;8RECggh3~dc^KVPjD-V*hkPEdl1pnnwL%~-CBnUs|<$fLSm2G>2;AF$`J^Q z-dlQ+9({tKB(-j{*vz-M43wH^FKR7mF3DCct$9j@RZLi|uDgLdy_7o|Y$ehI*X~6lSp+0fMYgDgSFWK@8DS4)RMagEYproj#NUW-KQH7+xOy#mL z3<;?_WkhdztkNgP>fDquEIxYi@YTI!|G8}+cO!1_NN_t9!F-g<>w*r2%bST89r8oBoPMV_ zLdK}m&0lp^Eh?D1?&&{GT{D06D$JlW8!Vy=c!SU7j}Yjd8$X~&uA)**u&f7Rmm}Tc zh|Q~!iRRZmC7DVHT#~7kE2R=lE|+R0Vx`>Sk&>kzuGMC<*hovDwoO8`Ne$p%Yl>q-RHys9h2+kf>FqR>Cr|cG8x~G`Tsw%EZ-}oL;xPiP}cCo@+VS(u09W z0@#2)qzDs&jbTNtw@#ckY489W$&Vw$aZY@q65qPIcTxXB9335N#2btH))3uLF!0oA zJm7OtZnAm1`|OLC=(`Y+UWBJTbUi-p{P&m5?~nO@@WhbsGV*;7+nm(F457(lF)`u< zu9s*~>lJ&c24|2Ie7Ze+KKNMxqf~CCN~EciROS$s#nm#U7Sm`8(ME3cQP?x~h_vSJ8PH}rcC%2I+HA|$=6IIWbt<2wml}W2qGI3pv%P%2a@;ZlE zY%*9Yw~<|y&9L5JDjx%?wJq4$PTu_JIJ%=9J!x-rg(+BNf=v5I!W|IxQD zG*Z01&t~l>E$v~e3*^ERq%D?LL?KUfP&5HqdHvq;4{ zt-V1@I!xvUt2izG<-2UueVsFS1?H{hsk%z~ezKB&m`Y=g>qAa8M>4LSG9vmRdG$neYeSLjLcAn|E+WH07_C?_O+affr4?Ph>lU!IZWV1v` z%H^UceNY)8BPx|w&8$3w|6-#nZ=r#U9Mn5_&qugPL$>4xH@gZjYNh*0dZeh#A~DJd zi^irih}4uSRzoOSqPn2i<8`<^WWd+xZ}T7PxU}=bBbE%~EZu6%SZ1k#rXFPwd~U&@ zh61JeC!9{D7mA+cFDsf~G_wfPl-C$_p#H<%BpTp1+anH&a0MJ*rziv>9U>YFDqxjm z459cKbn5cl_(VZ$kQh`8HF|BeiBzuNFmLW-nBeH#$5t%fREDVy2AxJ!s%%hpWU>|n$>J>lADMKkGBYn&RfT4%Ew zNx=<`ZjE+Q9X(QYuX3^+({Cs;SBdMC4p%jqHv6LK${3_Njh;P&HtiEsAZh%jP^mX+ zEUsE=3rVeWt=}M8V9T{?2#eNgw2IV0RYwh>4f{<_vCGGZY}Eal_nIH<7TZ&n1(p}- z`>WFp&u%iC7#CTCfi&2;AnHZ~rH!e{s?KIjP%MyldAS4VcW8Vgnk)XBm1}MafJk(@ zf``|U0ky`h6IYrmj4MquP2(zT#g;r%1KOA#`0&r}*Th}+wyoPlNBD>QhntTQo`@sh z5&1Qtsz!oRC|$L%3Ru9AX9UC!X@gWI%G75mULg#M63t4>6hpcL&2@k6>A;-92CzQB zcGwanqLON#O00unvN|;GYLY7U(4*~iUXC%_uu+d$j3yg+4-MXknKZ;Kuf8ohX5S98 z5FGg)kI1X@D=0!x;g>62%+fOc$Eoc2l{YwpX@k*^aJ`ajs8*Mi<WFTS^d2Ryy>{i&Tc5_dBGI4+3wyj?k0_!I%fevODtsF8X<9C<)frSK(jqO} zuximHn)BczbjnOjRjb!qM4+C0jpVtm)7ww%YHjR@b+$PTPNT!%Q9EC@Pq$CEt}@9m zi^8hbi43qjs|j_GGI+(YaNDkK>mKv#r1^;T@FCGwdy~V*bO%(wR~wK=2vuP3-rWaw z93JNjdVL-jV{JoSP#ctoh=5!LUDz>ur#C8c+1wTnVe#7B zPLbWy8r(}zd#Mf|1-1gCe!aRt4GgeC?K6lCTC-kFs&w;p^qpGFH2y`aRGg-ID}MeG z8);6*r(fnE)!;oa`Rgi8jye#I;3m)7l_L62Hu^5xYQp*oSLf3-0uviU2A|m1)ZpqO zgCBk4MkB;c5uGAP%0mIIUmOTfu^<_YxtkhAZPvHU2q(mp#Zwp3PADzTx+q*+QnsGzx^@ar(YTIrIDO)(_D`B1Aeq z^mGyqitFHcc6x$uldb5E4+6WzT><4fQZuxUTdY;e2|9+5(9Cbo-MVqxOMTCeQ~3OP zDu{bS&QMs?BH8}(e&WFL&26AI(Z+Ys*0YW8kBQ&?2JDHx8B`5!6oP+SqX1)jBmS6W zhG8LLmRRH#HLP?told0m$U{;>8V=Thw)RpnFWC-W#OdJBvmbf?ttdcR_jkcSykt=R z5w4Y!S$x4aFTy-rM?9l@PLrj=EXBpPVpuQD2D3*Ot|hBF8Z~~gE8z4rlDorigl~qd zs&vhBnzh<3n5oX9H;asJJ*6SEl+WZ5JNylfMzY<#+jG)`c~0(hHYawjYIT`pBf0X4 z7oM532veyHIuo6I|w&iPg0>n~J0#R&uS01zc_L zMoD{=D;Q`*cW@&=eCmBiysh14Z6sT5Tpuik-nyWqiEOHn!&+_9TZ|e~X~@?v)6@5> z(xWKV(dlgR_{O;0m}}Ldx?oL*l&I`zstbr6K9?^{QvPk>qfO|Jy=cr1G~fm zrZrrZrzQluADHG#@w8=c#iQTgDEKa#^|4^TAdVi3$AxNxSr413W(6tjW;DHza)5z$ zIQl^trG&loed!LFrnb`bylIszClAZdm9KqKG{1An(N)B{qZcaQ7r*o8#(@*$iT>_^ z0a3FuRISsPbQHHGxW*(mZZW-tr~Tn_e9pz5 zOJh*@T{Q9X^JfIN5D~8c;}kZ9L3O*Ftm$Y16UOg%cqp>f5B(rwj+yC>0&R`VI?uFH zmY0VW=P5U?6D?|Ad3Zgs@#y)gcf@bM5$--lp6u=J+aU^oDWp~#R4QWCvgfwU5YwaP zUifr(a9evj+1{}=xLxe=TTB5`7xcllyEE9>M>e2mkf`aVf3IU)Kd;H>ro1|;CQJsD zb)b07daI?5)L5!aB}PmTr=KggqZDq;(dZ5nE@y)iHU(22ya#RjYHD#9#@azRUfvdA@OR(FJ6?xa5@JJ7huM z2=j5l7w!H5{{i21{1v=1QhU?#5B$@}_0ToSKGU>7^Acv1SrlrK+G+GTJ>Ia7=sFPn z$c4sWo@0j``@yEOSzTnv#tnL0lusX2M9H8^?a_z@w+wX_lY%VQml%sodRuyw@4DtX zWWT)FcaGde%acoVe4&xq$ zSgtkUv-xT96PLZ<5{rC*GH#)fe;3FHU7*!WMytg{3gYwep74pL4`Y%=1+zC!Uz3^r zQb{>xGSxHtRUR?w)GA4^z|Ly@#oh4Ek{~TVNExWKZDcaigaJQx6{+*X>&Ka zDNG;-8y{9|a9&B;37tph(YoX~eU$#YkmgiMaOWb!3yQ^9TKwDVY=jN=a^k-q94}O> z)5&*(mx**1z*QK zl+zF9qK;AoiK5Ordu0ihHe(PD(DUQpaN=cyD}>MDfx5^g-0va1L1!o`imJNGb`r&X zo3^d(#$dkz=ccA;aqkkM1UH+@@qj6$1dMxW!~_)DF~=s_k8dR_L#jx1<{r+}1z%=WXwYe3G z$%-YV%Zpa))fz>ue0le}=KLTQ&M))GV6m{k{>tjLkgr#q-SpP#f(^MFbFyDryI|dn zS1_Z&Y_W+g_6D0v+|=QX^pU5!j`toNII?U1&Ve1D&Aqzl^oy807S+OT(d7w6%x(H! zvaYALMG;)JJ8SoxT?gMd^7(O;MuF%>U=!(bMLI>4CX%=wpk#bX@lmJ8pml?(kN#b7 zbnwo>`-MS|UTL!Ftaapiyiomo?IX%ZRI_x8t(ewkGV4Xw2CK_LbjUiDU24o|QtM39+yEc8X(^PF^TmoHLPJ zb>FI)tCkrw>5SFb;DH%Ryw-JK&;Db3j_-J*_ie2ELU>nD6xKwmmkW)ciF9^0?e0B+MLNArK9P+w`wbr05$!@t|JG~~r#(5?IrPx?W6&dm1%en{ z##xrw+PO=)PE|vVOjKsbQLh1KfaaCj_3{mvrpg4euJEZ~#%iODrkL0jb$U9<9{-yZ zVuL>yv9E!d-sH2Glv+u30a^I$l82w5M`N%cAMV|^V_?s~-rcA7Ukmj_TAQMb``7Og z1vHJacA{OT3~0n!jajEAYYkaynybL1^rA;KTCq&yjfA6@d(qvbr`_A+r7%y}>34zX z1uMZ*5erGGK>oqK^)4EGqxI^Txa{Hz@c#`A9*#dM3+eDaM+z1-|iT9*9t^Z>-x@XY9iRTVZNO+8kbb0b@vig2u2hPr3f_rkxY4Qp(e-rV470Ji!_ntKu zgT>{I`WoAb?>@bZ9&SP}xNmxn`XZRW$>q0;zy~b>H<_f$Cl{lNelYP(T8m5TSCZ}u zM+w}cQSsLVHn)Lk)3#rGL41n$`hI)E0NLw__=6$}7T*97RLH?<)F>CteiL64?W zjSq-H_itsRMS~A<2Jykw!l&_f*IZlr!TfRMFIQw&YpiS(CvN*qOA`qT7WzQt(M!>%BpYJ(d;v51}$yI>U! zkWEyFcf0fJCd3aTp$`M^iY!8^!j!=+ro0Z1i;OgRx9%08ZvH9P4k}DAEOWu~6D@_2 zDwX)E#WIIf?IWoQcWHr${)|8L>~gL}QEO9+4F-qHKw3REUr=O5H@UHfu+v94T@7#p zEeIY_*zieZUf_9L)Q3jCZU4&{bk|^nQ3iv{gqsXp!6m7=#-g^+zptf*N_tccRyXG* z<7Tmur?wi6I+4X`^caYWzBYAG+~8?&Qe^G~29JiwF!mw}F5YWNtM@X~9eHvNyO%pCd#?qb=>t-Hm;*BdwQOKMEe8wo)Ms z?jSMFOm(CJyyshL{2Fn!d69~1Sf6Jp61Sa&t&gYO-Q)^l{uUQ#4m;m#@Tn-mckQg} zfcRCO`SD};XDDF@fy z7On@Q+#8|7AVF<@g$l@W1eU6nc;FZFe@i z0Dlzxu7Kmai=IAllbvdCIQ*V^zc#1|7sV>PSOd&Py;v=0K+zKm=%cb>ugAC7JI>T#bQuV6Etjqr6qn44$wh3Xq&a=vzU z3`!Z?KXl_A!O{4)@vA}ypPpXL6~yN1H=3)hS{oRwmT?w~6^t;<;52)zM8Fs{IO@1M zyT+j=Hd_l#C4?RpX4T7z<<)B|bIV>X&#S1Yk*90)T$`;PrU>|poiG#a4!hk+!WFS# zcUxcoxSrmQ9kIPF2O3X=F9uF{54rZ*!{82c`9kRqkIiFpU!~H!oG08jydU{4xDGb# zY)B7!?F|mn<>vbMhM*NZ%xdpA86|VcZBk1*{kYT@bU5s8yKh|3LK!KdE>;~a3vQv( zomxW!vkk4c*+`?&rgLe+h3PJ}yVj!y6U3_w)P~h?;Vtd&=#F>LiOcNx(`Qf@VsYX= zrO@c&swrcrN#uVWk5M~uxHD)o5am)?tz4{AJ3LAfJ&yQ7BgNe<*&JJU3NH$jwO0~U zT}T%(xZ#eRQ-{d|LEUUTd0Jk8cj9T2&!RDB_6>VI(8AN`{x<|apxYiHI3!GFGgeop zGRnn8rJenL2L=B87}W??Dn(gL6bVM8!YRSv=AqUi3L~Bnt`s+z8Zb%@E`?KgA%p(! z_;&FnUZXK$4%x531GFma{0 z?uR3pmZZBsAohA3ZV&1AH2OQJBW;&<+&GG*Z90$cJ`VR!nL{MB4;J>%m3ZRVXdxa? zxvdvk0s(74yuCZn*1iwl(3&IOkS*OLB@MMx{=qH6jd+wfXX;(LeNpdor}36x#pUh$+33TIoWZjA^TIBC zJ-$(+w^Up8mT`JpmWFoa*bh5)ufW^-e}=a4Bqd&Hun{hq!+J)zFR5 zr@>RcbOzub&mqw;Otj<-y88@g@FhxEWUuJz7oEq?;&P)(T}N1KM!m&WZA!P9wQz?0 zQ2a6Be)lO~vxD1(uc$MYtMDBsI=AQimY7U6{cIVKvu6d~?(g^S|2H|gKwdE9Xu|A# zSF5A5SLFGe9(iu|T5MBw_Yh*P=r5ke&;JXX^sxR$5`PyqIu=cIZozd1v zvo~rF*@7mozM+Py)>W0STT-!Eui3b+s6?vV)W2z0&VDTCNX2f|*7mKPU0ofmP3_I? ztvfo?eO|wp@?wG;6y=K8nz6Khz;rlWmsf@P)++KMP#p_Z&+aT=7a25Zd^a8!NI)b6&>hoqyrz^4-{Hyki4qLyWY# z;pV;A>vZ{o+NivlY?dqibz-C5YSxfjbfu;O8)j2gSoGr9{?;>{@4SFtU43oowFTqS z3^)>;WTW$EQ2M*@y@ww@65v+qrP5;Y=JKt*6lgF%(AVg}8#R>DS%ulG^%jfB@jYe723QWU_PUJ+VNoMin(A^x{<6a> z_O0$u8pJQ)AH4M5(yPx8Tg!Uf+2{^zTZ5B{i$@>hocMz>}p_$s`U+8aC(#L{eke*V(@zbpvE zPhK5^8ZUhR{IgeL_Hhm^*C%&XmWgD1TX}unT2U>3Lw%`TL1_35 z4@Vbl%VWND@t9iGt@@Y^bMU;bdV2%ez0Gd#Cj}FF+z~LGVOygJ5CKJvTP_wX)haE9 zDzes@>boeZ;EUK+^D_H-a~lm-F7G8*z4Nm8NeL; z&{3|PA6A9IT5}%X-_R>=u~RNMe9;7?5klds^XgpSOJb}wRgGCMCCAI@kyZ5lm75J~ z^oz8cZ8D=tgIW2omcj=*ozfOvle58|eu!!?!5p=Xa~Zf`vTex~+4x2ERrWfffUo2m z<``Zv$S?tE*rJuGmC7xZ@{&4@$pH3}#o#b|ZBcW?7HQaK?+7+`w)BR&Jgr#cJN}dQ z-I$Lbu*aYm2O7E-xk_xclEgmdUGXRd7mau`yc$yUpRG8eEOUKx21fOJiqidUI!c zf7^lB$#Jbm8jrz+kfwJIf-m!q%5+D&yVJYX+v90=`LLuX)2|L!#0WU%a%${yeAr|9 z(|o)ydcN`V7$$gMwNSNGu^LOeb^_h~20Q-M>*#J+RC7_3Fn~%rfHFwfY)xP~ zMd`)Do`#NKYa7kPCbb0zRJ*MAO*$d}Z z7DtV%kPJTUn5v(!9j`FspIA}47R`3zJ;8m!;{nVgcgiG}akaN5ECo*w(Kl%%T9!J-LFa6>D_58Uv}#ug)o1rzljG*H&SI z{Whzu-U45r?K_4RoJ8Y#x5B~9;tPm->Eg}l@1a$H5qx?y?gY!nu6ATw%5;ix>&*Gp z6`N(bhFou+vn*24U2(AVkmjg&hrc5dZtdy}_QIDxF0-LQD^482kg76;Os*+X6?pS{ z)M0(d8ZtH8n|)2bCV#;1f(?Cx+m5;50~DL6&B^U;?}lR-$E)^T_Fl|?YQL-7g0F&W z4jj`{TkvS0^?;WQzWqzbSK}s~Nvk0RUq4%;EYPj7%rm6_gJ1dU6C3pG&qp@@=Mj_Z zf%IoJS?WKjF@3J27uU&64!OIS49;_8>ZWYR%ZZ90T%8aHyrC}G&HT-Z1X?r=Q%9qQ zu-E}tBU|AD($VeVs%zP7&zg z*cG^t;^TKptAcQVeg6eC25gKkFQA!cIq?Y{!o;Evi`{p4e>W(SvWm?bt;4M)t0+xl zn+QF4UDzrq4HPC;x!lCUFL%o+8L=t0w{oAjuR8z-Qyz~SoH$@>*&XHvv)2&R#NI*hDN#G^Ys&+CP&EXwfewC(2VuqR-WEw zHrWl1nsle4q1LW-y?7Ppz57Unwv*LnfGjPGe$8kaLeUR?K(*~Z6AI^X%KI7yAcv}9|%h#^F z_g>-&U*`Ok^YP&C>+#!v9qO*f(>QmDl)bdvHIFSj*4T;?>Kvm5YeB1>B}%2fcmbs{<9! zk~s_b^pj64q1g|ef8mGo$6F5%kdbxUs}C4j&Zk#^&wH^3C}j6+3r!bq)}MOVziFh4F#MhX(j*UuxfBfAKeD{~IUX7C$4LFog4_XJ=2J zmb?2p5yvMCrSWO(N+$XPBHw!-VMN-`L-EVt+{67I?eAv$@8N&R@uU61AD!L*a`Jw3 zlnH+{@oe4Pe;IjcOdBKm9UI*bw}_UabhH-YJP6AmK$;V8k7L53qO#5TJ!O65a{M0d zJ!6ZC%Qlnw)@@~d;^lbSsk$ri2d_{#O|H$FGG*;~^m|0UcJAYk54=GCo*3fWgmmT& zxS9V5dg!k(=F?H;RQM$CVH(adQt9bLT75n5N8jCG|55_hW#+r~ORTS0akhiqpE4yS zmeQB9C*?rOiIfW|@4_F-5_2-(kL~nxKH_|mIurh6&b-ux@P~2U;%0Ck=03rl!>!<+ z;SumX`*Gfzy!Uw@@h9-7@Lz#HU!&q{`BDD6{Oj0QOpKA(Mof;Gutw|%b_KgN;_(qr zjhHv$g%L#~sz+Ey93F9f1dX$CF+LgQ^$J{z+wcy22mU_(G5+01@yLvk6GpBYnK!a{ zq-3OgWbMe7k^Lk0jC^b4CnLWa`OlGqqgbOxj~YAbfl-f)dS=v;QLl_D7*#n+HHsS5 zK5F}@J)@3~Iy>s}sP{%)ANBF5Z${l7%^5vn^qr%Hqwo2DD!caRrmA$GP)g72eUmUa z#gcGyMAvmO_!dwY9wUfS5fv5WQ7rG$7Y~~>Y0@pc3`+i4upKO+F zk!-bWy{tr5A=ArVl{L!_$WF=5$Uc>QDf^r3x@=hXqdZ$q{EYlV`BnK>^6%vTrN~jp6cZG;D<&(ZDDGA~ zteCG@qIgNMPEn%Rp{P_;E8L1kMN+X#u}^VOF`#%&@s{G8;tz_C6<;c@D{hRJj2}0i zj2}OK;`qtqr;NXQ{5=!?bn>NPS^9-H5Q5({tjV=H9j03Lwv#@cb*pZ*evPrnq%9%g z%9av!vNW}>i~>$B#Ibyzvu}If+^_P?yek$}#v1u(vwH8*_5<;r z$4T4?0v-}l$(kClCQ)r=b2&^t_BPI^vlQ!A>(&^GOqvoB(WQ#jts7H?sRHc56mT-m z{Uip$2gf$`I{V5G%=s$M!n@*;(cycKwIATSA16G9Pl&^tYmmaCSQv%NL&A2U6f5I( ztc+jZN3bql?;%3Pbh3Z=YoYWGvSB*eb2za(p$r*2!R9^8d=sN4RsA%E)( z_OVh;kr5f2AYZ}O1hQ>zM2i}HEt+^muws&-F=FRcyL&oM?qLtTx95|#>s)g~w4pJW z$ZK@QYg*N<)in{^tlGWc*qhx(uiiV~I?psmr+4M~YQg*r@_ZZ1w?&cuXF?&a(XR|R zq9$IAqd!0V??UP5qW>ut{qtD#KOI^0g{{*`^5bJ6(GHnq9Zn3vk>Emj{>Q26WSL$Hr z>&~cvOpxKv$1bH}i69m38rJ@qc)*?1 z=n7t5$e62~W~b7_Il`d5Mc|--sKtev*?qAS@e6T=9wu)Jr7&bUPoGNv;>BfF?X#jG zYZ^Qj>Q`Ofw|!y8kjo$MO9vzkZMAb=;UmGzF@wH{8>Rmpq=9E7Mcm_q;+9@EYMR!)sLegf+FF)gNC@G8r7E>V7R_->mW2 z3^*m9Pa^~3LDi8&U4jR#dH&bw$xp6$Wz{D2rd9fU_@Hw?y+gR~y|+?_Pl|@Hbkn-( z0@aMQZwlF?hVXL#@^n^x#t>!&`iCy5hJlVA6F_{gHN(40Oxf-^?WUKce{$1;J#;bQ%u$tX1pmwENqU|kg z-?6TX&ELi^$B*;Ppqg`mI%UL^EN@qLY|}=KDk|iOE0oKN%VDXlahu#4!{+i8jMeA@ zht%EZjM>$6#ERhy!;q;8^B;V$@GR=YRmaYL@%hpGv~t9d&AT#1n0oQ8j=_HQ;lb3I zkCno_ng5ZVy5RYWRU6bBSL^a;DTSWlqti&4SVo94Jc@$8^uMBzb=)85wcMps7wUw` zXwf7L%UA)oap|jOOS9~!4?qjQHKCR zTiBj3w5gk`%qVYg+Io9t$X*+oUNsh6$ZQnqron*1OY<8t1Y|6+w#H;}oheRXKh8vr~;}O34TV7&&L>n+Nnh=ev4)*VT z?+811Vc@$yVRF;O__0Vc6OM7gdei{4?C4T=?KH&gDv?Kzr4EZ+`Ys(93R4zZ++y`f zDAoPe+ka(~U7=(nf*)aRR81{5Ta}YFZ_unL%HNv5^@XB>^}Xwlt^aMoJ3Edzc01ba zaT~`p+V%c&mEI`U;n+Q3sVdzev1AMRbZtl3I}6V(ytII6(S^%5DruxEl0+;u$Te^c z%70uO`iOYxsKK$*RqRgxurklRUE{4%X~y~8jykKzigt;ad;@D};=yNY$fOFLkD2CZ zA7MOJ9~k?{mxSzUYbfLjs&G5Ug;_fB0Yc}+O5>V%4dV`lL<@)#53ZXeLaF91^~tjb z-fTOPJkZpUjIJYev_5hxp|{p-izTXO$UH)~koknBYoULUMj8HJzRVJy8E%Jv*#70X z$c^7mBXAstyU;W0JT8Xw_yfrieaG1w4}biV??^wK4@YhCA1?`1Jq%y+KH=4A#5hv! zOT+bKB+BL)@FCptgt8~t%E#3M`;VV`^TW=AZLKXFlL!T)anNN_+75L}ZwObb=u#)n zTrR$ATWxDBnqmezi-!tS!Y30;;4p6OF6*mjQ|(wg+0KJoP8WKZAJr3!x1ndZ*wfY; zO-0#(&Z420Rg~+QIy^Vy4(Tj^TIxtkd&zbW!CmS@HbK)sXhVcSMHd2^VGFNC5?5Od zQ%2dLt`mKOM+ZO&I)47ts`F1=ewbO?->HpY?xhB(=u-qj2nt0R?x0_oD7>N+4&-#! zHzWQS0D&BZ6d8JiSRn?Mi_gP`%d+{x0Cf-!5zd}fWS_COcrQzzAYu(Z-7trU=W8

    {jkyM4+x$u7WP$0Wudi^7_mDKDqxGOv> zh!_C?{RQOAs*Ywvh$9GiMcLO9G#O=@qHr-#7ZuZhMxe=%b?rWng{2RW6N?G;mjt&& zHbgfhwzpI>W&3|y{gLX6Gr`0FOOx;N`{Q2|kbaWp6zF_OZB+;dn*PN&aFreQsHF{u z)rOm3RRD}FOb#rQ;*3MlrIqDMi{{Kp-^S>6TB~f}+FRmAwUI|qNX7Aukxuq_^3R~~ zwlb74S2*=GN;}o3Y)!n954U0-4V^zY)H;wn*woP!`Dq?OAYjV`*`PQiE|yuSGpM)e!$>lI$a9i^x%?UYD2Ety}uY zo#~&aClBR0kVXzEV@*B#2GxUS5B#RHGsD0NDk(>-gfCdlr-CGar$ai zMh6$^4-D~VS&-M8V#->sH+UpC6q>|U`%N`U+U_4=*-q;6Ww#NU%ac8XqA+`kz|d<; z)Bln~Qxk%OGKuS-1ka+xMs$6=v4F1*8IOiw$jVoOSgkXnx{9jI=EkU*eOSJFxnrF&MXDX4!opVOnn7YlOHSVvM#-?EX6Iu3;* z1>`O$G!Cec53PyoaON@!I=e*$9SZ$|y`p{rEqHqIQ_~kS4!6hURyK^IP(z@jdn~DZ zZqv*iD=OAi7Pk`Wvbq}FK@Zzp9$Ge2N!2?>gGu~u1e2($i?``Gwo&V+6Z(e@=`St_ z&wWHEKpzD99akxC{I6Wj`SD8np4|C2u3X9y-W>bmm3cR=jHA+1-w3aMku_`)Ou2Ow z`GRH+5grO9j;m1Oz;7lAy%<$PCOkzU-q8+^uTbqV`#^K2kq%Xy&~HyeJcH&Y2$dea zE|lTsdo`pjF!D8_<6746V+hdFN^LfZbOODh$0Ww6S3@`GP)w`Hl5N$YxxjzDiMxC zL}e}wwKjC@QYLEKeLZS#N9~6~o)T9iqnz>?gi}OK6=;M|)G~Y!>BOpKt9oeXT`#2x zOY8jMx&{@`?W)r#Gn7j;jY3c$CH?j^y|vPCWIEAAl__Y4K;~`~52%UNLQK5wq=dQ+e6uO+Dp@`Y94uDI~5AYH7-HURd{z zaMuTDeIU#`C;aLnWjheW?(HX3oc#iHMluQo)Ib~_T3A@RSyz^P>ga-tvwpLNLgJ~q znm3CQPc&ClfDx|3&Oqx0Iw{l|tptBhr-$@azNj3NLnGjUM_4Md4%C#11{!Jlnc>9m zq-RcNow>0smo6G{)CFd3N|>uBR8@&Q)kx}&MoVK_-o&`~6M6>bkRl(MiN@0is1vd8 z2pvsU

    FJW;hXg_T+VIb^sCs)mY6^h{7N(+OTwCvL@Zz_4fBMnvmT^MoM5~pyz(b{EK4|YV@z(knFh(p?@!R9Ssj>DLK7Vk$q@IO3?3G|hoyAF zmp4AmOupZx5zxz#t1FN=p^+gBH?y`k55Hw$p_F>8HfJ^cee~P}>UG0ZG+|DO^3~Gs zffW#u$5SGtcxr=)tiMQGA(1^(g!Dbh10u#sq_>Mw-FU443Z>cT6Y(JWXJjy2d>zvR zslyqPMbhOG<5?Ffy#5+! zL>nsEf5#Iv{`<}`(AE}@Rs4rBSB|3K|7iczzX|>SAH=c!5kNfdR-g_D0Ox={;4@$= zP>pkv13ZLwJrG1&iq~F1+_oL?08!u&-~enu86b|M0p16?fwzG$Py>jc*#f)>90tVW zF#$!uw$Z;awv<6T36zXN9AAX^8F7Eh0dafrd+Y$jeeNCoTig!gOIMDWA(;kD9rLi{ zc|eKxSB|+;axXATdb?!pn0(2sG211D|Gb^pCz%S3bzGAS@Y&25qvMI!2-kao2(dlp zd&$FDzm(i@b8I!9fbzeLd$a$ReM5eo01e`?ARsAf`>UbTE?xBG(&Z9H{3(b}N6GX^ z%S*OyzdCamKo#8~apU-!B$y47efUrQ E2Tw{-o0zK2^O2nx$HD*Ub4 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 literal 0 HcmV?d00001 diff --git a/lib/Han/dist/han.css b/lib/Han/dist/han.css new file mode 100644 index 0000000..1b82c58 --- /dev/null +++ b/lib/Han/dist/han.css @@ -0,0 +1,2038 @@ +@charset "UTF-8"; + +/*! 漢字標準格式 v3.3.0 | MIT License | css.hanzi.co */ +/*! Han.css: the CSS typography framework optimised for Hanzi */ + +/* normalize.css v4.0.0 | MIT License | github.com/necolas/normalize.css */ +html { + font-family: sans-serif; /* 1 */ + -ms-text-size-adjust: 100%; /* 2 */ + -webkit-text-size-adjust: 100%; /* 2 */ +} +body { + margin: 0; +} +article, +aside, +details, +figcaption, +figure, +footer, +header, +main, +menu, +nav, +section, +summary { + /* 1 */ + display: block; +} +audio, +canvas, +progress, +video { + display: inline-block; +} +audio:not([controls]) { + display: none; + height: 0; +} +progress { + vertical-align: baseline; +} +template, +[hidden] { + display: none; +} +a { + background-color: transparent; +} +a:active, +a:hover { + outline-width: 0; +} +abbr[title] { + border-bottom: none; /* 1 */ + text-decoration: underline; /* 2 */ + text-decoration: underline dotted; /* 2 */ +} +b, +strong { + font-weight: inherit; +} +b, +strong { + font-weight: bolder; +} +dfn { + font-style: italic; +} +h1 { + font-size: 2em; + margin: .67em 0; +} +mark { + background-color: #ff0; + color: #000; +} +small { + font-size: 80%; +} +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} +sub { + bottom: -.25em; +} +sup { + top: -.5em; +} +img { + border-style: none; +} +svg:not(:root) { + overflow: hidden; +} +code, +kbd, +pre, +samp { + font-family: monospace, monospace; /* 1 */ + font-size: 1em; /* 2 */ +} +figure { + margin: 1em 40px; +} +hr { + box-sizing: content-box; /* 1 */ + height: 0; /* 1 */ + overflow: visible; /* 2 */ +} +button, +input, +select, +textarea { + font: inherit; +} +optgroup { + font-weight: bold; +} +button, +input, +select { + /* 2 */ + overflow: visible; +} +button, +input, +select, +textarea { + /* 1 */ + margin: 0; +} +button, +select { + /* 1 */ + text-transform: none; +} +button, +[type="button"], +[type="reset"], +[type="submit"] { + cursor: pointer; +} +[disabled] { + cursor: default; +} +button, +html [type="button"], +[type="reset"], +[type="submit"] { + -webkit-appearance: button; /* 2 */ +} +button::-moz-focus-inner, +input::-moz-focus-inner { + border: 0; + padding: 0; +} +button:-moz-focusring, +input:-moz-focusring { + outline: 1px dotted ButtonText; +} +fieldset { + border: 1px solid #c0c0c0; + margin: 0 2px; + padding: .35em .625em .75em; +} +legend { + box-sizing: border-box; /* 1 */ + color: inherit; /* 2 */ + display: table; /* 1 */ + max-width: 100%; /* 1 */ + padding: 0; /* 3 */ + white-space: normal; /* 1 */ +} +textarea { + overflow: auto; +} +[type="checkbox"], +[type="radio"] { + box-sizing: border-box; /* 1 */ + padding: 0; /* 2 */ +} +[type="number"]::-webkit-inner-spin-button, +[type="number"]::-webkit-outer-spin-button { + height: auto; +} +[type="search"] { + -webkit-appearance: textfield; +} +[type="search"]::-webkit-search-cancel-button, +[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} +html { + line-height: 1.3; + -webkit-font-smoothing: subpixel-antialiased; +} +ol, +ul { + padding-left: 2em; +} +figure, +blockquote { + margin-left: 2em; + margin-right: 2em; +} +address { + font-style: inherit; +} +pre { + overflow: auto; + white-space: pre; + word-wrap: normal; +} +a { + text-decoration: inherit; +} +em:lang(zh), +em:lang(ja) { + -moz-text-emphasis: filled circle; + -webkit-text-emphasis: filled circle; + text-emphasis: filled circle; + -moz-text-emphasis-position: under; + -webkit-text-emphasis-position: under; + text-emphasis-position: under; + font-style: inherit; + border-bottom: 2px dotted; + padding-bottom: .05em; + border-bottom-width: -webkit-calc(0px); + padding-bottom: -webkit-calc(0px); +} +em:lang(ja) { + -moz-text-emphasis: filled sesame; + -webkit-text-emphasis: filled sesame; + text-emphasis: filled sesame; + -moz-text-emphasis-position: over; + -webkit-text-emphasis-position: over; + text-emphasis-position: over; +} +dfn:lang(zh), +dfn:lang(ja) { + font-weight: inherit; + font-style: inherit; +} +dfn:lang(zh), +dfn:lang(ja) { + font-weight: bolder; +} +cite:lang(zh), +cite:lang(ja) { + font-style: inherit; +} +q { + quotes: "\201c" "\201d" "\2018" "\2019" "\201c" "\201d" "\2018" "\2019" "\201c" "\201d" "\2018" "\2019"; +} +q:lang(zh) { + quotes: "\300c" "\300d" "\300e" "\300f" "\300c" "\300d" "\300e" "\300f" "\300c" "\300d" "\300e" "\300f"; +} +q:lang(zh-CN), +q:lang(en) { + quotes: "\201c" "\201d" "\2018" "\2019" "\201c" "\201d" "\2018" "\2019" "\201c" "\201d" "\2018" "\2019"; +} +q:lang(en-GB) { + quotes: "\2018" "\2019" "\201c" "\201d" "\2018" "\2019" "\201c" "\201d" "\2018" "\2019" "\201c" "\201d"; +} +q:before { + content: open-quote; +} +q:after { + content: close-quote; +} +q:lang(ja):before, +q:lang(ja):after { + content: none; +} +code, +kbd, +samp, +pre { + font-family: monospace, monospace, sans-serif; +} +i:lang(zh), +var:lang(zh), +i:lang(ja), +var:lang(ja) { + font-family: cursive, serif; + font-style: inherit; +} +u + u, +ins + u, +u + ins, +ins + ins, +s + s, +del + s, +s + del, +del + del, +.han-js-rendered u.adjacent, +.han-js-rendered ins.adjacent, +.han-js-rendered s + s.adjacent, +.han-js-rendered del + s.adjacent, +.han-js-rendered s + del.adjacent, +.han-js-rendered del + del.adjacent { + margin-left: .125em; +} +u, +ins { + padding-bottom: .05em; + border-bottom: 1px solid; + text-decoration: none; +} +ruby rtc rt { + display: inline; + font-size: inherit; +} +ruby.zhuyin, +ruby.mps { + display: ruby; + -webkit-ruby-position: inter-character; + ruby-position: inter-character; +} +ruby.zhuyin > rt, +ruby.mps > rt { + -moz-transform: scale(.8); + -ms-transform: scale(.8); + -webkit-transform: scale(.8); + transform: scale(.8); + -moz-transform-origin: left center; + -ms-transform-origin: left center; + -webkit-transform-origin: left center; + transform-origin: left center; + font-size: .5em; +} +ruby.zhuyin > rt:empty, +ruby.mps > rt:empty { + display: none; +} +.han-js-rendered u + u, +.han-js-rendered ins + u, +.han-js-rendered u + ins, +.han-js-rendered ins + ins, +.han-js-rendered s + s, +.han-js-rendered del + s, +.han-js-rendered s + del, +.han-js-rendered del + del { + margin-left: auto; +} +.textemphasis $han-text-emphasis-pf h-jinze, +.textemphasis em:lang(zh) h-jinze, +.textemphasis em:lang(ja) h-jinze { + display: inline; +} +.han-js-rendered em:lang(zh), +.han-js-rendered em:lang(ja) { + padding-bottom: auto; + border-bottom-width: 0; +} +.no-textemphasis em:lang(zh), +.no-textemphasis em:lang(ja) { + line-height: 2; +} +.no-textemphasis em:lang(zh) h-char, +.no-textemphasis em:lang(ja) h-char { + position: relative; + font-style: inherit; +} +.no-textemphasis em:lang(zh) h-char:after, +.no-textemphasis em:lang(ja) h-char:after { + -moz-text-emphasis: none; + -webkit-text-emphasis: none; + text-emphasis: none; + font-style: normal; + font-weight: normal; + line-height: normal; + text-decoration: none; + text-indent: 0; + -moz-transform: scale(.5); + -ms-transform: scale(.5); + -webkit-transform: scale(.5); + transform: scale(.5); + position: absolute; + left: 50%; + top: 0; + margin-left: -250%; + overflow: hidden; + display: inline-block; + height: 1em; + width: 500%; + line-height: 1; + text-align: center; + text-indent: 0; + font-family: Georgia, "Times New Roman", Arial, !important; +} +em:lang(zh) h-char.punct, +em:lang(ja) h-char.punct, +em:lang(zh) h-char.biaodian, +em:lang(ja) h-char.biaodian { + -moz-text-emphasis: none; + -webkit-text-emphasis: none; + text-emphasis: none; +} +.no-textemphasis em:lang(zh) h-char.punct:after, +.no-textemphasis em:lang(ja) h-char.punct:after, +.no-textemphasis em:lang(zh) h-char.biaodian:after, +.no-textemphasis em:lang(ja) h-char.biaodian:after { + content: none !important; +} +.no-textemphasis em:lang(zh) h-char:after { + margin-top: 1em; + content: "\25cf"; +} +.no-textemphasis em:lang(ja) h-char:after { + margin-top: -.7em; + content: "\fe45"; +} +ruby.zhuyin h-zhuyin, +ruby.mps h-zhuyin, +h-ruby.zhuyin h-zhuyin { + position: relative; + letter-spacing: 0; +} +ruby.zhuyin h-diao, +ruby.mps h-diao, +h-ruby.zhuyin h-diao { + position: absolute; + right: -.9em; + bottom: .5em; + display: block; + font-size: 1.5em; +} +ruby.zhuyin h-diao h-char, +ruby.mps h-diao h-char, +h-ruby.zhuyin h-diao h-char { + -webkit-writing-mode: horizontal-tb; + writing-mode: horizontal-tb; +} +ruby.zhuyin [diao="˙"] h-diao, +ruby.mps [diao="˙"] h-diao, +h-ruby.zhuyin [diao="˙"] h-diao { + top: -.3em; + right: auto; + bottom: auto; + left: 0; + font-size: 1em; +} +ruby.zhuyin [diao^="ㆴ"] h-diao, +ruby.mps [diao^="ㆴ"] h-diao, +h-ruby.zhuyin [diao^="ㆴ"] h-diao, +ruby.zhuyin [diao^="ㆵ"] h-diao, +ruby.mps [diao^="ㆵ"] h-diao, +h-ruby.zhuyin [diao^="ㆵ"] h-diao, +ruby.zhuyin [diao^="ㆶ"] h-diao, +ruby.mps [diao^="ㆶ"] h-diao, +h-ruby.zhuyin [diao^="ㆶ"] h-diao, +ruby.zhuyin [diao^="ㆷ"] h-diao, +ruby.mps [diao^="ㆷ"] h-diao, +h-ruby.zhuyin [diao^="ㆷ"] h-diao, +ruby.zhuyin [diao="󳆴"] h-diao, +ruby.mps [diao="󳆴"] h-diao, +h-ruby.zhuyin [diao="󳆴"] h-diao, +ruby.zhuyin [diao="󳆵"] h-diao, +ruby.mps [diao="󳆵"] h-diao, +h-ruby.zhuyin [diao="󳆵"] h-diao, +ruby.zhuyin [diao="󳆶"] h-diao, +ruby.mps [diao="󳆶"] h-diao, +h-ruby.zhuyin [diao="󳆶"] h-diao, +ruby.zhuyin [diao="󳆷"] h-diao, +ruby.mps [diao="󳆷"] h-diao, +h-ruby.zhuyin [diao="󳆷"] h-diao { + right: -1em; + bottom: -.125em; + font-size: 1em; +} +h-ru[annotation] { + position: relative; + display: inline-table; + border-collapse: collapse; + border-spacing: 0; + line-height: 1.1; + text-align: center; + vertical-align: 1em; +} +h-ru[annotation] > h-ru[annotation] { + vertical-align: -.1em; +} +h-ru[annotation] > h-ru, +h-ru[annotation] > rb, +h-ru[annotation] > rt { + line-height: 1; + text-align: center; +} +h-ru[annotation] > rt { + display: table-header-group; + height: 1em; + font-size: .5em; + white-space: nowrap; + word-break: normal; +} +h-ru[annotation] > rt:before, +h-ru[annotation] > rt:after { + content: "\2006"; +} +h-ru[order="0"] > rt, +h-ruby[rightangle][doubleline] h-ru[order="0"] > rt { + display: table-header-group; +} +h-ru[order="1"] > rt, +h-ruby[rightangle] h-ru[order="0"] > rt, +h-ruby[rightangle][doubleline] h-ru[order="1"] > rt { + display: table-footer-group; +} +h-ru[order="0"] > h-ru[order="1"] { + vertical-align: .15em; +} +h-ruby[rightangle][doubleline] h-ru[order="0"] rt { + line-height: 1.5; +} +h-ruby[rightangle][doubleline] h-ru[annotation] { + vertical-align: .5em; +} +[zhuyin] h-zhuyin { + -moz-text-emphasis: none; + -webkit-text-emphasis: none; + text-emphasis: none; + font-style: normal; + font-weight: normal; + line-height: normal; + text-decoration: none; + text-indent: 0; + position: relative; + display: inline-block; + height: 1em; + width: .4em; + vertical-align: text-top; +} +[zhuyin] h-zhuyin > * { + -moz-transform: scale(.4); + -ms-transform: scale(.4); + -webkit-transform: scale(.4); + transform: scale(.4); + -moz-transform-origin: left top; + -ms-transform-origin: left top; + -webkit-transform-origin: left top; + transform-origin: left top; + display: inline-block; +} +[zhuyin] h-yin { + position: absolute; + left: 0; + height: 1em; + vertical-align: top; + line-height: 1; +} +[zhuyin] h-diao { + position: absolute; + bottom: 0; + right: -.9em; + line-height: 1; +} +[zhuyin] h-yin:empty, +[zhuyin] h-diao:empty { + display: none; +} +[zhuyin] [length="0"] { + margin-right: 0; +} +[zhuyin] [length="0"] h-zhuyin { + display: none; +} +[zhuyin] [length="1"] h-yin { + top: .3em; +} +[zhuyin] [length="1"] h-diao { + bottom: 0; +} +[zhuyin] [length="2"] h-yin { + top: .05em; +} +[zhuyin] [length="2"] h-diao { + bottom: -.3em; +} +[zhuyin] [length="3"] h-yin { + top: -.05em; + line-height: .85; +} +[zhuyin] [length="3"] h-diao { + bottom: -.35em; +} +[zhuyin] [diao="˙"] h-diao { + top: 0; + right: auto; + bottom: auto; + left: .06em; +} +[zhuyin] [diao="˙"] [length="1"] h-diao { + top: .15em; +} +[zhuyin] [diao="˙"] [length="2"] h-diao { + top: -.05em; +} +[zhuyin] [diao="˙"] [length="3"] h-diao { + top: -.2em; +} +[zhuyin] [diao="˪"] h-diao, +[zhuyin] [diao="˫"] h-diao { + -moz-transform: scale(.6); + -ms-transform: scale(.6); + -webkit-transform: scale(.6); + transform: scale(.6); + -moz-transform-origin: left top; + -ms-transform-origin: left top; + -webkit-transform-origin: left top; + transform-origin: left top; +} +[zhuyin] [diao^="ㆴ"] h-diao, +[zhuyin] [diao^="ㆵ"] h-diao, +[zhuyin] [diao^="ㆶ"] h-diao, +[zhuyin] [diao^="ㆷ"] h-diao, +[zhuyin] [diao="󳆴"] h-diao, +[zhuyin] [diao="󳆵"] h-diao, +[zhuyin] [diao="󳆶"] h-diao, +[zhuyin] [diao="󳆷"] h-diao { + bottom: -.6em; + margin-right: .3em; +} +[zhuyin] { + margin-right: .2em; + display: inline-block; + line-height: 1.8; +} +[rightangle] h-ru[annotation] { + vertical-align: 0; + line-height: 1; +} +[rightangle] rt:after { + content: ""; + display: inline-block; + width: 1.2em; +} +h-ru h-ru[zhuyin] { + margin-top: -.4em; + margin-bottom: -.2em; + line-height: 1.8; +} +h-jinze, +h-word { + display: inline-block; + text-indent: 0; +} +@font-face { + font-family: "Han Heiti"; + src: local("Hiragino Sans GB"), local("Lantinghei TC Extralight"), local("Lantinghei SC Extralight"), local(FZLTXHB--B51-0), local(FZLTZHK--GBK1-0), local(".PingFang SC Light"), local(".PingFang TC Light"), local(".PingFang-SC-Light"), local(".PingFang-TC-Light"), local(".PingFang SC"), local(".PingFang TC"), local("Heiti SC Light"), local(STHeitiSC-Light), local("Heiti SC"), local("Heiti TC Light"), local(STHeitiTC-Light), local("Heiti TC"), local("Microsoft Yahei"), local("Microsoft Jhenghei"), local("Noto Sans CJK KR"), local("Noto Sans CJK JP"), local("Noto Sans CJK SC"), local("Noto Sans CJK TC"), local("Source Han Sans K"), local("Source Han Sans KR"), local("Source Han Sans JP"), local("Source Han Sans CN"), local("Source Han Sans HK"), local("Source Han Sans TW"), local("Source Han Sans TWHK"), local("Droid Sans Fallback"); +} +@font-face { + unicode-range: U+4E00-9FFF, U+3400-4DB5, U+20000-2A6D6, U+2A700-2B734, U+2B740-2B81D, U+FA0E-FA0F, U+FA11, U+FA13-FA14, U+FA1F, U+FA21, U+FA23, U+FA24, U+FA27-FA29, U+3040-309F, U+30A0-30FF, U+3099-309E, U+FF66-FF9F, U+3007, U+31C0-31E3, U+2F00-2FD5, U+2E80-2EF3; + font-family: "Han Heiti"; + src: local(YuGothic), local("Hiragino Kaku Gothic ProN"), local("Hiragino Kaku Gothic Pro"); +} +@font-face { + font-family: "Han Heiti CNS"; + src: local(".PingFang TC Light"), local(".PingFang-TC-Light"), local(".PingFang TC"), local("Heiti TC Light"), local(STHeitiTC-Light), local("Heiti TC"), local("Lantinghei TC Extralight"), local(FZLTXHB--B51-0), local("Lantinghei TC"), local("Microsoft Jhenghei"), local("Microsoft Yahei"), local("Noto Sans CJK TC"), local("Source Han Sans TC"), local("Source Han Sans TW"), local("Source Han Sans TWHK"), local("Source Han Sans HK"), local("Droid Sans Fallback"); +} +@font-face { + font-family: "Han Heiti GB"; + src: local("Hiragino Sans GB"), local(".PingFang SC Light"), local(".PingFang-SC-Light"), local(".PingFang SC"), local("Lantinghei SC Extralight"), local(FZLTXHK--GBK1-0), local("Lantinghei SC"), local("Heiti SC Light"), local(STHeitiSC-Light), local("Heiti SC"), local("Microsoft Yahei"), local("Noto Sans CJK SC"), local("Source Han Sans SC"), local("Source Han Sans CN"), local("Droid Sans Fallback"); +} +@font-face { + font-family: "Han Heiti"; + font-weight: 600; + src: local("Hiragino Sans GB W6"), local(HiraginoSansGB-W6), local("Lantinghei TC Demibold"), local("Lantinghei SC Demibold"), local(FZLTZHB--B51-0), local(FZLTZHK--GBK1-0), local(".PingFang-SC-Semibold"), local(".PingFang-TC-Semibold"), local("Heiti SC Medium"), local("STHeitiSC-Medium"), local("Heiti SC"), local("Heiti TC Medium"), local("STHeitiTC-Medium"), local("Heiti TC"), local("Microsoft YaHei Bold"), local("Microsoft Jhenghei Bold"), local(MicrosoftYaHei-Bold), local(MicrosoftJhengHeiBold), local("Microsoft YaHei"), local("Microsoft Jhenghei"), local("Noto Sans CJK KR Bold"), local("Noto Sans CJK JP Bold"), local("Noto Sans CJK SC Bold"), local("Noto Sans CJK TC Bold"), local(NotoSansCJKkr-Bold), local(NotoSansCJKjp-Bold), local(NotoSansCJKsc-Bold), local(NotoSansCJKtc-Bold), local("Source Han Sans K Bold"), local(SourceHanSansK-Bold), local("Source Han Sans K"), local("Source Han Sans KR Bold"), local("Source Han Sans JP Bold"), local("Source Han Sans CN Bold"), local("Source Han Sans HK Bold"), local("Source Han Sans TW Bold"), local("Source Han Sans TWHK Bold"), local("SourceHanSansKR-Bold"), local("SourceHanSansJP-Bold"), local("SourceHanSansCN-Bold"), local("SourceHanSansHK-Bold"), local("SourceHanSansTW-Bold"), local("SourceHanSansTWHK-Bold"), local("Source Han Sans KR"), local("Source Han Sans CN"), local("Source Han Sans HK"), local("Source Han Sans TW"), local("Source Han Sans TWHK"); +} +@font-face { + unicode-range: U+4E00-9FFF, U+3400-4DB5, U+20000-2A6D6, U+2A700-2B734, U+2B740-2B81D, U+FA0E-FA0F, U+FA11, U+FA13-FA14, U+FA1F, U+FA21, U+FA23, U+FA24, U+FA27-FA29, U+3040-309F, U+30A0-30FF, U+3099-309E, U+FF66-FF9F, U+3007, U+31C0-31E3, U+2F00-2FD5, U+2E80-2EF3; + font-family: "Han Heiti"; + font-weight: 600; + src: local("YuGothic Bold"), local("Hiragino Kaku Gothic ProN W6"), local("Hiragino Kaku Gothic Pro W6"), local(YuGo-Bold), local(HiraKakuProN-W6), local(HiraKakuPro-W6); +} +@font-face { + font-family: "Han Heiti CNS"; + font-weight: 600; + src: local(".PingFang TC Semibold"), local(".PingFang-TC-Semibold"), local("Heiti TC Medium"), local("STHeitiTC-Medium"), local("Heiti TC"), local("Lantinghei TC Demibold"), local(FZLTXHB--B51-0), local("Microsoft Jhenghei Bold"), local(MicrosoftJhengHeiBold), local("Microsoft Jhenghei"), local("Microsoft YaHei Bold"), local(MicrosoftYaHei-Bold), local("Noto Sans CJK TC Bold"), local(NotoSansCJKtc-Bold), local("Noto Sans CJK TC"), local("Source Han Sans TC Bold"), local("SourceHanSansTC-Bold"), local("Source Han Sans TC"), local("Source Han Sans TW Bold"), local("SourceHanSans-TW"), local("Source Han Sans TW"), local("Source Han Sans TWHK Bold"), local("SourceHanSans-TWHK"), local("Source Han Sans TWHK"), local("Source Han Sans HK"), local("SourceHanSans-HK"), local("Source Han Sans HK"); +} +@font-face { + font-family: "Han Heiti GB"; + font-weight: 600; + src: local("Hiragino Sans GB W6"), local(HiraginoSansGB-W6), local(".PingFang SC Semibold"), local(".PingFang-SC-Semibold"), local("Lantinghei SC Demibold"), local(FZLTZHK--GBK1-0), local("Heiti SC Medium"), local("STHeitiSC-Medium"), local("Heiti SC"), local("Microsoft YaHei Bold"), local(MicrosoftYaHei-Bold), local("Microsoft YaHei"), local("Noto Sans CJK SC Bold"), local(NotoSansCJKsc-Bold), local("Noto Sans CJK SC"), local("Source Han Sans SC Bold"), local("SourceHanSansSC-Bold"), local("Source Han Sans CN Bold"), local("SourceHanSansCN-Bold"), local("Source Han Sans SC"), local("Source Han Sans CN"); +} +@font-face { + font-family: "Han Heiti"; + src: local("Hiragino Sans GB"), local("Lantinghei TC Extralight"), local("Lantinghei SC Extralight"), local(FZLTXHB--B51-0), local(FZLTZHK--GBK1-0), local(".PingFang SC Light"), local(".PingFang TC Light"), local(".PingFang-SC-Light"), local(".PingFang-TC-Light"), local(".PingFang SC"), local(".PingFang TC"), local("Heiti SC Light"), local("STHeitiSC-Light"), local("Heiti SC"), local("Heiti TC Light"), local("STHeitiTC-Light"), local("Heiti TC"), local("Microsoft Yahei"), local("Microsoft Jhenghei"), local("Noto Sans CJK KR"), local("Noto Sans CJK JP"), local("Noto Sans CJK SC"), local("Noto Sans CJK TC"), local("Source Han Sans K"), local("Source Han Sans KR"), local("Source Han Sans JP"), local("Source Han Sans CN"), local("Source Han Sans HK"), local("Source Han Sans TW"), local("Source Han Sans TWHK"), local("Droid Sans Fallback"); + unicode-range: U+270C; +} +@font-face { + font-family: "Han Heiti"; + font-weight: 600; + src: local("Hiragino Sans GB W6"), local(HiraginoSansGB-W6), local("Lantinghei TC Demibold"), local("Lantinghei SC Demibold"), local(FZLTZHB--B51-0), local(FZLTZHK--GBK1-0), local(".PingFang-SC-Semibold"), local(".PingFang-TC-Semibold"), local("Heiti SC Medium"), local("STHeitiSC-Medium"), local("Heiti SC"), local("Heiti TC Medium"), local("STHeitiTC-Medium"), local("Heiti TC"), local("Microsoft YaHei Bold"), local("Microsoft Jhenghei Bold"), local(MicrosoftYaHei-Bold), local(MicrosoftJhengHeiBold), local("Microsoft YaHei"), local("Microsoft Jhenghei"), local("Noto Sans CJK KR Bold"), local("Noto Sans CJK JP Bold"), local("Noto Sans CJK SC Bold"), local("Noto Sans CJK TC Bold"), local(NotoSansCJKkr-Bold), local(NotoSansCJKjp-Bold), local(NotoSansCJKsc-Bold), local(NotoSansCJKtc-Bold), local("Source Han Sans K Bold"), local(SourceHanSansK-Bold), local("Source Han Sans K"), local("Source Han Sans KR Bold"), local("Source Han Sans JP Bold"), local("Source Han Sans CN Bold"), local("Source Han Sans HK Bold"), local("Source Han Sans TW Bold"), local("Source Han Sans TWHK Bold"), local("SourceHanSansKR-Bold"), local("SourceHanSansJP-Bold"), local("SourceHanSansCN-Bold"), local("SourceHanSansHK-Bold"), local("SourceHanSansTW-Bold"), local("SourceHanSansTWHK-Bold"), local("Source Han Sans KR"), local("Source Han Sans CN"), local("Source Han Sans HK"), local("Source Han Sans TW"), local("Source Han Sans TWHK"); + unicode-range: U+270C; +} +@font-face { + font-family: "Han Songti"; + src: local("Songti SC Regular"), local(STSongti-SC-Regular), local("Songti SC"), local("Songti TC Regular"), local(STSongti-TC-Regular), local("Songti TC"), local(STSong), local("Lisong Pro"), local(SimSun), local(PMingLiU); +} +@font-face { + unicode-range: U+4E00-9FFF, U+3400-4DB5, U+20000-2A6D6, U+2A700-2B734, U+2B740-2B81D, U+FA0E-FA0F, U+FA11, U+FA13-FA14, U+FA1F, U+FA21, U+FA23, U+FA24, U+FA27-FA29, U+3040-309F, U+30A0-30FF, U+3099-309E, U+FF66-FF9F, U+3007, U+31C0-31E3, U+2F00-2FD5, U+2E80-2EF3; + font-family: "Han Songti"; + src: local(YuMincho), local("Hiragino Mincho ProN"), local("Hiragino Mincho Pro"), local("MS Mincho"); +} +@font-face { + font-family: "Han Songti CNS"; + src: local("Songti TC Regular"), local(STSongti-TC-Regular), local("Songti TC"), local("Lisong Pro"), local("Songti SC Regular"), local(STSongti-SC-Regular), local("Songti SC"), local(STSong), local(PMingLiU), local(SimSun); +} +@font-face { + font-family: "Han Songti GB"; + src: local("Songti SC Regular"), local(STSongti-SC-Regular), local("Songti SC"), local(STSong), local(SimSun), local(PMingLiU); +} +@font-face { + font-family: "Han Songti"; + font-weight: 600; + src: local("STSongti SC Bold"), local("STSongti TC Bold"), local(STSongti-SC-Bold), local(STSongti-TC-Bold), local("STSongti SC"), local("STSongti TC"); +} +@font-face { + unicode-range: U+4E00-9FFF, U+3400-4DB5, U+20000-2A6D6, U+2A700-2B734, U+2B740-2B81D, U+FA0E-FA0F, U+FA11, U+FA13-FA14, U+FA1F, U+FA21, U+FA23, U+FA24, U+FA27-FA29, U+3040-309F, U+30A0-30FF, U+3099-309E, U+FF66-FF9F, U+3007, U+31C0-31E3, U+2F00-2FD5, U+2E80-2EF3; + font-family: "Han Songti"; + font-weight: 600; + src: local("YuMincho Demibold"), local("Hiragino Mincho ProN W6"), local("Hiragino Mincho Pro W6"), local(YuMin-Demibold), local(HiraMinProN-W6), local(HiraMinPro-W6), local(YuMincho), local("Hiragino Mincho ProN"), local("Hiragino Mincho Pro"); +} +@font-face { + font-family: "Han Songti CNS"; + font-weight: 600; + src: local("STSongti TC Bold"), local("STSongti SC Bold"), local(STSongti-TC-Bold), local(STSongti-SC-Bold), local("STSongti TC"), local("STSongti SC"); +} +@font-face { + font-family: "Han Songti GB"; + font-weight: 600; + src: local("STSongti SC Bold"), local(STSongti-SC-Bold), local("STSongti SC"); +} +@font-face { + font-family: "Han Songti"; + src: local("Songti SC Regular"), local(STSongti-SC-Regular), local("Songti SC"), local("Songti TC Regular"), local(STSongti-TC-Regular), local("Songti TC"), local(STSongti), local("Lisong Pro"), local("MS Mincho"), local(SimSun), local(PMingLiU); + unicode-range: U+270C; +} +@font-face { + font-family: "Han Songti"; + font-weight: 600; + src: local("Songti TC Bold"), local("Songti SC Bold"), local(STSongti-TC-Bold), local(STSongti-SC-Bold), local("Songti TC"), local("Songti SC"); + unicode-range: U+270C; +} +@font-face { + font-family: "Han Songti CNS"; + src: local("Songti TC Regular"), local("Lisong Pro"), local("Songti TC"), local("Songti SC Regular"), local(STSong), local("Songti SC"), local("MS Mincho"), local(PMingLiU), local(SimSun); + unicode-range: U+270C; +} +@font-face { + font-family: "Han Songti CNS"; + font-weight: 600; + src: local("Songti TC Bold"), local("Songti SC Bold"), local(STSongti-TC-Bold), local(STSongti-SC-Bold), local("Songti TC"), local("Songti SC"); + unicode-range: U+270C; +} +@font-face { + font-family: "Han Songti GB"; + src: local("Songti SC"), local(STSong), local(SimSun); + unicode-range: U+270C; +} +@font-face { + font-family: "Han Songti GB"; + font-weight: 600; + src: local("Songti SC Bold"), local(STSongti-SC-Bold), local("Songti SC"); + unicode-range: U+270C; +} +@font-face { + font-family: cursive; + src: local("Kaiti TC Regular"), local(STKaiTi-TC-Regular), local("Kaiti TC"), local("Kaiti SC"), local(STKaiti), local(BiauKai), local("標楷體"), local(DFKaiShu-SB-Estd-BF), local(Kaiti), local(DFKai-SB); +} +@font-face { + unicode-range: U+4E00-9FFF, U+3400-4DB5, U+20000-2A6D6, U+2A700-2B734, U+2B740-2B81D, U+FA0E-FA0F, U+FA11, U+FA13-FA14, U+FA1F, U+FA21, U+FA23, U+FA24, U+FA27-FA29, U+3040-309F, U+30A0-30FF, U+3099-309E, U+FF66-FF9F, U+3007, U+31C0-31E3, U+2F00-2FD5, U+2E80-2EF3; + font-family: "Han Kaiti"; + src: local("Kaiti TC Regular"), local(STKaiTi-TC-Regular), local("Kaiti TC"), local("Kaiti SC"), local(STKaiti), local(BiauKai), local("標楷體"), local(DFKaiShu-SB-Estd-BF), local(Kaiti), local(DFKai-SB); +} +@font-face { + unicode-range: U+4E00-9FFF, U+3400-4DB5, U+20000-2A6D6, U+2A700-2B734, U+2B740-2B81D, U+FA0E-FA0F, U+FA11, U+FA13-FA14, U+FA1F, U+FA21, U+FA23, U+FA24, U+FA27-FA29, U+3040-309F, U+30A0-30FF, U+3099-309E, U+FF66-FF9F, U+3007, U+31C0-31E3, U+2F00-2FD5, U+2E80-2EF3; + font-family: "Han Kaiti CNS"; + src: local(BiauKai), local("標楷體"), local(DFKaiShu-SB-Estd-BF), local("Kaiti TC Regular"), local(STKaiTi-TC-Regular), local("Kaiti TC"); +} +@font-face { + unicode-range: U+4E00-9FFF, U+3400-4DB5, U+20000-2A6D6, U+2A700-2B734, U+2B740-2B81D, U+FA0E-FA0F, U+FA11, U+FA13-FA14, U+FA1F, U+FA21, U+FA23, U+FA24, U+FA27-FA29, U+3040-309F, U+30A0-30FF, U+3099-309E, U+FF66-FF9F, U+3007, U+31C0-31E3, U+2F00-2FD5, U+2E80-2EF3; + font-family: "Han Kaiti GB"; + src: local("Kaiti SC Regular"), local(STKaiTi-SC-Regular), local("Kaiti SC"), local(STKaiti), local(Kai), local(Kaiti), local(DFKai-SB); +} +@font-face { + font-family: cursive; + font-weight: 600; + src: local("Kaiti TC Bold"), local(STKaiTi-TC-Bold), local("Kaiti SC Bold"), local(STKaiti-SC-Bold), local("Kaiti TC"), local("Kaiti SC"); +} +@font-face { + font-family: "Han Kaiti"; + font-weight: 600; + src: local("Kaiti TC Bold"), local(STKaiTi-TC-Bold), local("Kaiti SC Bold"), local(STKaiti-SC-Bold), local("Kaiti TC"), local("Kaiti SC"); +} +@font-face { + font-family: "Han Kaiti CNS"; + font-weight: 600; + src: local("Kaiti TC Bold"), local(STKaiTi-TC-Bold), local("Kaiti TC"); +} +@font-face { + font-family: "Han Kaiti GB"; + font-weight: 600; + src: local("Kaiti SC Bold"), local(STKaiti-SC-Bold); +} +@font-face { + unicode-range: U+4E00-9FFF, U+3400-4DB5, U+20000-2A6D6, U+2A700-2B734, U+2B740-2B81D, U+FA0E-FA0F, U+FA11, U+FA13-FA14, U+FA1F, U+FA21, U+FA23, U+FA24, U+FA27-FA29, U+3040-309F, U+30A0-30FF, U+3099-309E, U+FF66-FF9F, U+3007, U+31C0-31E3, U+2F00-2FD5, U+2E80-2EF3; + font-family: "Han Fangsong"; + src: local(STFangsong), local(FangSong); +} +@font-face { + unicode-range: U+4E00-9FFF, U+3400-4DB5, U+20000-2A6D6, U+2A700-2B734, U+2B740-2B81D, U+FA0E-FA0F, U+FA11, U+FA13-FA14, U+FA1F, U+FA21, U+FA23, U+FA24, U+FA27-FA29, U+3040-309F, U+30A0-30FF, U+3099-309E, U+FF66-FF9F, U+3007, U+31C0-31E3, U+2F00-2FD5, U+2E80-2EF3; + font-family: "Han Fangsong CNS"; + src: local(STFangsong), local(FangSong); +} +@font-face { + unicode-range: U+4E00-9FFF, U+3400-4DB5, U+20000-2A6D6, U+2A700-2B734, U+2B740-2B81D, U+FA0E-FA0F, U+FA11, U+FA13-FA14, U+FA1F, U+FA21, U+FA23, U+FA24, U+FA27-FA29, U+3040-309F, U+30A0-30FF, U+3099-309E, U+FF66-FF9F, U+3007, U+31C0-31E3, U+2F00-2FD5, U+2E80-2EF3; + font-family: "Han Fangsong GB"; + src: local(STFangsong), local(FangSong); +} +@font-face { + font-family: "Biaodian Sans"; + src: local("Hiragino Sans GB"), local("Heiti SC"), local(STHeiti), local("MS Gothic"), local(SimSun); + unicode-range: U+FF0E; +} +@font-face { + font-family: "Biaodian Serif"; + src: local("Hiragino Mincho ProN"), local("Hiragino Mincho Pro"), local("Songti SC"), local(STSong), local(SimSun); + unicode-range: U+FF0E; +} +@font-face { + font-family: "Biaodian Pro Sans"; + src: local("Hiragino Sans GB"), local("Heiti SC"), local(STHeiti), local("MS Gothic"), local(SimSun); + unicode-range: U+FF0E; +} +@font-face { + font-family: "Biaodian Pro Serif"; + src: local("Hiragino Mincho ProN"), local("Hiragino Mincho Pro"), local("Songti SC"), local(STSong), local(SimSun); + unicode-range: U+FF0E; +} +@font-face { + font-family: "Biaodian Pro Sans CNS"; + src: local("Hiragino Sans GB"), local("Heiti SC"), local(STHeiti), local("MS Gothic"), local(SimSun); + unicode-range: U+FF0E; +} +@font-face { + font-family: "Biaodian Pro Serif CNS"; + src: local("Hiragino Mincho ProN"), local("Hiragino Mincho Pro"), local("Songti SC"), local(STSong), local(SimSun); + unicode-range: U+FF0E; +} +@font-face { + font-family: "Biaodian Pro Sans GB"; + src: local("Hiragino Sans GB"), local("Heiti SC"), local(STHeiti), local("MS Gothic"), local(SimSun); + unicode-range: U+FF0E; +} +@font-face { + font-family: "Biaodian Pro Serif GB"; + src: local("Hiragino Mincho ProN"), local("Hiragino Mincho Pro"), local("Songti SC"), local(STSong), local(SimSun); + unicode-range: U+FF0E; +} +@font-face { + font-family: "Biaodian Sans"; + src: local("Hiragino Sans GB"), local("Heiti SC"), local(STHeiti), local(SimSun); + unicode-range: U+00B7; +} +@font-face { + font-family: "Biaodian Serif"; + src: local("Songti SC"), local(STSong), local("Heiti SC"), local(SimSun); + unicode-range: U+00B7; +} +@font-face { + font-family: "Biaodian Pro Sans"; + src: local("Hiragino Sans GB"), local("Heiti SC"), local(STHeiti), local(SimSun); + unicode-range: U+00B7; +} +@font-face { + font-family: "Biaodian Pro Serif"; + src: local("Songti SC"), local(STSong), local("Heiti SC"), local(SimSun); + unicode-range: U+00B7; +} +@font-face { + font-family: "Biaodian Pro Sans CNS"; + src: local("Hiragino Sans GB"), local("Heiti SC"), local(STHeiti), local(SimSun); + unicode-range: U+00B7; +} +@font-face { + font-family: "Biaodian Pro Serif CNS"; + src: local("Songti SC"), local(STSong), local("Heiti SC"), local(SimSun); + unicode-range: U+00B7; +} +@font-face { + font-family: "Biaodian Pro Sans GB"; + src: local("Hiragino Sans GB"), local("Heiti SC"), local(STHeiti), local(SimSun); + unicode-range: U+00B7; +} +@font-face { + font-family: "Biaodian Pro Serif GB"; + src: local("Songti SC"), local(STSong), local("Heiti SC"), local(SimSun); + unicode-range: U+00B7; +} +@font-face { + font-family: "Biaodian Sans"; + src: url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"), local("Hiragino Sans GB"), local("Hiragino Kaku Gothic ProN"), local("Hiragino Kaku Gothic Pro"), local("Microsoft Yahei"), local(SimSun); + unicode-range: U+2014; +} +@font-face { + font-family: "Biaodian Serif"; + src: url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"), local("Hiragino Mincho ProN"), local("Hiragino Mincho Pro"), local("Songti SC"), local(STSong), local("Microsoft Yahei"), local(SimSun); + unicode-range: U+2014; +} +@font-face { + font-family: "Yakumono Sans"; + src: url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"), local("Hiragino Kaku Gothic ProN"), local("Hiragino Kaku Gothic Pro"), local("Arial Unicode MS"), local("MS Gothic"); + unicode-range: U+2014; +} +@font-face { + font-family: "Yakumono Serif"; + src: url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"), local("Hiragino Mincho ProN"), local("Hiragino Mincho Pro"), local("MS Mincho"), local("Microsoft Yahei"); + unicode-range: U+2014; +} +@font-face { + font-family: "Biaodian Pro Sans"; + src: url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"), local("Hiragino Sans GB"), local("Hiragino Kaku Gothic ProN"), local("Hiragino Kaku Gothic Pro"), local("Microsoft Yahei"), local(SimSun); + unicode-range: U+2014; +} +@font-face { + font-family: "Biaodian Pro Serif"; + src: url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"), local("Hiragino Mincho ProN"), local("Hiragino Mincho Pro"), local("Songti SC"), local(STSong), local("Microsoft Yahei"), local(SimSun); + unicode-range: U+2014; +} +@font-face { + font-family: "Biaodian Pro Sans CNS"; + src: url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"), local("Hiragino Sans GB"), local("Hiragino Kaku Gothic ProN"), local("Hiragino Kaku Gothic Pro"), local("Microsoft Yahei"), local(SimSun); + unicode-range: U+2014; +} +@font-face { + font-family: "Biaodian Pro Serif CNS"; + src: url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"), local("Hiragino Mincho ProN"), local("Hiragino Mincho Pro"), local("Songti SC"), local(STSong), local("Microsoft Yahei"), local(SimSun); + unicode-range: U+2014; +} +@font-face { + font-family: "Biaodian Pro Sans GB"; + src: url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"), local("Hiragino Sans GB"), local("Hiragino Kaku Gothic ProN"), local("Hiragino Kaku Gothic Pro"), local("Microsoft Yahei"), local(SimSun); + unicode-range: U+2014; +} +@font-face { + font-family: "Biaodian Pro Serif GB"; + src: url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"), local("Hiragino Mincho ProN"), local("Hiragino Mincho Pro"), local("Songti SC"), local(STSong), local("Microsoft Yahei"), local(SimSun); + unicode-range: U+2014; +} +@font-face { + font-family: "Biaodian Sans"; + src: url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"), local("Hiragino Sans GB"), local("Hiragino Kaku Gothic ProN"), local("Hiragino Kaku Gothic Pro"), local(Meiryo), local("MS Gothic"), local(SimSun), local(PMingLiU); + unicode-range: U+2026; +} +@font-face { + font-family: "Biaodian Serif"; + src: url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"), local("Hiragino Mincho ProN"), local("Hiragino Mincho Pro"), local("Songti SC"), local("MS Mincho"), local(SimSun), local(PMingLiU); + unicode-range: U+2026; +} +@font-face { + font-family: "Yakumono Sans"; + src: url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"), local("Hiragino Kaku Gothic ProN"), local("Hiragino Kaku Gothic Pro"), local(Meiryo), local("MS Gothic"); + unicode-range: U+2026; +} +@font-face { + font-family: "Yakumono Serif"; + src: url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"), local("Hiragino Mincho ProN"), local("Hiragino Mincho Pro"), local("MS Mincho"); + unicode-range: U+2026; +} +@font-face { + font-family: "Biaodian Pro Sans"; + src: url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"), local("Hiragino Sans GB"), local("Hiragino Kaku Gothic ProN"), local("Hiragino Kaku Gothic Pro"), local(SimSun), local(PMingLiU); + unicode-range: U+2026; +} +@font-face { + font-family: "Biaodian Pro Serif"; + src: url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"), local("Hiragino Mincho ProN"), local("Hiragino Mincho Pro"), local("Songti SC"), local(SimSun), local(PMingLiU); + unicode-range: U+2026; +} +@font-face { + font-family: "Biaodian Pro Sans CNS"; + src: url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"), local("Hiragino Sans GB"), local("Hiragino Kaku Gothic ProN"), local("Hiragino Kaku Gothic Pro"), local(SimSun), local(PMingLiU); + unicode-range: U+2026; +} +@font-face { + font-family: "Biaodian Pro Serif CNS"; + src: url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"), local("Hiragino Mincho ProN"), local("Hiragino Mincho Pro"), local("Songti SC"), local(STSongti), local(SimSun), local(PMingLiU); + unicode-range: U+2026; +} +@font-face { + font-family: "Biaodian Pro Sans GB"; + src: url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"), local("Hiragino Sans GB"), local("Hiragino Kaku Gothic ProN"), local("Hiragino Kaku Gothic Pro"), local(SimSun), local(PMingLiU); + unicode-range: U+2026; +} +@font-face { + font-family: "Biaodian Pro Serif GB"; + src: url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"), local("Hiragino Mincho ProN"), local("Hiragino Mincho Pro"), local("Songti SC"), local(STSongti), local(SimSun), local(PMingLiU); + unicode-range: U+2026; +} +@font-face { + font-family: "Biaodian Pro Sans GB"; + src: local("Hiragino Sans GB"), local("Heiti SC"), local(STHeiti), local(SimSun), local(PMingLiU); + unicode-range: U+201C-201D, U+2018-2019; +} +@font-face { + font-family: "Biaodian Pro Sans GB"; + font-weight: bold; + src: local("Hiragino Sans GB"), local("Heiti SC"), local(STHeiti), local(SimSun), local(PMingLiU); + unicode-range: U+201C-201D, U+2018-2019; +} +@font-face { + font-family: "Biaodian Pro Serif GB"; + src: local("Lisong Pro"), local("Heiti SC"), local(STHeiti), local(SimSun), local(PMingLiU); + unicode-range: U+201C-201D, U+2018-2019; +} +@font-face { + font-family: "Biaodian Pro Serif GB"; + font-weight: bold; + src: local("Lisong Pro"), local("Heiti SC"), local(STHeiti), local(SimSun), local(PMingLiU); + unicode-range: U+201C-201D, U+2018-2019; +} +@font-face { + font-family: "Biaodian Sans"; + src: local(Georgia), local("Times New Roman"), local(Arial), local("Droid Sans Fallback"); + unicode-range: U+25CF; +} +@font-face { + font-family: "Biaodian Serif"; + src: local(Georgia), local("Times New Roman"), local(Arial), local("Droid Sans Fallback"); + unicode-range: U+25CF; +} +@font-face { + font-family: "Biaodian Pro Sans"; + src: local(Georgia), local("Times New Roman"), local(Arial), local("Droid Sans Fallback"); + unicode-range: U+25CF; +} +@font-face { + font-family: "Biaodian Pro Serif"; + src: local(Georgia), local("Times New Roman"), local(Arial), local("Droid Sans Fallback"); + unicode-range: U+25CF; +} +@font-face { + font-family: "Biaodian Pro Sans CNS"; + src: local(Georgia), local("Times New Roman"), local(Arial), local("Droid Sans Fallback"); + unicode-range: U+25CF; +} +@font-face { + font-family: "Biaodian Pro Serif CNS"; + src: local(Georgia), local("Times New Roman"), local(Arial), local("Droid Sans Fallback"); + unicode-range: U+25CF; +} +@font-face { + font-family: "Biaodian Pro Sans GB"; + src: local(Georgia), local("Times New Roman"), local(Arial), local("Droid Sans Fallback"); + unicode-range: U+25CF; +} +@font-face { + font-family: "Biaodian Pro Serif GB"; + src: local(Georgia), local("Times New Roman"), local(Arial), local("Droid Sans Fallback"); + unicode-range: U+25CF; +} +@font-face { + font-family: "Biaodian Pro Sans"; + src: local("Hiragino Kaku Gothic ProN"), local("Hiragino Kaku Gothic Pro"), local("MS Gothic"); + unicode-range: U+3002, U+FF0C, U+3001, U+FF1B, U+FF1A, U+FF1F, U+FF01, U+FF0D, U+FF0F, U+FF3C; +} +@font-face { + font-family: "Biaodian Pro Serif"; + src: local("Hiragino Mincho ProN"), local("Hiragino Mincho Pro"), local("MS Mincho"); + unicode-range: U+3002, U+FF0C, U+3001, U+FF1B, U+FF1A, U+FF1F, U+FF01, U+FF0D, U+FF0F, U+FF3C; +} +@font-face { + font-family: "Biaodian Pro Sans CNS"; + src: local("Heiti TC"), local("Lihei Pro"), local("Microsoft Jhenghei"), local(PMingLiU); + unicode-range: U+3002, U+FF0C, U+3001; +} +@font-face { + font-family: "Biaodian Pro Sans CNS"; + src: local("Hiragino Kaku Gothic ProN"), local("Hiragino Kaku Gothic Pro"), local("Heiti TC"), local("Lihei Pro"), local("Microsoft Jhenghei"), local(PMingLiU), local("MS Gothic"); + unicode-range: U+FF1B, U+FF1A, U+FF1F, U+FF01; +} +@font-face { + font-family: "Biaodian Pro Sans CNS"; + src: local("Hiragino Mincho ProN"), local("Hiragino Mincho Pro"), local("MS Mincho"); + unicode-range: U+FF0D, U+FF0F, U+FF3C; +} +@font-face { + font-family: "Biaodian Pro Serif CNS"; + src: local(STSongti-TC-Regular), local("Lisong Pro"), local("Heiti TC"), local(PMingLiU); + unicode-range: U+3002, U+FF0C, U+3001; +} +@font-face { + font-family: "Biaodian Pro Serif CNS"; + src: local("Hiragino Mincho ProN"), local("Hiragino Mincho Pro"), local(PMingLiU), local("MS Mincho"); + unicode-range: U+FF1B, U+FF1A, U+FF1F, U+FF01, U+FF0D, U+FF0F, U+FF3C; +} +@font-face { + font-family: "Biaodian Pro Sans GB"; + src: local("Hiragino Sans GB"), local("Heiti SC"), local(STHeiti), local("Hiragino Kaku Gothic ProN"), local("Hiragino Kaku Gothic Pro"), local(SimSun), local("MS Gothic"); + unicode-range: U+3002, U+FF0C, U+3001, U+FF1B, U+FF1A, U+FF1F, U+FF01, U+FF0D, U+FF0F, U+FF3C; +} +@font-face { + font-family: "Biaodian Pro Serif GB"; + src: local("Songti SC"), local(STSongti), local("Hiragino Mincho ProN"), local("Hiragino Mincho Pro"), local("Hiragino Sans GB"), local("Heiti SC"), local(STHeiti), local(SimSun), local("MS Mincho"); + unicode-range: U+3002, U+FF0C, U+3001, U+FF1B, U+FF1A, U+FF1F, U+FF01; +} +@font-face { + font-family: "Biaodian Pro Serif GB"; + src: local("Hiragino Mincho ProN"), local("Hiragino Mincho Pro"), local(PMingLiU), local("MS Mincho"); + unicode-range: U+FF0D, U+FF0F, U+FF3C; +} +@font-face { + font-family: "Biaodian Pro Sans"; + src: local("Hiragino Kaku Gothic ProN"), local("Hiragino Kaku Gothic Pro"), local("Yu Gothic"), local(YuGothic), local(SimSun), local(PMingLiU); + unicode-range: U+300C-300F, U+300A-300B, U+3008-3009, U+FF08-FF09, U+3014-3015; +} +@font-face { + font-family: "Biaodian Pro Serif"; + src: local("Hiragino Mincho ProN"), local("Hiragino Mincho Pro"), local("Yu Mincho"), local(YuMincho), local(SimSun), local(PMingLiU); + unicode-range: U+300C-300F, U+300A-300B, U+3008-3009, U+FF08-FF09, U+3014-3015; +} +@font-face { + font-family: "Biaodian Pro Sans CNS"; + src: local("Hiragino Kaku Gothic ProN"), local("Hiragino Kaku Gothic Pro"), local("Yu Gothic"), local(YuGothic), local(SimSun), local(PMingLiU); + unicode-range: U+300C-300F, U+300A-300B, U+3008-3009, U+FF08-FF09, U+3014-3015; +} +@font-face { + font-family: "Biaodian Pro Serif CNS"; + src: local("Hiragino Mincho ProN"), local("Hiragino Mincho Pro"), local("Yu Mincho"), local(YuMincho), local(SimSun), local(PMingLiU); + unicode-range: U+300C-300F, U+300A-300B, U+3008-3009, U+FF08-FF09, U+3014-3015; +} +@font-face { + font-family: "Biaodian Pro Sans GB"; + src: local("Hiragino Kaku Gothic ProN"), local("Hiragino Kaku Gothic Pro"), local("Yu Gothic"), local(YuGothic), local(SimSun), local(PMingLiU); + unicode-range: U+300C-300F, U+300A-300B, U+3008-3009, U+FF08-FF09, U+3014-3015; +} +@font-face { + font-family: "Biaodian Pro Serif GB"; + src: local("Hiragino Mincho ProN"), local("Hiragino Mincho Pro"), local("Yu Mincho"), local(YuMincho), local(SimSun), local(PMingLiU); + unicode-range: U+300C-300F, U+300A-300B, U+3008-3009, U+FF08-FF09, U+3014-3015; +} +@font-face { + font-family: "Biaodian Basic"; + src: url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"); + unicode-range: U+2014, U+2026, U+00B7; +} +@font-face { + font-family: "Biaodian Basic"; + font-weight: bold; + src: url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"); + unicode-range: U+2014, U+2026, U+00B7; +} +@font-face { + font-family: "Biaodian Sans"; + font-weight: bold; + src: url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"); + unicode-range: U+2014, U+2026, U+00B7; +} +@font-face { + font-family: "Biaodian Pro Sans"; + font-weight: bold; + src: url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"); + unicode-range: U+2014, U+2026, U+00B7; +} +@font-face { + font-family: "Biaodian Pro Sans"; + font-weight: bold; + src: url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"); + unicode-range: U+2014, U+2026, U+00B7; +} +@font-face { + font-family: "Biaodian Pro Sans CNS"; + font-weight: bold; + src: url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"); + unicode-range: U+2014, U+2026, U+00B7; +} +@font-face { + font-family: "Biaodian Pro Sans GB"; + font-weight: bold; + src: url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"); + unicode-range: U+2014, U+2026, U+00B7; +} +@font-face { + font-family: "Biaodian Pro Serif"; + font-weight: bold; + src: url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"); + unicode-range: U+2014, U+2026, U+00B7; +} +@font-face { + font-family: "Biaodian Pro Serif CNS"; + font-weight: bold; + src: url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"); + unicode-range: U+2014, U+2026, U+00B7; +} +@font-face { + font-family: "Biaodian Pro Serif GB"; + font-weight: bold; + src: url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"); + unicode-range: U+2014, U+2026, U+00B7; +} +@font-face { + font-family: "Latin Italic Serif"; + src: local("Georgia Italic"), local("Times New Roman Italic"), local(Georgia-Italic), local(TimesNewRomanPS-ItalicMT), local(Times-Italic); +} +@font-face { + font-family: "Latin Italic Serif"; + font-weight: 700; + src: local("Georgia Bold Italic"), local("Times New Roman Bold Italic"), local(Georgia-BoldItalic), local(TimesNewRomanPS-BoldItalicMT), local(Times-Italic); +} +@font-face { + font-family: "Latin Italic Sans"; + src: local("Helvetica Neue Italic"), local("Helvetica Oblique"), local("Arial Italic"), local(HelveticaNeue-Italic), local(Helvetica-LightOblique), local(Arial-ItalicMT); +} +@font-face { + font-family: "Latin Italic Sans"; + font-weight: 700; + src: local("Helvetica Neue Bold Italic"), local("Helvetica Bold Oblique"), local("Arial Bold Italic"), local(HelveticaNeue-BoldItalic), local(Helvetica-BoldOblique), local(Arial-BoldItalicMT); +} +@font-face { + unicode-range: U+0030-0039; + font-family: "Numeral TF Sans"; + src: local(Skia), local("Neutraface 2 Text"), local(Candara), local(Corbel); +} +@font-face { + unicode-range: U+0030-0039; + font-family: "Numeral TF Serif"; + src: local(Georgia), local("Hoefler Text"), local("Big Caslon"); +} +@font-face { + unicode-range: U+0030-0039; + font-family: "Numeral TF Italic Serif"; + src: local("Georgia Italic"), local("Hoefler Text Italic"), local(Georgia-Italic), local(HoeflerText-Italic); +} +@font-face { + unicode-range: U+0030-0039; + font-family: "Numeral LF Sans"; + src: local("Helvetica Neue"), local(Helvetica), local(Arial); +} +@font-face { + unicode-range: U+0030-0039; + font-family: "Numeral LF Italic Sans"; + src: local("Helvetica Neue Italic"), local("Helvetica Oblique"), local("Arial Italic"), local(HelveticaNeue-Italic), local(Helvetica-LightOblique), local(Arial-ItalicMT); +} +@font-face { + unicode-range: U+0030-0039; + font-family: "Numeral LF Italic Sans"; + font-weight: bold; + src: local("Helvetica Neue Bold Italic"), local("Helvetica Bold Oblique"), local("Arial Bold Italic"), local(HelveticaNeue-BoldItalic), local(Helvetica-BoldOblique), local(Arial-BoldItalicMT); +} +@font-face { + unicode-range: U+0030-0039; + font-family: "Numeral LF Serif"; + src: local(Palatino), local("Palatino Linotype"), local("Times New Roman"); +} +@font-face { + unicode-range: U+0030-0039; + font-family: "Numeral LF Italic Serif"; + src: local("Palatino Italic"), local("Palatino Italic Linotype"), local("Times New Roman Italic"), local(Palatino-Italic), local(Palatino-Italic-Linotype), local(TimesNewRomanPS-ItalicMT); +} +@font-face { + unicode-range: U+0030-0039; + font-family: "Numeral LF Italic Serif"; + font-weight: bold; + src: local("Palatino Bold Italic"), local("Palatino Bold Italic Linotype"), local("Times New Roman Bold Italic"), local(Palatino-BoldItalic), local(Palatino-BoldItalic-Linotype), local(TimesNewRomanPS-BoldItalicMT); +} +@font-face { + font-family: "Numeral TF Sans"; + src: local(lying-to-firefox); + unicode-range: U+270C; +} +@font-face { + font-family: "Numeral TF Serif"; + src: local(lying-to-firefox); + unicode-range: U+270C; +} +@font-face { + font-family: "Numeral TF Italic Serif"; + src: local(lying-to-firefox); + unicode-range: U+270C; +} +@font-face { + font-family: "Numeral LF Sans"; + src: local(lying-to-firefox); + unicode-range: U+270C; +} +@font-face { + font-family: "Numeral LF Italic Sans"; + src: local(lying-to-firefox); + unicode-range: U+270C; +} +@font-face { + font-family: "Numeral LF Italic Sans"; + font-weight: bold; + src: local(lying-to-firefox); + unicode-range: U+270C; +} +@font-face { + font-family: "Numeral LF Serif"; + src: local(lying-to-firefox); + unicode-range: U+270C; +} +@font-face { + font-family: "Numeral LF Italic Serif"; + src: local(lying-to-firefox); + unicode-range: U+270C; +} +@font-face { + font-family: "Numeral LF Italic Serif"; + font-weight: bold; + src: local(lying-to-firefox); + unicode-range: U+270C; +} +@font-face { + src: url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"); + unicode-range: U+3105-312D, U+31A0-31BA, U+02D9, U+02CA, U+02C5, U+02C7, U+02CB, U+02EA-02EB, U+030D, U+0358, U+F31B4-F31B7, U+F0061, U+F0065, U+F0069, U+F006F, U+F0075; + font-family: "Zhuyin Kaiti"; +} +@font-face { + unicode-range: U+3105-312D, U+31A0-31BA, U+02D9, U+02CA, U+02C5, U+02C7, U+02CB, U+02EA-02EB, U+030D, U+0358, U+F31B4-F31B7, U+F0061, U+F0065, U+F0069, U+F006F, U+F0075; + font-family: "Zhuyin Heiti"; + src: local("Hiragino Sans GB"), local("Heiti TC"), local("Microsoft Jhenghei"), url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"); +} +@font-face { + font-family: "Zhuyin Heiti"; + src: local("Heiti TC"), local("Microsoft Jhenghei"), url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"); + unicode-range: U+3127; +} +@font-face { + src: url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"); + font-family: "Zhuyin Heiti"; + unicode-range: U+02D9, U+02CA, U+02C5, U+02C7, U+02CB, U+02EA-02EB, U+31B4, U+31B5, U+31B6, U+31B7, U+030D, U+0358, U+F31B4-F31B7, U+F0061, U+F0065, U+F0069, U+F006F, U+F0075; +} +@font-face { + src: url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"); + font-family: "Romanization Sans"; + unicode-range: U+030D, U+0358, U+F31B4-F31B7, U+F0061, U+F0065, U+F0069, U+F006F, U+F0075; +} +html:lang(zh-Latn), +html:lang(ja-Latn), +html:not(:lang(zh)):not(:lang(ja)), +html *:lang(zh-Latn), +html *:lang(ja-Latn), +html *:not(:lang(zh)):not(:lang(ja)), +article strong:lang(zh-Latn), +article strong:lang(ja-Latn), +article strong:not(:lang(zh)):not(:lang(ja)), +article strong *:lang(zh-Latn), +article strong *:lang(ja-Latn), +article strong *:not(:lang(zh)):not(:lang(ja)) { + font-family: "Helvetica Neue", Helvetica, Arial, "Han Heiti", sans-serif; +} +html:lang(zh), +html:lang(zh-Hant), +[lang^="zh"], +[lang*="Hant"], +[lang="zh-TW"], +[lang="zh-HK"], +article strong:lang(zh), +article strong:lang(zh-Hant) { + font-family: "Biaodian Pro Sans CNS", "Helvetica Neue", Helvetica, Arial, "Zhuyin Heiti", "Han Heiti", sans-serif; +} +html:lang(zh).no-unicoderange, +html:lang(zh-Hant).no-unicoderange, +.no-unicoderange [lang^="zh"], +.no-unicoderange [lang*="Hant"], +.no-unicoderange [lang="zh-TW"], +.no-unicoderange [lang="zh-HK"], +.no-unicoderange article strong:lang(zh), +.no-unicoderange article strong:lang(zh-Hant) { + font-family: "Helvetica Neue", Helvetica, Arial, "Han Heiti", sans-serif; +} +html:lang(zh-Hans), +html:lang(zh-CN), +[lang*="Hans"], +[lang="zh-CN"], +article strong:lang(zh-Hans), +article strong:lang(zh-CN) { + font-family: "Biaodian Pro Sans GB", "Helvetica Neue", Helvetica, Arial, "Han Heiti GB", sans-serif; +} +html:lang(zh-Hans).no-unicoderange, +html:lang(zh-CN).no-unicoderange, +.no-unicoderange [lang*="Hans"], +.no-unicoderange [lang="zh-CN"], +.no-unicoderange article strong:lang(zh-Hans), +.no-unicoderange article strong:lang(zh-CN) { + font-family: "Helvetica Neue", Helvetica, Arial, "Han Heiti GB", sans-serif; +} +html:lang(ja), +[lang^="ja"], +article strong:lang(ja) { + font-family: "Yakumono Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; +} +html:lang(ja).no-unicoderange, +.no-unicoderange [lang^="ja"], +.no-unicoderange article strong:lang(ja) { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; +} +article blockquote i:lang(zh-Latn), +article blockquote var:lang(zh-Latn), +article blockquote i:lang(ja-Latn), +article blockquote var:lang(ja-Latn), +article blockquote i:not(:lang(zh)):not(:lang(ja)), +article blockquote var:not(:lang(zh)):not(:lang(ja)), +article blockquote i *:lang(zh-Latn), +article blockquote var *:lang(zh-Latn), +article blockquote i *:lang(ja-Latn), +article blockquote var *:lang(ja-Latn), +article blockquote i *:not(:lang(zh)):not(:lang(ja)), +article blockquote var *:not(:lang(zh)):not(:lang(ja)) { + font-family: "Latin Italic Sans", "Helvetica Neue", Helvetica, Arial, "Han Heiti", sans-serif; +} +article blockquote i:lang(zh), +article blockquote var:lang(zh), +article blockquote i:lang(zh-Hant), +article blockquote var:lang(zh-Hant) { + font-family: "Biaodian Pro Sans CNS", "Latin Italic Sans", "Helvetica Neue", Helvetica, Arial, "Zhuyin Heiti", "Han Heiti", sans-serif; +} +.no-unicoderange article blockquote i:lang(zh), +.no-unicoderange article blockquote var:lang(zh), +.no-unicoderange article blockquote i:lang(zh-Hant), +.no-unicoderange article blockquote var:lang(zh-Hant) { + font-family: "Latin Italic Sans", "Helvetica Neue", Helvetica, Arial, "Han Heiti", sans-serif; +} +.no-unicoderange article blockquote i:lang(zh), +.no-unicoderange article blockquote var:lang(zh), +.no-unicoderange article blockquote i:lang(zh-Hant), +.no-unicoderange article blockquote var:lang(zh-Hant) { + font-family: "Latin Italic Sans", "Helvetica Neue", Helvetica, Arial, "Han Heiti", sans-serif; +} +article blockquote i:lang(zh-Hans), +article blockquote var:lang(zh-Hans), +article blockquote i:lang(zh-CN), +article blockquote var:lang(zh-CN) { + font-family: "Biaodian Pro Sans GB", "Latin Italic Sans", "Helvetica Neue", Helvetica, Arial, "Han Heiti GB", sans-serif; +} +.no-unicoderange article blockquote i:lang(zh-Hans), +.no-unicoderange article blockquote var:lang(zh-Hans), +.no-unicoderange article blockquote i:lang(zh-CN), +.no-unicoderange article blockquote var:lang(zh-CN) { + font-family: "Latin Italic Sans", "Helvetica Neue", Helvetica, Arial, "Han Heiti GB", sans-serif; +} +article blockquote i:lang(ja), +article blockquote var:lang(ja) { + font-family: "Yakumono Sans", "Latin Italic Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; +} +.no-unicoderange article blockquote i:lang(ja), +.no-unicoderange article blockquote var:lang(ja) { + font-family: "Latin Italic Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; +} +article figure blockquote:lang(zh-Latn), +article figure blockquote:lang(ja-Latn), +article figure blockquote:not(:lang(zh)):not(:lang(ja)), +article figure blockquote *:lang(zh-Latn), +article figure blockquote *:lang(ja-Latn), +article figure blockquote *:not(:lang(zh)):not(:lang(ja)) { + font-family: Georgia, "Times New Roman", "Han Songti", cursive, serif; +} +article figure blockquote:lang(zh), +article figure blockquote:lang(zh-Hant) { + font-family: "Biaodian Pro Serif CNS", "Numeral LF Serif", Georgia, "Times New Roman", "Zhuyin Kaiti", "Han Songti", serif; +} +.no-unicoderange article figure blockquote:lang(zh), +.no-unicoderange article figure blockquote:lang(zh-Hant) { + font-family: "Numeral LF Serif", Georgia, "Times New Roman", "Han Songti", serif; +} +article figure blockquote:lang(zh-Hans), +article figure blockquote:lang(zh-CN) { + font-family: "Biaodian Pro Serif GB", "Numeral LF Serif", Georgia, "Times New Roman", "Han Songti GB", serif; +} +.no-unicoderange article figure blockquote:lang(zh-Hans), +.no-unicoderange article figure blockquote:lang(zh-CN) { + font-family: "Numeral LF Serif", Georgia, "Times New Roman", "Han Songti GB", serif; +} +article figure blockquote:lang(ja) { + font-family: "Yakumono Serif", "Numeral LF Serif", Georgia, "Times New Roman", serif; +} +.no-unicoderange article figure blockquote:lang(ja) { + font-family: "Numeral LF Serif", Georgia, "Times New Roman", serif; +} +article blockquote:lang(zh-Latn), +article blockquote:lang(ja-Latn), +article blockquote:not(:lang(zh)):not(:lang(ja)), +article blockquote *:lang(zh-Latn), +article blockquote *:lang(ja-Latn), +article blockquote *:not(:lang(zh)):not(:lang(ja)) { + font-family: Georgia, "Times New Roman", "Han Kaiti", cursive, serif; +} +article blockquote:lang(zh), +article blockquote:lang(zh-Hant) { + font-family: "Biaodian Pro Serif CNS", "Numeral LF Serif", Georgia, "Times New Roman", "Zhuyin Kaiti", "Han Kaiti", cursive, serif; +} +.no-unicoderange article blockquote:lang(zh), +.no-unicoderange article blockquote:lang(zh-Hant) { + font-family: "Numeral LF Serif", Georgia, "Times New Roman", "Han Kaiti", cursive, serif; +} +article blockquote:lang(zh-Hans), +article blockquote:lang(zh-CN) { + font-family: "Biaodian Pro Serif GB", "Numeral LF Serif", Georgia, "Times New Roman", "Han Kaiti GB", cursive, serif; +} +.no-unicoderange article blockquote:lang(zh-Hans), +.no-unicoderange article blockquote:lang(zh-CN) { + font-family: "Numeral LF Serif", Georgia, "Times New Roman", "Han Kaiti GB", cursive, serif; +} +article blockquote:lang(ja) { + font-family: "Yakumono Serif", "Numeral LF Serif", Georgia, "Times New Roman", cursive, serif; +} +.no-unicoderange article blockquote:lang(ja) { + font-family: "Numeral LF Serif", Georgia, "Times New Roman", cursive, serif; +} +i:lang(zh-Latn), +var:lang(zh-Latn), +i:lang(ja-Latn), +var:lang(ja-Latn), +i:not(:lang(zh)):not(:lang(ja)), +var:not(:lang(zh)):not(:lang(ja)), +i *:lang(zh-Latn), +var *:lang(zh-Latn), +i *:lang(ja-Latn), +var *:lang(ja-Latn), +i *:not(:lang(zh)):not(:lang(ja)), +var *:not(:lang(zh)):not(:lang(ja)) { + font-family: "Latin Italic Serif", Georgia, "Times New Roman", "Han Kaiti", cursive, serif; +} +i:lang(zh), +var:lang(zh), +i:lang(zh-Hant), +var:lang(zh-Hant) { + font-family: "Biaodian Pro Serif CNS", "Numeral LF Italic Serif", "Latin Italic Serif", Georgia, "Times New Roman", "Zhuyin Kaiti", "Han Kaiti", cursive, serif; +} +.no-unicoderange i:lang(zh), +.no-unicoderange var:lang(zh), +.no-unicoderange i:lang(zh-Hant), +.no-unicoderange var:lang(zh-Hant) { + font-family: "Numeral LF Italic Serif", "Latin Italic Serif", Georgia, "Times New Roman", "Han Kaiti", cursive, serif; +} +i:lang(zh-Hans), +var:lang(zh-Hans), +i:lang(zh-CN), +var:lang(zh-CN) { + font-family: "Biaodian Pro Serif GB", "Numeral LF Italic Serif", "Latin Italic Serif", Georgia, "Times New Roman", "Han Kaiti GB", cursive, serif; +} +.no-unicoderange i:lang(zh-Hans), +.no-unicoderange var:lang(zh-Hans), +.no-unicoderange i:lang(zh-CN), +.no-unicoderange var:lang(zh-CN) { + font-family: "Numeral LF Italic Serif", "Latin Italic Serif", Georgia, "Times New Roman", "Han Kaiti GB", cursive, serif; +} +i:lang(ja), +var:lang(ja) { + font-family: "Yakumono Serif", "Numeral LF Italic Serif", "Latin Italic Serif", Georgia, "Times New Roman", cursive, serif; +} +.no-unicoderange i:lang(ja), +.no-unicoderange var:lang(ja) { + font-family: "Numeral LF Italic Serif", "Latin Italic Serif", Georgia, "Times New Roman", cursive, serif; +} +code:lang(zh-Latn), +kbd:lang(zh-Latn), +samp:lang(zh-Latn), +pre:lang(zh-Latn), +code:lang(ja-Latn), +kbd:lang(ja-Latn), +samp:lang(ja-Latn), +pre:lang(ja-Latn), +code:not(:lang(zh)):not(:lang(ja)), +kbd:not(:lang(zh)):not(:lang(ja)), +samp:not(:lang(zh)):not(:lang(ja)), +pre:not(:lang(zh)):not(:lang(ja)), +code *:lang(zh-Latn), +kbd *:lang(zh-Latn), +samp *:lang(zh-Latn), +pre *:lang(zh-Latn), +code *:lang(ja-Latn), +kbd *:lang(ja-Latn), +samp *:lang(ja-Latn), +pre *:lang(ja-Latn), +code *:not(:lang(zh)):not(:lang(ja)), +kbd *:not(:lang(zh)):not(:lang(ja)), +samp *:not(:lang(zh)):not(:lang(ja)), +pre *:not(:lang(zh)):not(:lang(ja)) { + font-family: Menlo, Consolas, Courier, "Han Heiti", monospace, monospace, sans-serif; +} +code:lang(zh), +kbd:lang(zh), +samp:lang(zh), +pre:lang(zh), +code:lang(zh-Hant), +kbd:lang(zh-Hant), +samp:lang(zh-Hant), +pre:lang(zh-Hant) { + font-family: "Biaodian Pro Sans CNS", Menlo, Consolas, Courier, "Zhuyin Heiti", "Han Heiti", monospace, monospace, sans-serif; +} +.no-unicoderange code:lang(zh), +.no-unicoderange kbd:lang(zh), +.no-unicoderange samp:lang(zh), +.no-unicoderange pre:lang(zh), +.no-unicoderange code:lang(zh-Hant), +.no-unicoderange kbd:lang(zh-Hant), +.no-unicoderange samp:lang(zh-Hant), +.no-unicoderange pre:lang(zh-Hant) { + font-family: Menlo, Consolas, Courier, "Han Heiti", monospace, monospace, sans-serif; +} +code:lang(zh-Hans), +kbd:lang(zh-Hans), +samp:lang(zh-Hans), +pre:lang(zh-Hans), +code:lang(zh-CN), +kbd:lang(zh-CN), +samp:lang(zh-CN), +pre:lang(zh-CN) { + font-family: "Biaodian Pro Sans GB", Menlo, Consolas, Courier, "Han Heiti GB", monospace, monospace, sans-serif; +} +.no-unicoderange code:lang(zh-Hans), +.no-unicoderange kbd:lang(zh-Hans), +.no-unicoderange samp:lang(zh-Hans), +.no-unicoderange pre:lang(zh-Hans), +.no-unicoderange code:lang(zh-CN), +.no-unicoderange kbd:lang(zh-CN), +.no-unicoderange samp:lang(zh-CN), +.no-unicoderange pre:lang(zh-CN) { + font-family: Menlo, Consolas, Courier, "Han Heiti GB", monospace, monospace, sans-serif; +} +code:lang(ja), +kbd:lang(ja), +samp:lang(ja), +pre:lang(ja) { + font-family: "Yakumono Sans", Menlo, Consolas, Courier, monospace, monospace, sans-serif; +} +.no-unicoderange code:lang(ja), +.no-unicoderange kbd:lang(ja), +.no-unicoderange samp:lang(ja), +.no-unicoderange pre:lang(ja) { + font-family: Menlo, Consolas, Courier, monospace, monospace, sans-serif; +} +html, +.no-unicoderange h-char.bd-liga, +.no-unicoderange h-char[unicode="b7"], +ruby h-zhuyin, +h-ruby h-zhuyin, +ruby h-zhuyin h-diao, +h-ruby h-zhuyin h-diao, +ruby.romanization rt, +h-ruby.romanization rt, +ruby [annotation] rt, +h-ruby [annotation] rt { + -moz-font-feature-settings: "liga"; + -ms-font-feature-settings: "liga"; + -webkit-font-feature-settings: "liga"; + font-feature-settings: "liga"; +} +html, +[lang^="zh"], +[lang*="Hant"], +[lang="zh-TW"], +[lang="zh-HK"], +[lang*="Hans"], +[lang="zh-CN"], +article strong, +code, +kbd, +samp, +pre, +article blockquote i, +article blockquote var { + -moz-font-feature-settings: "liga=1, locl=0"; + -ms-font-feature-settings: "liga", "locl" 0; + -webkit-font-feature-settings: "liga", "locl" 0; + font-feature-settings: "liga", "locl" 0; +} +.no-unicoderange h-char.bd-cop:lang(zh-Hant), +.no-unicoderange h-char.bd-cop:lang(zh-TW), +.no-unicoderange h-char.bd-cop:lang(zh-HK) { + font-family: -apple-system, "Han Heiti CNS"; +} +.no-unicoderange h-char.bd-liga, +.no-unicoderange h-char[unicode="b7"] { + font-family: "Biaodian Basic", "Han Heiti"; +} +.no-unicoderange h-char[unicode="2018"]:lang(zh-Hans), +.no-unicoderange h-char[unicode="2019"]:lang(zh-Hans), +.no-unicoderange h-char[unicode="201c"]:lang(zh-Hans), +.no-unicoderange h-char[unicode="201d"]:lang(zh-Hans), +.no-unicoderange h-char[unicode="2018"]:lang(zh-CN), +.no-unicoderange h-char[unicode="2019"]:lang(zh-CN), +.no-unicoderange h-char[unicode="201c"]:lang(zh-CN), +.no-unicoderange h-char[unicode="201d"]:lang(zh-CN) { + font-family: "Han Heiti GB"; +} +i, +var { + font-style: inherit; +} +.no-unicoderange ruby h-zhuyin, +.no-unicoderange h-ruby h-zhuyin, +.no-unicoderange ruby h-zhuyin h-diao, +.no-unicoderange h-ruby h-zhuyin h-diao { + font-family: "Zhuyin Kaiti", cursive, serif; +} +ruby h-diao, +h-ruby h-diao { + font-family: "Zhuyin Kaiti", cursive, serif; +} +ruby.romanization rt, +h-ruby.romanization rt, +ruby [annotation] rt, +h-ruby [annotation] rt { + font-family: "Romanization Sans", "Helvetica Neue", Helvetica, Arial, "Han Heiti", sans-serif; +} +.no-kaiti i, +.no-kaiti var { + padding-bottom: .05em; + border-bottom: 3px double #d3d3d3; +} +article h1 + blockquote, +article h2 + blockquote, +article h3 + blockquote, +article h4 + blockquote, +article h5 + blockquote, +article h6 + blockquote, +article h1 + p, +article h2 + p, +article h3 + p, +article h4 + p, +article h5 + p, +article h6 + p, +article h1 + ol, +article h2 + ol, +article h3 + ol, +article h4 + ol, +article h5 + ol, +article h6 + ol, +article h1 + ul, +article h2 + ul, +article h3 + ul, +article h4 + ul, +article h5 + ul, +article h6 + ul, +article h1 + h6, +article h2 + h6, +article h3 + h6, +article h4 + h6, +article h5 + h6, +article h6 + h6, +article h1 + section > h6:first-child, +article h2 + section > h6:first-child, +article h3 + section > h6:first-child, +article h4 + section > h6:first-child, +article h5 + section > h6:first-child, +article h6 + section > h6:first-child, +article h1 + section > p:first-child, +article h2 + section > p:first-child, +article h3 + section > p:first-child, +article h4 + section > p:first-child, +article h5 + section > p:first-child, +article h6 + section > p:first-child, +article h1 + section > ol:first-child, +article h2 + section > ol:first-child, +article h3 + section > ol:first-child, +article h4 + section > ol:first-child, +article h5 + section > ol:first-child, +article h6 + section > ol:first-child, +article h1 + section > ul:first-child, +article h2 + section > ul:first-child, +article h3 + section > ul:first-child, +article h4 + section > ul:first-child, +article h5 + section > ul:first-child, +article h6 + section > ul:first-child, +article h1 + section > blockquote:first-child, +article h2 + section > blockquote:first-child, +article h3 + section > blockquote:first-child, +article h4 + section > blockquote:first-child, +article h5 + section > blockquote:first-child, +article h6 + section > blockquote:first-child, +article h1 + h5, +article h2 + h5, +article h3 + h5, +article h4 + h5, +article h5 + h5, +article h1 + section > h5:first-child, +article h2 + section > h5:first-child, +article h3 + section > h5:first-child, +article h4 + section > h5:first-child, +article h5 + section > h5:first-child, +article h1 + h4, +article h2 + h4, +article h3 + h4, +article h4 + h4, +article h1 + section > h4:first-child, +article h2 + section > h4:first-child, +article h3 + section > h4:first-child, +article h4 + section > h4:first-child, +article h1 + h3, +article h2 + h3, +article h3 + h3, +article h1 + section > h3:first-child, +article h2 + section > h3:first-child, +article h3 + section > h3:first-child, +article h1 + h2, +article h2 + h2, +article h1 + section > h2:first-child, +article h2 + section > h2:first-child { + margin-top: -1em; +} +article { + line-height: 1.7; +} +article { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} +article p, +article li { + text-align: justify; + text-justify: inter-ideograph; +} +p.poem-like, +.poem-like p { + margin-left: 2em; +} +@media only screen and (max-width: 480px) { + p.poem-like, + .poem-like p { + margin-left: 1em; + } +} +article blockquote { + margin-right: 0; +} +@media only screen and (max-width: 480px) { + article blockquote { + margin-left: 1em; + } +} +figure blockquote { + margin: 0; +} +blockquote blockquote { + margin-left: 1em; + margin-right: 1em; +} +article blockquote blockquote { + margin-right: 0; +} +@media only screen and (max-width: 480px) { + blockquote, + figure { + margin-left: 1em; + margin-right: 1em; + } +} +h-hws, +h-hws[hidden] { + display: inline; + visibility: hidden; + font: .89em Arial; +} +code h-hws, +code h-hws[hidden], +kbd h-hws, +kbd h-hws[hidden], +samp h-hws, +samp h-hws[hidden], +pre h-hws, +pre h-hws[hidden], +h-hws.quote-inner, +h-hws[hidden].quote-inner, +h-hws.quote-outer:lang(zh-Hans), +h-hws[hidden].quote-outer:lang(zh-Hans), +h-hws.quote-outer:lang(zh-CN), +h-hws[hidden].quote-outer:lang(zh-CN) { + display: none; +} +@font-face { + src: url("./font/han-space.woff?v3.3.0") format("woff"), url("./font/han-space.otf?v3.3.0") format("opentype"); + font-family: "Han Space"; + unicode-range: U+20; +} +h-char.bd-hangable:lang(zh) h-cs, +h-char.bd-hangable:lang(zh-Hant) h-cs, +h-char.bd-hangable:lang(zh-TW) h-cs, +h-char.bd-hangable:lang(zh-HK) h-cs, +h-cs, +h-char.bd-hangable:lang(zh) h-cs[hidden], +h-char.bd-hangable:lang(zh-Hant) h-cs[hidden], +h-char.bd-hangable:lang(zh-TW) h-cs[hidden], +h-char.bd-hangable:lang(zh-HK) h-cs[hidden], +h-cs[hidden] { + display: inline; + visibility: inherit; + font-family: inherit; + font-size: inherit; +} +h-cs.hangable-outer, +h-cs.hangable-outer[hidden] { + display: inline; + font: 1em "Han Space"; +} +h-cs.hangable-outer:lang(zh-Hant), +h-cs.hangable-outer[hidden]:lang(zh-Hant), +h-cs.hangable-outer:lang(zh-TW), +h-cs.hangable-outer[hidden]:lang(zh-TW), +h-cs.hangable-outer:lang(zh-HK), +h-cs.hangable-outer[hidden]:lang(zh-HK) { + display: none; +} +h-char.bd-hangable:lang(zh-Hans), +h-char.bd-hangable:lang(zh-CN), +h-char.bd-hangable:lang(ja) { + position: relative; +} +h-char.bd-hangable:lang(zh-Hans):after, +h-char.bd-hangable:lang(zh-CN):after, +h-char.bd-hangable:lang(ja):after { + display: none !important; +} +h-char.bd-hangable:lang(zh-Hans):before, +h-char.bd-hangable:lang(zh-CN):before, +h-char.bd-hangable:lang(ja):before { + display: inline !important; + content: " "; + font: 1em "Han Space", Menlo, Consolas, Courier; +} +h-char.bd-hangable:lang(zh-Hans) > h-inner, +h-char.bd-hangable:lang(zh-CN) > h-inner, +h-char.bd-hangable:lang(ja) > h-inner { + -moz-text-emphasis: none; + -webkit-text-emphasis: none; + text-emphasis: none; + font-style: normal; + font-weight: normal; + line-height: normal; + text-decoration: none; + text-indent: 0; + position: absolute; + left: 0; + top: 0; + display: inline-block; + line-height: 1.1; +} +ruby h-char.bd-hangable:lang(zh-Hans) > h-inner, +ruby h-char.bd-hangable:lang(zh-CN) > h-inner, +ruby h-char.bd-hangable:lang(ja) > h-inner, +h-ru h-char.bd-hangable:lang(zh-Hans) > h-inner, +h-ru h-char.bd-hangable:lang(zh-CN) > h-inner, +h-ru h-char.bd-hangable:lang(ja) > h-inner { + position: relative; +} +h-char.bd-jiya.bd-open:before, +h-char.bd-jiya.bd-end:after, +h-cs, +h-cs[hidden] { + display: none; + visibility: hidden; + content: " "; + font: .825em Courier; + letter-spacing: 0; + white-space: normal; +} +h-cs.jinze-outer, +h-cs.jinze-outer[hidden] { + display: inline; +} +h-char.bd-jiya.bd-open > h-inner { + margin-left: -.5em; +} +h-char.bd-jiya.bd-close > h-inner, +h-char.bd-jiya.bd-cop > h-inner, +h-char.bd-jiya[unicode="ff0e"] > h-inner { + letter-spacing: -.5em; +} +h-char.bd-jiya.bd-open:before, +h-char.bd-jiya.bd-close:after, +h-char.bd-jiya.bd-cop:after, +h-char.bd-jiya[unicode="ff0e"]:after { + display: inline; +} +h-char.bd-jiya.bd-cop:lang(zh-Hant):after, +h-char.bd-jiya.bd-cop:lang(zh-TW):after, +h-char.bd-jiya.bd-cop:lang(zh-HK):after { + display: none; +} +h-char.bd-jiya.bd-cop:lang(zh-Hant) > h-inner, +h-char.bd-jiya.bd-cop:lang(zh-TW) > h-inner, +h-char.bd-jiya.bd-cop:lang(zh-HK) > h-inner { + letter-spacing: inherit; +} +h-char.bd-consecutive.bd-end:not(.end-portion):after, +h-char.bd-consecutive.bd-open[prev="bd-open"]:before, +h-cs.jiya-outer.bd-end:not(.end-portion) { + display: none; +} +h-cs.jiya-outer.bd-end[next="bd-open"] { + display: inline; +} +h-char.bd-consecutive.bd-open[prev*="bd-cop"]:lang(zh-Hant):before, +h-char.bd-consecutive.bd-open[prev*="bd-cop"]:lang(zh-TW):before, +h-char.bd-consecutive.bd-open[prev*="bd-cop"]:lang(zh-HK):before { + display: none; +} +h-cs.jiya-outer[prev*="bd-cop"]:lang(zh-Hant), +h-cs.jiya-outer.bd-end:lang(zh-Hant), +h-cs.jiya-outer[prev*="bd-cop"]:lang(zh-TW), +h-cs.jiya-outer.bd-end:lang(zh-TW), +h-cs.jiya-outer[prev*="bd-cop"]:lang(zh-HK), +h-cs.jiya-outer.bd-end:lang(zh-HK) { + display: none; +} +h-char.bd-consecutive[unicode="b7"]:not(.end-portion), +h-char.bd-consecutive[unicode="30fb"]:not(.end-portion) { + letter-spacing: -.5em; +} +h-char.bd-consecutive.bd-liga:not(.end-portion) { + margin-right: -.25em; +} +h-char[display-as] { + position: relative; + display: inline-block; +} +h-char[display-as] h-inner { + color: transparent; +} +h-char[display-as]:after { + position: absolute; + left: 0; + display: inline-block; + content: attr(display-as); +} +h-char[display-as].comb-liga:after { + font-family: "Romanization Sans", "Zhuyin Kaiti"; +} diff --git a/lib/Han/dist/han.js b/lib/Han/dist/han.js new file mode 100644 index 0000000..75976c6 --- /dev/null +++ b/lib/Han/dist/han.js @@ -0,0 +1,3005 @@ +/*! + * 漢字標準格式 v3.3.0 | MIT License | css.hanzi.co + * Han.css: the CSS typography framework optimised for Hanzi + */ + +void function( global, factory ) { + + // CommonJS + if ( typeof module === 'object' && typeof module.exports === 'object' ) { + module.exports = factory( global, true ) + // AMD + } else if ( typeof define === 'function' && define.amd ) { + define(function() { return factory( global, true ) }) + // Global namespace + } else { + factory( global ) + } + +}( typeof window !== 'undefined' ? window : this, function( window, noGlobalNS ) { + +'use strict' + +var document = window.document + +var root = document.documentElement + +var body = document.body + +var VERSION = '3.3.0' + +var ROUTINE = [ + // Initialise the condition with feature-detecting + // classes (Modernizr-alike), binding onto the root + // element, possibly ``. + 'initCond', + + // Address element normalisation + 'renderElem', + + // Handle Biaodian + /* 'jinzify', */ + 'renderJiya', + 'renderHanging', + + // Address Biaodian correction + 'correctBiaodian', + + // Address Hanzi and Western script mixed spacing + 'renderHWS', + + // Address presentational correction to combining ligatures + 'substCombLigaWithPUA' + + // Address semantic correction to inaccurate characters + // **Note:** inactivated by default + /* 'substInaccurateChar', */ +] + +// Define Han +var Han = function( context, condition ) { + return new Han.fn.init( context, condition ) +} + +var init = function() { + if ( arguments[ 0 ] ) { + this.context = arguments[ 0 ] + } + if ( arguments[ 1 ] ) { + this.condition = arguments[ 1 ] + } + return this +} + +Han.version = VERSION + +Han.fn = Han.prototype = { + version: VERSION, + + constructor: Han, + + // Body as the default target context + context: body, + + // Root element as the default condition + condition: root, + + // Default rendering routine + routine: ROUTINE, + + init: init, + + setRoutine: function( routine ) { + if ( Array.isArray( routine )) { + this.routine = routine + } + return this + }, + + // Note that the routine set up here will execute + // only once. The method won't alter the routine in + // the instance or in the prototype chain. + render: function( routine ) { + var it = this + var routine = Array.isArray( routine ) + ? routine + : this.routine + + routine + .forEach(function( method ) { + if ( + typeof method === 'string' && + typeof it[ method ] === 'function' + ) { + it[ method ]() + } else if ( + Array.isArray( method ) && + typeof it[ method[0] ] === 'function' + ) { + it[ method.shift() ].apply( it, method ) + } + }) + return this + } +} + +Han.fn.init.prototype = Han.fn + +/** + * Shortcut for `render()` under the default + * situation. + * + * Once initialised, replace `Han.init` with the + * instance for future usage. + */ +Han.init = function() { + return Han.init = Han().render() +} + +var UNICODE = { + /** + * Western punctuation (西文標點符號) + */ + punct: { + base: '[\u2026,.;:!?\u203D_]', + sing: '[\u2010-\u2014\u2026]', + middle: '[\\\/~\\-&\u2010-\u2014_]', + open: '[\'"‘“\\(\\[\u00A1\u00BF\u2E18\u00AB\u2039\u201A\u201C\u201E]', + close: '[\'"”’\\)\\]\u00BB\u203A\u201B\u201D\u201F]', + end: '[\'"”’\\)\\]\u00BB\u203A\u201B\u201D\u201F\u203C\u203D\u2047-\u2049,.;:!?]', + }, + + /** + * CJK biaodian (CJK標點符號) + */ + biaodian: { + base: '[︰.、,。:;?!ー]', + liga: '[—…⋯]', + middle: '[·\/-゠\uFF06\u30FB\uFF3F]', + open: '[「『《〈(〔[{【〖]', + close: '[」』》〉)〕]}】〗]', + end: '[」』》〉)〕]}】〗︰.、,。:;?!ー]' + }, + + /** + * CJK-related blocks (CJK相關字符區段) + * + * 1. 中日韓統一意音文字:[\u4E00-\u9FFF] + Basic CJK unified ideographs + * 2. 擴展-A區:[\u3400-\u4DB5] + Extended-A + * 3. 擴展-B區:[\u20000-\u2A6D6]([\uD840-\uD869][\uDC00-\uDED6]) + Extended-B + * 4. 擴展-C區:[\u2A700-\u2B734](\uD86D[\uDC00-\uDF3F]|[\uD86A-\uD86C][\uDC00-\uDFFF]|\uD869[\uDF00-\uDFFF]) + Extended-C + * 5. 擴展-D區:[\u2B740-\u2B81D](急用漢字,\uD86D[\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1F]) + Extended-D + * 6. 擴展-E區:[\u2B820-\u2F7FF](暫未支援) + Extended-E (not supported yet) + * 7. 擴展-F區(暫未支援) + Extended-F (not supported yet) + * 8. 筆畫區:[\u31C0-\u31E3] + Strokes + * 9. 意音數字「〇」:[\u3007] + Ideographic number zero + * 10. 相容意音文字及補充:[\uF900-\uFAFF][\u2F800-\u2FA1D](不使用) + Compatibility ideograph and supplement (not supported) + + 12 exceptions: + [\uFA0E\uFA0F\uFA11\uFA13\uFA14\uFA1F\uFA21\uFA23\uFA24\uFA27-\uFA29] + + https://zh.wikipedia.org/wiki/中日韓統一表意文字#cite_note-1 + + * 11. 康熙字典及簡化字部首:[\u2F00-\u2FD5\u2E80-\u2EF3] + Kangxi and supplement radicals + * 12. 意音文字描述字元:[\u2FF0-\u2FFA] + Ideographic description characters + */ + hanzi: { + base: '[\u4E00-\u9FFF\u3400-\u4DB5\u31C0-\u31E3\u3007\uFA0E\uFA0F\uFA11\uFA13\uFA14\uFA1F\uFA21\uFA23\uFA24\uFA27-\uFA29]|[\uD800-\uDBFF][\uDC00-\uDFFF]', + desc: '[\u2FF0-\u2FFA]', + radical: '[\u2F00-\u2FD5\u2E80-\u2EF3]' + }, + + /** + * Latin script blocks (拉丁字母區段) + * + * 1. 基本拉丁字母:A-Za-z + Basic Latin + * 2. 阿拉伯數字:0-9 + Digits + * 3. 補充-1:[\u00C0-\u00FF] + Latin-1 supplement + * 4. 擴展-A區:[\u0100-\u017F] + Extended-A + * 5. 擴展-B區:[\u0180-\u024F] + Extended-B + * 5. 擴展-C區:[\u2C60-\u2C7F] + Extended-C + * 5. 擴展-D區:[\uA720-\uA7FF] + Extended-D + * 6. 附加區:[\u1E00-\u1EFF] + Extended additional + * 7. 變音組字符:[\u0300-\u0341\u1DC0-\u1DFF] + Combining diacritical marks + */ + latin: { + base: '[A-Za-z0-9\u00C0-\u00FF\u0100-\u017F\u0180-\u024F\u2C60-\u2C7F\uA720-\uA7FF\u1E00-\u1EFF]', + combine: '[\u0300-\u0341\u1DC0-\u1DFF]' + }, + + /** + * Elli̱niká (Greek) script blocks (希臘字母區段) + * + * 1. 希臘字母及擴展:[\u0370–\u03FF\u1F00-\u1FFF] + Basic Greek & Greek Extended + * 2. 阿拉伯數字:0-9 + Digits + * 3. 希臘字母變音組字符:[\u0300-\u0345\u1DC0-\u1DFF] + Combining diacritical marks + */ + ellinika: { + base: '[0-9\u0370-\u03FF\u1F00-\u1FFF]', + combine: '[\u0300-\u0345\u1DC0-\u1DFF]' + }, + + /** + * Kirillica (Cyrillic) script blocks (西里爾字母區段) + * + * 1. 西里爾字母及補充:[\u0400-\u0482\u048A-\u04FF\u0500-\u052F] + Basic Cyrillic and supplement + * 2. 擴展B區:[\uA640-\uA66E\uA67E-\uA697] + Extended-B + * 3. 阿拉伯數字:0-9 + Digits + * 4. 西里爾字母組字符:[\u0483-\u0489\u2DE0-\u2DFF\uA66F-\uA67D\uA69F](位擴展A、B區) + Cyrillic combining diacritical marks (in extended-A, B) + */ + kirillica: { + base: '[0-9\u0400-\u0482\u048A-\u04FF\u0500-\u052F\uA640-\uA66E\uA67E-\uA697]', + combine: '[\u0483-\u0489\u2DE0-\u2DFF\uA66F-\uA67D\uA69F]' + }, + + /** + * Kana (假名) + * + * 1. 日文假名:[\u30A2\u30A4\u30A6\u30A8\u30AA-\u30FA\u3042\u3044\u3046\u3048\u304A-\u3094\u309F\u30FF] + Japanese Kana + * 2. 假名補充[\u1B000\u1B001](\uD82C[\uDC00-\uDC01]) + Kana supplement + * 3. 日文假名小寫:[\u3041\u3043\u3045\u3047\u3049\u30A1\u30A3\u30A5\u30A7\u30A9\u3063\u3083\u3085\u3087\u308E\u3095\u3096\u30C3\u30E3\u30E5\u30E7\u30EE\u30F5\u30F6\u31F0-\u31FF] + Japanese small Kana + * 4. 假名組字符:[\u3099-\u309C] + Kana combining characters + * 5. 半形假名:[\uFF66-\uFF9F] + Halfwidth Kana + * 6. 符號:[\u309D\u309E\u30FB-\u30FE] + Marks + */ + kana: { + base: '[\u30A2\u30A4\u30A6\u30A8\u30AA-\u30FA\u3042\u3044\u3046\u3048\u304A-\u3094\u309F\u30FF]|\uD82C[\uDC00-\uDC01]', + small: '[\u3041\u3043\u3045\u3047\u3049\u30A1\u30A3\u30A5\u30A7\u30A9\u3063\u3083\u3085\u3087\u308E\u3095\u3096\u30C3\u30E3\u30E5\u30E7\u30EE\u30F5\u30F6\u31F0-\u31FF]', + combine: '[\u3099-\u309C]', + half: '[\uFF66-\uFF9F]', + mark: '[\u30A0\u309D\u309E\u30FB-\u30FE]' + }, + + /** + * Eonmun (Hangul, 諺文) + * + * 1. 諺文音節:[\uAC00-\uD7A3] + Eonmun (Hangul) syllables + * 2. 諺文字母:[\u1100-\u11FF\u314F-\u3163\u3131-\u318E\uA960-\uA97C\uD7B0-\uD7FB] + Eonmun (Hangul) letters + * 3. 半形諺文字母:[\uFFA1-\uFFDC] + Halfwidth Eonmun (Hangul) letters + */ + eonmun: { + base: '[\uAC00-\uD7A3]', + letter: '[\u1100-\u11FF\u314F-\u3163\u3131-\u318E\uA960-\uA97C\uD7B0-\uD7FB]', + half: '[\uFFA1-\uFFDC]' + }, + + /** + * Zhuyin (注音符號, Mandarin & Dialect Phonetic Symbols) + * + * 1. 國語注音、方言音符號:[\u3105-\u312D][\u31A0-\u31BA] + Bopomofo phonetic symbols + * 2. 平上去聲調號:[\u02D9\u02CA\u02C5\u02C7\u02EA\u02EB\u02CB] (**註:**國語三聲包含乙個不合規範的符號) + Level, rising, departing tones + * 3. 入聲調號:[\u31B4-\u31B7][\u0358\u030d]? + Checked (entering) tones + */ + zhuyin: { + base: '[\u3105-\u312D\u31A0-\u31BA]', + initial: '[\u3105-\u3119\u312A-\u312C\u31A0-\u31A3]', + medial: '[\u3127-\u3129]', + final: '[\u311A-\u3129\u312D\u31A4-\u31B3\u31B8-\u31BA]', + tone: '[\u02D9\u02CA\u02C5\u02C7\u02CB\u02EA\u02EB]', + checked: '[\u31B4-\u31B7][\u0358\u030d]?' + } +} + +var TYPESET = (function() { + var rWhite = '[\\x20\\t\\r\\n\\f]' + // Whitespace characters + // http://www.w3.org/TR/css3-selectors/#whitespace + + var rPtOpen = UNICODE.punct.open + var rPtClose = UNICODE.punct.close + var rPtEnd = UNICODE.punct.end + var rPtMid = UNICODE.punct.middle + var rPtSing = UNICODE.punct.sing + var rPt = rPtOpen + '|' + rPtEnd + '|' + rPtMid + + var rBDOpen = UNICODE.biaodian.open + var rBDClose = UNICODE.biaodian.close + var rBDEnd = UNICODE.biaodian.end + var rBDMid = UNICODE.biaodian.middle + var rBDLiga = UNICODE.biaodian.liga + '{2}' + var rBD = rBDOpen + '|' + rBDEnd + '|' + rBDMid + + var rKana = UNICODE.kana.base + UNICODE.kana.combine + '?' + var rKanaS = UNICODE.kana.small + UNICODE.kana.combine + '?' + var rKanaH = UNICODE.kana.half + var rEon = UNICODE.eonmun.base + '|' + UNICODE.eonmun.letter + var rEonH = UNICODE.eonmun.half + + var rHan = UNICODE.hanzi.base + '|' + UNICODE.hanzi.desc + '|' + UNICODE.hanzi.radical + '|' + rKana + + var rCbn = UNICODE.ellinika.combine + var rLatn = UNICODE.latin.base + rCbn + '*' + var rGk = UNICODE.ellinika.base + rCbn + '*' + + var rCyCbn = UNICODE.kirillica.combine + var rCy = UNICODE.kirillica.base + rCyCbn + '*' + + var rAlph = rLatn + '|' + rGk + '|' + rCy + + // For words like `it's`, `Jones’s` or `'99` + var rApo = '[\u0027\u2019]' + var rChar = rHan + '|(?:' + rAlph + '|' + rApo + ')+' + + var rZyS = UNICODE.zhuyin.initial + var rZyJ = UNICODE.zhuyin.medial + var rZyY = UNICODE.zhuyin.final + var rZyD = UNICODE.zhuyin.tone + '|' + UNICODE.zhuyin.checked + + return { + /* Character-level selector (字級選擇器) + */ + char: { + punct: { + all: new RegExp( '(' + rPt + ')', 'g' ), + open: new RegExp( '(' + rPtOpen + ')', 'g' ), + end: new RegExp( '(' + rPtEnd + ')', 'g' ), + sing: new RegExp( '(' + rPtSing + ')', 'g' ) + }, + + biaodian: { + all: new RegExp( '(' + rBD + ')', 'g' ), + open: new RegExp( '(' + rBDOpen + ')', 'g' ), + close: new RegExp( '(' + rBDClose + ')', 'g' ), + end: new RegExp( '(' + rBDEnd + ')', 'g' ), + liga: new RegExp( '(' + rBDLiga + ')', 'g' ) + }, + + hanzi: new RegExp( '(' + rHan + ')', 'g' ), + + latin: new RegExp( '(' + rLatn + ')', 'ig' ), + ellinika: new RegExp( '(' + rGk + ')', 'ig' ), + kirillica: new RegExp( '(' + rCy + ')', 'ig' ), + + kana: new RegExp( '(' + rKana + '|' + rKanaS + '|' + rKanaH + ')', 'g' ), + eonmun: new RegExp( '(' + rEon + '|' + rEonH + ')', 'g' ) + }, + + /* Word-level selectors (詞級選擇器) + */ + group: { + biaodian: [ + new RegExp( '((' + rBD + '){2,})', 'g' ), + new RegExp( '(' + rBDLiga + rBDOpen + ')', 'g' ) + ], + punct: null, + hanzi: new RegExp( '(' + rHan + ')+', 'g' ), + western: new RegExp( '(' + rLatn + '|' + rGk + '|' + rCy + '|' + rPt + ')+', 'ig' ), + kana: new RegExp( '(' + rKana + '|' + rKanaS + '|' + rKanaH + ')+', 'g' ), + eonmun: new RegExp( '(' + rEon + '|' + rEonH + '|' + rPt + ')+', 'g' ) + }, + + /* Punctuation Rules (禁則) + */ + jinze: { + hanging: new RegExp( rWhite + '*([、,。.])(?!' + rBDEnd + ')', 'ig' ), + touwei: new RegExp( '(' + rBDOpen + '+)(' + rChar + ')(' + rBDEnd + '+)', 'ig' ), + tou: new RegExp( '(' + rBDOpen + '+)(' + rChar + ')', 'ig' ), + wei: new RegExp( '(' + rChar + ')(' + rBDEnd + '+)', 'ig' ), + middle: new RegExp( '(' + rChar + ')(' + rBDMid + ')(' + rChar + ')', 'ig' ) + }, + + zhuyin: { + form: new RegExp( '^\u02D9?(' + rZyS + ')?(' + rZyJ + ')?(' + rZyY + ')?(' + rZyD + ')?$' ), + diao: new RegExp( '(' + rZyD + ')', 'g' ) + }, + + /* Hanzi and Western mixed spacing (漢字西文混排間隙) + * - Basic mode + * - Strict mode + */ + hws: { + base: [ + new RegExp( '('+ rHan + ')(' + rAlph + '|' + rPtOpen + ')', 'ig' ), + new RegExp( '('+ rAlph + '|' + rPtEnd + ')(' + rHan + ')', 'ig' ) + ], + + strict: [ + new RegExp( '('+ rHan + ')' + rWhite + '?(' + rAlph + '|' + rPtOpen + ')', 'ig' ), + new RegExp( '('+ rAlph + '|' + rPtEnd + ')' + rWhite + '?(' + rHan + ')', 'ig' ) + ] + }, + + // The feature displays the following characters + // in its variant form for font consistency and + // presentational reason. Meanwhile, this won't + // alter the original character in the DOM. + 'display-as': { + 'ja-font-for-hant': [ + // '夠 够', + '查 査', + '啟 啓', + '鄉 鄕', + '值 値', + '污 汚' + ], + + 'comb-liga-pua': [ + [ '\u0061[\u030d\u0358]', '\uDB80\uDC61' ], + [ '\u0065[\u030d\u0358]', '\uDB80\uDC65' ], + [ '\u0069[\u030d\u0358]', '\uDB80\uDC69' ], + [ '\u006F[\u030d\u0358]', '\uDB80\uDC6F' ], + [ '\u0075[\u030d\u0358]', '\uDB80\uDC75' ], + + [ '\u31B4[\u030d\u0358]', '\uDB8C\uDDB4' ], + [ '\u31B5[\u030d\u0358]', '\uDB8C\uDDB5' ], + [ '\u31B6[\u030d\u0358]', '\uDB8C\uDDB6' ], + [ '\u31B7[\u030d\u0358]', '\uDB8C\uDDB7' ] + ], + + 'comb-liga-vowel': [ + [ '\u0061[\u030d\u0358]', '\uDB80\uDC61' ], + [ '\u0065[\u030d\u0358]', '\uDB80\uDC65' ], + [ '\u0069[\u030d\u0358]', '\uDB80\uDC69' ], + [ '\u006F[\u030d\u0358]', '\uDB80\uDC6F' ], + [ '\u0075[\u030d\u0358]', '\uDB80\uDC75' ] + ], + + 'comb-liga-zhuyin': [ + [ '\u31B4[\u030d\u0358]', '\uDB8C\uDDB4' ], + [ '\u31B5[\u030d\u0358]', '\uDB8C\uDDB5' ], + [ '\u31B6[\u030d\u0358]', '\uDB8C\uDDB6' ], + [ '\u31B7[\u030d\u0358]', '\uDB8C\uDDB7' ] + ] + }, + + // The feature actually *converts* the character + // in the DOM for semantic reason. + // + // Note that this could be aggressive. + 'inaccurate-char': [ + [ '[\u2022\u2027]', '\u00B7' ], + [ '\u22EF\u22EF', '\u2026\u2026' ], + [ '\u2500\u2500', '\u2014\u2014' ], + [ '\u2035', '\u2018' ], + [ '\u2032', '\u2019' ], + [ '\u2036', '\u201C' ], + [ '\u2033', '\u201D' ] + ] + } +})() + +Han.UNICODE = UNICODE +Han.TYPESET = TYPESET + +// Aliases +Han.UNICODE.cjk = Han.UNICODE.hanzi +Han.UNICODE.greek = Han.UNICODE.ellinika +Han.UNICODE.cyrillic = Han.UNICODE.kirillica +Han.UNICODE.hangul = Han.UNICODE.eonmun +Han.UNICODE.zhuyin.ruyun = Han.UNICODE.zhuyin.checked + +Han.TYPESET.char.cjk = Han.TYPESET.char.hanzi +Han.TYPESET.char.greek = Han.TYPESET.char.ellinika +Han.TYPESET.char.cyrillic = Han.TYPESET.char.kirillica +Han.TYPESET.char.hangul = Han.TYPESET.char.eonmun + +Han.TYPESET.group.hangul = Han.TYPESET.group.eonmun +Han.TYPESET.group.cjk = Han.TYPESET.group.hanzi + +var $ = { + /** + * Query selectors which return arrays of the resulted + * node lists. + */ + id: function( selector, $context ) { + return ( $context || document ).getElementById( selector ) + }, + + tag: function( selector, $context ) { + return this.makeArray( + ( $context || document ).getElementsByTagName( selector ) + ) + }, + + qs: function( selector, $context ) { + return ( $context || document ).querySelector( selector ) + }, + + qsa: function( selector, $context ) { + return this.makeArray( + ( $context || document ).querySelectorAll( selector ) + ) + }, + + parent: function( $node, selector ) { + return selector + ? (function() { + if ( typeof $.matches !== 'function' ) return + + while (!$.matches( $node, selector )) { + if ( + !$node || + $node === document.documentElement + ) { + $node = undefined + break + } + $node = $node.parentNode + } + return $node + })() + : $node + ? $node.parentNode : undefined + }, + + /** + * Create a document fragment, a text node with text + * or an element with/without classes. + */ + create: function( name, clazz ) { + var $elmt = '!' === name + ? document.createDocumentFragment() + : '' === name + ? document.createTextNode( clazz || '' ) + : document.createElement( name ) + + try { + if ( clazz ) { + $elmt.className = clazz + } + } catch (e) {} + + return $elmt + }, + + /** + * Clone a DOM node (text, element or fragment) deeply + * or childlessly. + */ + clone: function( $node, deep ) { + return $node.cloneNode( + typeof deep === 'boolean' + ? deep + : true + ) + }, + + /** + * Remove a node (text, element or fragment). + */ + remove: function( $node ) { + return $node.parentNode.removeChild( $node ) + }, + + /** + * Set attributes all in once with an object. + */ + setAttr: function( target, attr ) { + if ( typeof attr !== 'object' ) return + var len = attr.length + + // Native `NamedNodeMap``: + if ( + typeof attr[0] === 'object' && + 'name' in attr[0] + ) { + for ( var i = 0; i < len; i++ ) { + if ( attr[ i ].value !== undefined ) { + target.setAttribute( attr[ i ].name, attr[ i ].value ) + } + } + + // Plain object: + } else { + for ( var name in attr ) { + if ( + attr.hasOwnProperty( name ) && + attr[ name ] !== undefined + ) { + target.setAttribute( name, attr[ name ] ) + } + } + } + return target + }, + + /** + * Indicate whether or not the given node is an + * element. + */ + isElmt: function( $node ) { + return $node && $node.nodeType === Node.ELEMENT_NODE + }, + + /** + * Indicate whether or not the given node should + * be ignored (`` or comments). + */ + isIgnorable: function( $node ) { + if ( !$node ) return false + + return ( + $node.nodeName === 'WBR' || + $node.nodeType === Node.COMMENT_NODE + ) + }, + + /** + * Convert array-like objects into real arrays. + */ + makeArray: function( object ) { + return Array.prototype.slice.call( object ) + }, + + /** + * Extend target with an object. + */ + extend: function( target, object ) { + if (( + typeof target === 'object' || + typeof target === 'function' ) && + typeof object === 'object' + ) { + for ( var name in object ) { + if (object.hasOwnProperty( name )) { + target[ name ] = object[ name ] + } + } + } + return target + } +} + +var Fibre = +/*! + * Fibre.js v0.2.1 | MIT License | github.com/ethantw/fibre.js + * Based on findAndReplaceDOMText + */ + +function( Finder ) { + +'use strict' + +var VERSION = '0.2.1' +var NON_INLINE_PROSE = Finder.NON_INLINE_PROSE +var AVOID_NON_PROSE = Finder.PRESETS.prose.filterElements + +var global = window || {} +var document = global.document || undefined + +function matches( node, selector, bypassNodeType39 ) { + var Efn = Element.prototype + var matches = Efn.matches || Efn.mozMatchesSelector || Efn.msMatchesSelector || Efn.webkitMatchesSelector + + if ( node instanceof Element ) { + return matches.call( node, selector ) + } else if ( bypassNodeType39 ) { + if ( /^[39]$/.test( node.nodeType )) return true + } + return false +} + +if ( typeof document === 'undefined' ) throw new Error( 'Fibre requires a DOM-supported environment.' ) + +var Fibre = function( context, preset ) { + return new Fibre.fn.init( context, preset ) +} + +Fibre.version = VERSION +Fibre.matches = matches + +Fibre.fn = Fibre.prototype = { + constructor: Fibre, + + version: VERSION, + + finder: [], + + context: undefined, + + portionMode: 'retain', + + selector: {}, + + preset: 'prose', + + init: function( context, noPreset ) { + if ( !!noPreset ) this.preset = null + + this.selector = { + context: null, + filter: [], + avoid: [], + boundary: [] + } + + if ( !context ) { + throw new Error( 'A context is required for Fibre to initialise.' ) + } else if ( context instanceof Node ) { + if ( context instanceof Document ) this.context = context.body || context + else this.context = context + } else if ( typeof context === 'string' ) { + this.context = document.querySelector( context ) + this.selector.context = context + } + return this + }, + + filterFn: function( node ) { + var filter = this.selector.filter.join( ', ' ) || '*' + var avoid = this.selector.avoid.join( ', ' ) || null + var result = matches( node, filter, true ) && !matches( node, avoid ) + return ( this.preset === 'prose' ) ? AVOID_NON_PROSE( node ) && result : result + }, + + boundaryFn: function( node ) { + var boundary = this.selector.boundary.join( ', ' ) || null + var result = matches( node, boundary ) + return ( this.preset === 'prose' ) ? NON_INLINE_PROSE( node ) || result : result + }, + + filter: function( selector ) { + if ( typeof selector === 'string' ) { + this.selector.filter.push( selector ) + } + return this + }, + + endFilter: function( all ) { + if ( all ) { + this.selector.filter = [] + } else { + this.selector.filter.pop() + } + return this + }, + + avoid: function( selector ) { + if ( typeof selector === 'string' ) { + this.selector.avoid.push( selector ) + } + return this + }, + + endAvoid: function( all ) { + if ( all ) { + this.selector.avoid = [] + } else { + this.selector.avoid.pop() + } + return this + }, + + addBoundary: function( selector ) { + if ( typeof selector === 'string' ) { + this.selector.boundary.push( selector ) + } + return this + }, + + removeBoundary: function() { + this.selector.boundary = [] + return this + }, + + setMode: function( portionMode ) { + this.portionMode = portionMode === 'first' ? 'first' : 'retain' + return this + }, + + replace: function( regexp, newSubStr ) { + var it = this + it.finder.push(Finder( it.context, { + find: regexp, + replace: newSubStr, + filterElements: function( currentNode ) { + return it.filterFn( currentNode ) + }, + forceContext: function( currentNode ) { + return it.boundaryFn( currentNode ) + }, + portionMode: it.portionMode + })) + return it + }, + + wrap: function( regexp, strElemName ) { + var it = this + it.finder.push(Finder( it.context, { + find: regexp, + wrap: strElemName, + filterElements: function( currentNode ) { + return it.filterFn( currentNode ) + }, + forceContext: function( currentNode ) { + return it.boundaryFn( currentNode ) + }, + portionMode: it.portionMode + })) + return it + }, + + revert: function( level ) { + var max = this.finder.length + var level = Number( level ) || ( level === 0 ? Number(0) : + ( level === 'all' ? max : 1 )) + + if ( typeof max === 'undefined' || max === 0 ) return this + else if ( level > max ) level = max + + for ( var i = level; i > 0; i-- ) { + this.finder.pop().revert() + } + return this + } +} + +// Deprecated API(s) +Fibre.fn.filterOut = Fibre.fn.avoid + +// Make sure init() inherit from Fibre() +Fibre.fn.init.prototype = Fibre.fn + +return Fibre + +}( + +/** + * findAndReplaceDOMText v 0.4.3 + * @author James Padolsey http://james.padolsey.com + * @license http://unlicense.org/UNLICENSE + * + * Matches the text of a DOM node against a regular expression + * and replaces each match (or node-separated portions of the match) + * in the specified element. + */ + (function() { + + var PORTION_MODE_RETAIN = 'retain' + var PORTION_MODE_FIRST = 'first' + var doc = document + var toString = {}.toString + var hasOwn = {}.hasOwnProperty + function isArray(a) { + return toString.call(a) == '[object Array]' + } + + function escapeRegExp(s) { + return String(s).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1') + } + + function exposed() { + // Try deprecated arg signature first: + return deprecated.apply(null, arguments) || findAndReplaceDOMText.apply(null, arguments) + } + + function deprecated(regex, node, replacement, captureGroup, elFilter) { + if ((node && !node.nodeType) && arguments.length <= 2) { + return false + } + var isReplacementFunction = typeof replacement == 'function' + if (isReplacementFunction) { + replacement = (function(original) { + return function(portion, match) { + return original(portion.text, match.startIndex) + } + }(replacement)) + } + + // Awkward support for deprecated argument signature (<0.4.0) + var instance = findAndReplaceDOMText(node, { + + find: regex, + + wrap: isReplacementFunction ? null : replacement, + replace: isReplacementFunction ? replacement : '$' + (captureGroup || '&'), + + prepMatch: function(m, mi) { + + // Support captureGroup (a deprecated feature) + + if (!m[0]) throw 'findAndReplaceDOMText cannot handle zero-length matches' + if (captureGroup > 0) { + var cg = m[captureGroup] + m.index += m[0].indexOf(cg) + m[0] = cg + } + + m.endIndex = m.index + m[0].length + m.startIndex = m.index + m.index = mi + return m + }, + filterElements: elFilter + }) + exposed.revert = function() { + return instance.revert() + } + return true + } + + /** + * findAndReplaceDOMText + * + * Locates matches and replaces with replacementNode + * + * @param {Node} node Element or Text node to search within + * @param {RegExp} options.find The regular expression to match + * @param {String|Element} [options.wrap] A NodeName, or a Node to clone + * @param {String|Function} [options.replace='$&'] What to replace each match with + * @param {Function} [options.filterElements] A Function to be called to check whether to + * process an element. (returning true = process element, + * returning false = avoid element) + */ + function findAndReplaceDOMText(node, options) { + return new Finder(node, options) + } + + exposed.NON_PROSE_ELEMENTS = { + br:1, hr:1, + // Media / Source elements: + script:1, style:1, img:1, video:1, audio:1, canvas:1, svg:1, map:1, object:1, + // Input elements + input:1, textarea:1, select:1, option:1, optgroup: 1, button:1 + } + exposed.NON_CONTIGUOUS_PROSE_ELEMENTS = { + + // Elements that will not contain prose or block elements where we don't + // want prose to be matches across element borders: + + // Block Elements + address:1, article:1, aside:1, blockquote:1, dd:1, div:1, + dl:1, fieldset:1, figcaption:1, figure:1, footer:1, form:1, h1:1, h2:1, h3:1, + h4:1, h5:1, h6:1, header:1, hgroup:1, hr:1, main:1, nav:1, noscript:1, ol:1, + output:1, p:1, pre:1, section:1, ul:1, + // Other misc. elements that are not part of continuous inline prose: + br:1, li: 1, summary: 1, dt:1, details:1, rp:1, rt:1, rtc:1, + // Media / Source elements: + script:1, style:1, img:1, video:1, audio:1, canvas:1, svg:1, map:1, object:1, + // Input elements + input:1, textarea:1, select:1, option:1, optgroup: 1, button:1, + // Table related elements: + table:1, tbody:1, thead:1, th:1, tr:1, td:1, caption:1, col:1, tfoot:1, colgroup:1 + + } + exposed.NON_INLINE_PROSE = function(el) { + return hasOwn.call(exposed.NON_CONTIGUOUS_PROSE_ELEMENTS, el.nodeName.toLowerCase()) + } + // Presets accessed via `options.preset` when calling findAndReplaceDOMText(): + exposed.PRESETS = { + prose: { + forceContext: exposed.NON_INLINE_PROSE, + filterElements: function(el) { + return !hasOwn.call(exposed.NON_PROSE_ELEMENTS, el.nodeName.toLowerCase()) + } + } + } + exposed.Finder = Finder + /** + * Finder -- encapsulates logic to find and replace. + */ + function Finder(node, options) { + + var preset = options.preset && exposed.PRESETS[options.preset] + options.portionMode = options.portionMode || PORTION_MODE_RETAIN + if (preset) { + for (var i in preset) { + if (hasOwn.call(preset, i) && !hasOwn.call(options, i)) { + options[i] = preset[i] + } + } + } + + this.node = node + this.options = options + // ENable match-preparation method to be passed as option: + this.prepMatch = options.prepMatch || this.prepMatch + this.reverts = [] + this.matches = this.search() + if (this.matches.length) { + this.processMatches() + } + + } + + Finder.prototype = { + + /** + * Searches for all matches that comply with the instance's 'match' option + */ + search: function() { + + var match + var matchIndex = 0 + var offset = 0 + var regex = this.options.find + var textAggregation = this.getAggregateText() + var matches = [] + var self = this + regex = typeof regex === 'string' ? RegExp(escapeRegExp(regex), 'g') : regex + matchAggregation(textAggregation) + function matchAggregation(textAggregation) { + for (var i = 0, l = textAggregation.length; i < l; ++i) { + + var text = textAggregation[i] + if (typeof text !== 'string') { + // Deal with nested contexts: (recursive) + matchAggregation(text) + continue + } + + if (regex.global) { + while (match = regex.exec(text)) { + matches.push(self.prepMatch(match, matchIndex++, offset)) + } + } else { + if (match = text.match(regex)) { + matches.push(self.prepMatch(match, 0, offset)) + } + } + + offset += text.length + } + } + + return matches + }, + + /** + * Prepares a single match with useful meta info: + */ + prepMatch: function(match, matchIndex, characterOffset) { + + if (!match[0]) { + throw new Error('findAndReplaceDOMText cannot handle zero-length matches') + } + + match.endIndex = characterOffset + match.index + match[0].length + match.startIndex = characterOffset + match.index + match.index = matchIndex + return match + }, + + /** + * Gets aggregate text within subject node + */ + getAggregateText: function() { + + var elementFilter = this.options.filterElements + var forceContext = this.options.forceContext + return getText(this.node) + /** + * Gets aggregate text of a node without resorting + * to broken innerText/textContent + */ + function getText(node, txt) { + + if (node.nodeType === 3) { + return [node.data] + } + + if (elementFilter && !elementFilter(node)) { + return [] + } + + var txt = [''] + var i = 0 + if (node = node.firstChild) do { + + if (node.nodeType === 3) { + txt[i] += node.data + continue + } + + var innerText = getText(node) + if ( + forceContext && + node.nodeType === 1 && + (forceContext === true || forceContext(node)) + ) { + txt[++i] = innerText + txt[++i] = '' + } else { + if (typeof innerText[0] === 'string') { + // Bridge nested text-node data so that they're + // not considered their own contexts: + // I.e. ['some', ['thing']] -> ['something'] + txt[i] += innerText.shift() + } + if (innerText.length) { + txt[++i] = innerText + txt[++i] = '' + } + } + } while (node = node.nextSibling) + return txt + } + + }, + + /** + * Steps through the target node, looking for matches, and + * calling replaceFn when a match is found. + */ + processMatches: function() { + + var matches = this.matches + var node = this.node + var elementFilter = this.options.filterElements + var startPortion, + endPortion, + innerPortions = [], + curNode = node, + match = matches.shift(), + atIndex = 0, // i.e. nodeAtIndex + matchIndex = 0, + portionIndex = 0, + doAvoidNode, + nodeStack = [node] + out: while (true) { + + if (curNode.nodeType === 3) { + + if (!endPortion && curNode.length + atIndex >= match.endIndex) { + + // We've found the ending + endPortion = { + node: curNode, + index: portionIndex++, + text: curNode.data.substring(match.startIndex - atIndex, match.endIndex - atIndex), + indexInMatch: atIndex - match.startIndex, + indexInNode: match.startIndex - atIndex, // always zero for end-portions + endIndexInNode: match.endIndex - atIndex, + isEnd: true + } + } else if (startPortion) { + // Intersecting node + innerPortions.push({ + node: curNode, + index: portionIndex++, + text: curNode.data, + indexInMatch: atIndex - match.startIndex, + indexInNode: 0 // always zero for inner-portions + }) + } + + if (!startPortion && curNode.length + atIndex > match.startIndex) { + // We've found the match start + startPortion = { + node: curNode, + index: portionIndex++, + indexInMatch: 0, + indexInNode: match.startIndex - atIndex, + endIndexInNode: match.endIndex - atIndex, + text: curNode.data.substring(match.startIndex - atIndex, match.endIndex - atIndex) + } + } + + atIndex += curNode.data.length + } + + doAvoidNode = curNode.nodeType === 1 && elementFilter && !elementFilter(curNode) + if (startPortion && endPortion) { + + curNode = this.replaceMatch(match, startPortion, innerPortions, endPortion) + // processMatches has to return the node that replaced the endNode + // and then we step back so we can continue from the end of the + // match: + + atIndex -= (endPortion.node.data.length - endPortion.endIndexInNode) + startPortion = null + endPortion = null + innerPortions = [] + match = matches.shift() + portionIndex = 0 + matchIndex++ + if (!match) { + break; // no more matches + } + + } else if ( + !doAvoidNode && + (curNode.firstChild || curNode.nextSibling) + ) { + // Move down or forward: + if (curNode.firstChild) { + nodeStack.push(curNode) + curNode = curNode.firstChild + } else { + curNode = curNode.nextSibling + } + continue + } + + // Move forward or up: + while (true) { + if (curNode.nextSibling) { + curNode = curNode.nextSibling + break + } + curNode = nodeStack.pop() + if (curNode === node) { + break out + } + } + + } + + }, + + /** + * Reverts ... TODO + */ + revert: function() { + // Reversion occurs backwards so as to avoid nodes subsequently + // replaced during the matching phase (a forward process): + for (var l = this.reverts.length; l--;) { + this.reverts[l]() + } + this.reverts = [] + }, + + prepareReplacementString: function(string, portion, match, matchIndex) { + var portionMode = this.options.portionMode + if ( + portionMode === PORTION_MODE_FIRST && + portion.indexInMatch > 0 + ) { + return '' + } + string = string.replace(/\$(\d+|&|`|')/g, function($0, t) { + var replacement + switch(t) { + case '&': + replacement = match[0] + break + case '`': + replacement = match.input.substring(0, match.startIndex) + break + case '\'': + replacement = match.input.substring(match.endIndex) + break + default: + replacement = match[+t] + } + return replacement + }) + if (portionMode === PORTION_MODE_FIRST) { + return string + } + + if (portion.isEnd) { + return string.substring(portion.indexInMatch) + } + + return string.substring(portion.indexInMatch, portion.indexInMatch + portion.text.length) + }, + + getPortionReplacementNode: function(portion, match, matchIndex) { + + var replacement = this.options.replace || '$&' + var wrapper = this.options.wrap + if (wrapper && wrapper.nodeType) { + // Wrapper has been provided as a stencil-node for us to clone: + var clone = doc.createElement('div') + clone.innerHTML = wrapper.outerHTML || new XMLSerializer().serializeToString(wrapper) + wrapper = clone.firstChild + } + + if (typeof replacement == 'function') { + replacement = replacement(portion, match, matchIndex) + if (replacement && replacement.nodeType) { + return replacement + } + return doc.createTextNode(String(replacement)) + } + + var el = typeof wrapper == 'string' ? doc.createElement(wrapper) : wrapper + replacement = doc.createTextNode( + this.prepareReplacementString( + replacement, portion, match, matchIndex + ) + ) + if (!replacement.data) { + return replacement + } + + if (!el) { + return replacement + } + + el.appendChild(replacement) + return el + }, + + replaceMatch: function(match, startPortion, innerPortions, endPortion) { + + var matchStartNode = startPortion.node + var matchEndNode = endPortion.node + var preceedingTextNode + var followingTextNode + if (matchStartNode === matchEndNode) { + + var node = matchStartNode + if (startPortion.indexInNode > 0) { + // Add `before` text node (before the match) + preceedingTextNode = doc.createTextNode(node.data.substring(0, startPortion.indexInNode)) + node.parentNode.insertBefore(preceedingTextNode, node) + } + + // Create the replacement node: + var newNode = this.getPortionReplacementNode( + endPortion, + match + ) + node.parentNode.insertBefore(newNode, node) + if (endPortion.endIndexInNode < node.length) { // ????? + // Add `after` text node (after the match) + followingTextNode = doc.createTextNode(node.data.substring(endPortion.endIndexInNode)) + node.parentNode.insertBefore(followingTextNode, node) + } + + node.parentNode.removeChild(node) + this.reverts.push(function() { + if (preceedingTextNode === newNode.previousSibling) { + preceedingTextNode.parentNode.removeChild(preceedingTextNode) + } + if (followingTextNode === newNode.nextSibling) { + followingTextNode.parentNode.removeChild(followingTextNode) + } + newNode.parentNode.replaceChild(node, newNode) + }) + return newNode + } else { + // Replace matchStartNode -> [innerMatchNodes...] -> matchEndNode (in that order) + + preceedingTextNode = doc.createTextNode( + matchStartNode.data.substring(0, startPortion.indexInNode) + ) + followingTextNode = doc.createTextNode( + matchEndNode.data.substring(endPortion.endIndexInNode) + ) + var firstNode = this.getPortionReplacementNode( + startPortion, + match + ) + var innerNodes = [] + for (var i = 0, l = innerPortions.length; i < l; ++i) { + var portion = innerPortions[i] + var innerNode = this.getPortionReplacementNode( + portion, + match + ) + portion.node.parentNode.replaceChild(innerNode, portion.node) + this.reverts.push((function(portion, innerNode) { + return function() { + innerNode.parentNode.replaceChild(portion.node, innerNode) + } + }(portion, innerNode))) + innerNodes.push(innerNode) + } + + var lastNode = this.getPortionReplacementNode( + endPortion, + match + ) + matchStartNode.parentNode.insertBefore(preceedingTextNode, matchStartNode) + matchStartNode.parentNode.insertBefore(firstNode, matchStartNode) + matchStartNode.parentNode.removeChild(matchStartNode) + matchEndNode.parentNode.insertBefore(lastNode, matchEndNode) + matchEndNode.parentNode.insertBefore(followingTextNode, matchEndNode) + matchEndNode.parentNode.removeChild(matchEndNode) + this.reverts.push(function() { + preceedingTextNode.parentNode.removeChild(preceedingTextNode) + firstNode.parentNode.replaceChild(matchStartNode, firstNode) + followingTextNode.parentNode.removeChild(followingTextNode) + lastNode.parentNode.replaceChild(matchEndNode, lastNode) + }) + return lastNode + } + } + + } + return exposed +}()) + +); + +var isNodeNormalizeNormal = (function() { + //// Disabled `Node.normalize()` for temp due to + //// issue below in IE11. + //// See: http://stackoverflow.com/questions/22337498/why-does-ie11-handle-node-normalize-incorrectly-for-the-minus-symbol + var div = $.create( 'div' ) + + div.appendChild($.create( '', '0-' )) + div.appendChild($.create( '', '2' )) + div.normalize() + + return div.firstChild.length !== 2 +})() + +function getFuncOrElmt( obj ) { + return ( + typeof obj === 'function' || + obj instanceof Element + ) + ? obj + : undefined +} + +function createBDGroup( portion ) { + var clazz = portion.index === 0 && portion.isEnd + ? 'biaodian cjk' + : 'biaodian cjk portion ' + ( + portion.index === 0 + ? 'is-first' + : portion.isEnd + ? 'is-end' + : 'is-inner' + ) + + var $elmt = $.create( 'h-char-group', clazz ) + $elmt.innerHTML = portion.text + return $elmt +} + +function createBDChar( char ) { + var div = $.create( 'div' ) + var unicode = char.charCodeAt( 0 ).toString( 16 ) + + div.innerHTML = ( + '' + char + '' + ) + return div.firstChild +} + +function getBDType( char ) { + return char.match( TYPESET.char.biaodian.open ) + ? 'bd-open' + : char.match( TYPESET.char.biaodian.close ) + ? 'bd-close bd-end' + : char.match( TYPESET.char.biaodian.end ) + ? ( + /(?:\u3001|\u3002|\uff0c)/i.test( char ) + ? 'bd-end bd-cop' + : 'bd-end' + ) + : char.match(new RegExp( UNICODE.biaodian.liga )) + ? 'bd-liga' + : char.match(new RegExp( UNICODE.biaodian.middle )) + ? 'bd-middle' + : '' +} + +$.extend( Fibre.fn, { + normalize: function() { + if ( isNodeNormalizeNormal ) { + this.context.normalize() + } + return this + }, + + // Force punctuation & biaodian typesetting rules to be applied. + jinzify: function( selector ) { + return ( + this + .filter( selector || null ) + .avoid( 'h-jinze' ) + .replace( + TYPESET.jinze.touwei, + function( portion, match ) { + var elem = $.create( 'h-jinze', 'touwei' ) + elem.innerHTML = match[0] + return (( portion.index === 0 && portion.isEnd ) || portion.index === 1 ) ? elem : '' + } + ) + .replace( + TYPESET.jinze.wei, + function( portion, match ) { + var elem = $.create( 'h-jinze', 'wei' ) + elem.innerHTML = match[0] + return portion.index === 0 ? elem : '' + } + ) + .replace( + TYPESET.jinze.tou, + function( portion, match ) { + var elem = $.create( 'h-jinze', 'tou' ) + elem.innerHTML = match[0] + return (( portion.index === 0 && portion.isEnd ) || portion.index === 1 ) + ? elem : '' + } + ) + .replace( + TYPESET.jinze.middle, + function( portion, match ) { + var elem = $.create( 'h-jinze', 'middle' ) + elem.innerHTML = match[0] + return (( portion.index === 0 && portion.isEnd ) || portion.index === 1 ) + ? elem : '' + } + ) + .endAvoid() + .endFilter() + ) + }, + + groupify: function( option ) { + var option = $.extend({ + biaodian: false, + //punct: false, + hanzi: false, // Includes Kana + kana: false, + eonmun: false, + western: false // Includes Latin, Greek and Cyrillic + }, option || {}) + + this.avoid( 'h-word, h-char-group' ) + + if ( option.biaodian ) { + this.replace( + TYPESET.group.biaodian[0], createBDGroup + ).replace( + TYPESET.group.biaodian[1], createBDGroup + ) + } + + if ( option.hanzi || option.cjk ) { + this.wrap( + TYPESET.group.hanzi, $.clone($.create( 'h-char-group', 'hanzi cjk' )) + ) + } + if ( option.western ) { + this.wrap( + TYPESET.group.western, $.clone($.create( 'h-word', 'western' )) + ) + } + if ( option.kana ) { + this.wrap( + TYPESET.group.kana, $.clone($.create( 'h-char-group', 'kana' )) + ) + } + if ( option.eonmun || option.hangul ) { + this.wrap( + TYPESET.group.eonmun, $.clone($.create( 'h-word', 'eonmun hangul' )) + ) + } + + this.endAvoid() + return this + }, + + charify: function( option ) { + var option = $.extend({ + avoid: true, + biaodian: false, + punct: false, + hanzi: false, // Includes Kana + latin: false, + ellinika: false, + kirillica: false, + kana: false, + eonmun: false + }, option || {}) + + if ( option.avoid ) { + this.avoid( 'h-char' ) + } + + if ( option.biaodian ) { + this.replace( + TYPESET.char.biaodian.all, + getFuncOrElmt( option.biaodian ) + || + function( portion ) { return createBDChar( portion.text ) } + ).replace( + TYPESET.char.biaodian.liga, + getFuncOrElmt( option.biaodian ) + || + function( portion ) { return createBDChar( portion.text ) } + ) + } + if ( option.hanzi || option.cjk ) { + this.wrap( + TYPESET.char.hanzi, + getFuncOrElmt( option.hanzi || option.cjk ) + || + $.clone($.create( 'h-char', 'hanzi cjk' )) + ) + } + if ( option.punct ) { + this.wrap( + TYPESET.char.punct.all, + getFuncOrElmt( option.punct ) + || + $.clone($.create( 'h-char', 'punct' )) + ) + } + if ( option.latin ) { + this.wrap( + TYPESET.char.latin, + getFuncOrElmt( option.latin ) + || + $.clone($.create( 'h-char', 'alphabet latin' )) + ) + } + if ( option.ellinika || option.greek ) { + this.wrap( + TYPESET.char.ellinika, + getFuncOrElmt( option.ellinika || option.greek ) + || + $.clone($.create( 'h-char', 'alphabet ellinika greek' )) + ) + } + if ( option.kirillica || option.cyrillic ) { + this.wrap( + TYPESET.char.kirillica, + getFuncOrElmt( option.kirillica || option.cyrillic ) + || + $.clone($.create( 'h-char', 'alphabet kirillica cyrillic' )) + ) + } + if ( option.kana ) { + this.wrap( + TYPESET.char.kana, + getFuncOrElmt( option.kana ) + || + $.clone($.create( 'h-char', 'kana' )) + ) + } + if ( option.eonmun || option.hangul ) { + this.wrap( + TYPESET.char.eonmun, + getFuncOrElmt( option.eonmun || option.hangul ) + || + $.clone($.create( 'h-char', 'eonmun hangul' )) + ) + } + + this.endAvoid() + return this + } +}) + +$.extend( Han, { + isNodeNormalizeNormal: isNodeNormalizeNormal, + find: Fibre, + createBDGroup: createBDGroup, + createBDChar: createBDChar +}) + +$.matches = Han.find.matches + +void [ + 'setMode', + 'wrap', 'replace', 'revert', + 'addBoundary', 'removeBoundary', + 'avoid', 'endAvoid', + 'filter', 'endFilter', + 'jinzify', 'groupify', 'charify' +].forEach(function( method ) { + Han.fn[ method ] = function() { + if ( !this.finder ) { + // Share the same selector + this.finder = Han.find( this.context ) + } + + this.finder[ method ]( arguments[ 0 ], arguments[ 1 ] ) + return this + } +}) + +var Locale = {} + +function writeOnCanvas( text, font ) { + var canvas = $.create( 'canvas' ) + var context + + canvas.width = '50' + canvas.height = '20' + canvas.style.display = 'none' + + body.appendChild( canvas ) + + context = canvas.getContext( '2d' ) + context.textBaseline = 'top' + context.font = '15px ' + font + ', sans-serif' + context.fillStyle = 'black' + context.strokeStyle = 'black' + context.fillText( text, 0, 0 ) + + return { + node: canvas, + context: context, + remove: function() { + $.remove( canvas, body ) + } + } +} + +function compareCanvases( treat, control ) { + var ret + var a = treat.context + var b = control.context + + try { + for ( var j = 1; j <= 20; j++ ) { + for ( var i = 1; i <= 50; i++ ) { + if ( + typeof ret === 'undefined' && + a.getImageData(i, j, 1, 1).data[3] !== b.getImageData(i, j, 1, 1).data[3] + ) { + ret = false + break + } else if ( typeof ret === 'boolean' ) { + break + } + + if ( i === 50 && j === 20 && typeof ret === 'undefined' ) { + ret = true + } + } + } + + // Remove and clean from memory + treat.remove() + control.remove() + treat = null + control = null + + return ret + } catch (e) {} + return false +} + +function detectFont( treat, control, text ) { + var treat = treat + var control = control || 'sans-serif' + var text = text || '辭Q' + var ret + + control = writeOnCanvas( text, control ) + treat = writeOnCanvas( text, treat ) + + return !compareCanvases( treat, control ) +} + +Locale.writeOnCanvas = writeOnCanvas +Locale.compareCanvases = compareCanvases +Locale.detectFont = detectFont + +Locale.support = (function() { + + var PREFIX = 'Webkit Moz ms'.split(' ') + + // Create an element for feature detecting + // (in `testCSSProp`) + var elem = $.create( 'h-test' ) + + function testCSSProp( prop ) { + var ucProp = prop.charAt(0).toUpperCase() + prop.slice(1) + var allProp = ( prop + ' ' + PREFIX.join( ucProp + ' ' ) + ucProp ).split(' ') + var ret + + allProp.forEach(function( prop ) { + if ( typeof elem.style[ prop ] === 'string' ) { + ret = true + } + }) + return ret || false + } + + function injectElementWithStyle( rule, callback ) { + var fakeBody = body || $.create( 'body' ) + var div = $.create( 'div' ) + var container = body ? div : fakeBody + var callback = typeof callback === 'function' ? callback : function() {} + var style, ret, docOverflow + + style = [ '' ].join('') + + container.innerHTML += style + fakeBody.appendChild( div ) + + if ( !body ) { + fakeBody.style.background = '' + fakeBody.style.overflow = 'hidden' + docOverflow = root.style.overflow + + root.style.overflow = 'hidden' + root.appendChild( fakeBody ) + } + + // Callback + ret = callback( container, rule ) + + // Remove the injected scope + $.remove( container ) + if ( !body ) { + root.style.overflow = docOverflow + } + return !!ret + } + + function getStyle( elem, prop ) { + var ret + + if ( window.getComputedStyle ) { + ret = document.defaultView.getComputedStyle( elem, null ).getPropertyValue( prop ) + } else if ( elem.currentStyle ) { + // for IE + ret = elem.currentStyle[ prop ] + } + return ret + } + + return { + columnwidth: testCSSProp( 'columnWidth' ), + + fontface: (function() { + var ret + + injectElementWithStyle( + '@font-face { font-family: font; src: url("//"); }', + function( node, rule ) { + var style = $.qsa( 'style', node )[0] + var sheet = style.sheet || style.styleSheet + var cssText = sheet ? + ( sheet.cssRules && sheet.cssRules[0] ? + sheet.cssRules[0].cssText : sheet.cssText || '' + ) : '' + + ret = /src/i.test( cssText ) && + cssText.indexOf( rule.split(' ')[0] ) === 0 + } + ) + + return ret + })(), + + ruby: (function() { + var ruby = $.create( 'ruby' ) + var rt = $.create( 'rt' ) + var rp = $.create( 'rp' ) + var ret + + ruby.appendChild( rp ) + ruby.appendChild( rt ) + root.appendChild( ruby ) + + // Browsers that support ruby hide the `` via `display: none` + ret = ( + getStyle( rp, 'display' ) === 'none' || + // but in IE, `` has `display: inline`, so the test needs other conditions: + getStyle( ruby, 'display' ) === 'ruby' && + getStyle( rt, 'display' ) === 'ruby-text' + ) ? true : false + + // Remove and clean from memory + root.removeChild( ruby ) + ruby = null + rt = null + rp = null + + return ret + })(), + + 'ruby-display': (function() { + var div = $.create( 'div' ) + + div.innerHTML = '' + return div.querySelector( 'h-test-a' ).style.display === 'ruby' && div.querySelector( 'h-test-b' ).style.display === 'ruby-text-container' + })(), + + 'ruby-interchar': (function() { + var IC = 'inter-character' + var div = $.create( 'div' ) + var css + + div.innerHTML = '' + css = div.querySelector( 'h-test' ).style + return css.rubyPosition === IC || css.WebkitRubyPosition === IC || css.MozRubyPosition === IC || css.msRubyPosition === IC + })(), + + textemphasis: testCSSProp( 'textEmphasis' ), + + // Address feature support test for `unicode-range` via + // detecting whether it's Arial (supported) or + // Times New Roman (not supported). + unicoderange: (function() { + var ret + + injectElementWithStyle( + '@font-face{font-family:test-for-unicode-range;src:local(Arial),local("Droid Sans")}@font-face{font-family:test-for-unicode-range;src:local("Times New Roman"),local(Times),local("Droid Serif");unicode-range:U+270C}', + function() { + ret = !Locale.detectFont( + 'test-for-unicode-range', // treatment group + 'Arial, "Droid Sans"', // control group + 'Q' // ASCII characters only + ) + } + ) + return ret + })(), + + writingmode: testCSSProp( 'writingMode' ) + } +})() + +Locale.initCond = function( target ) { + var target = target || root + var ret = '' + var clazz + + for ( var feature in Locale.support ) { + clazz = ( Locale.support[ feature ] ? '' : 'no-' ) + feature + + target.classList.add( clazz ) + ret += clazz + ' ' + } + return ret +} + +var SUPPORT_IC = Locale.support[ 'ruby-interchar' ] + +// 1. Simple ruby polyfill; +// 2. Inter-character polyfill for Zhuyin +function renderSimpleRuby( $ruby ) { + var frag = $.create( '!' ) + var clazz = $ruby.classList + var $rb, $ru + + frag.appendChild( $.clone( $ruby )) + + $ + .tag( 'rt', frag.firstChild ) + .forEach(function( $rt ) { + var $rb = $.create( '!' ) + var airb = [] + var irb + + // Consider the previous nodes the implied + // ruby base + do { + irb = ( irb || $rt ).previousSibling + if ( !irb || irb.nodeName.match( /((?:h\-)?r[ubt])/i )) break + + $rb.insertBefore( $.clone( irb ), $rb.firstChild ) + airb.push( irb ) + } while ( !irb.nodeName.match( /((?:h\-)?r[ubt])/i )) + + // Create a real `` to append. + $ru = clazz.contains( 'zhuyin' ) ? createZhuyinRu( $rb, $rt ) : createNormalRu( $rb, $rt ) + + // Replace the ruby text with the new ``, + // and remove the original implied ruby base(s) + try { + $rt.parentNode.replaceChild( $ru, $rt ) + airb.map( $.remove ) + } catch ( e ) {} + }) + return createCustomRuby( frag ) +} + +function renderInterCharRuby( $ruby ) { + var frag = $.create( '!' ) + frag.appendChild( $.clone( $ruby )) + + $ + .tag( 'rt', frag.firstChild ) + .forEach(function( $rt ) { + var $rb = $.create( '!' ) + var airb = [] + var irb, $zhuyin + + // Consider the previous nodes the implied + // ruby base + do { + irb = ( irb || $rt ).previousSibling + if ( !irb || irb.nodeName.match( /((?:h\-)?r[ubt])/i )) break + + $rb.insertBefore( $.clone( irb ), $rb.firstChild ) + airb.push( irb ) + } while ( !irb.nodeName.match( /((?:h\-)?r[ubt])/i )) + + $zhuyin = $.create( 'rt' ) + $zhuyin.innerHTML = getZhuyinHTML( $rt ) + $rt.parentNode.replaceChild( $zhuyin, $rt ) + }) + return frag.firstChild +} + +// 3. Complex ruby polyfill +// - Double-lined annotation; +// - Right-angled annotation. +function renderComplexRuby( $ruby ) { + var frag = $.create( '!' ) + var clazz = $ruby.classList + var $cloned, $rb, $ru, maxspan + + frag.appendChild( $.clone( $ruby )) + $cloned = frag.firstChild + + $rb = $ru = $.tag( 'rb', $cloned ) + maxspan = $rb.length + + // First of all, deal with Zhuyin containers + // individually + // + // Note that we only support one single Zhuyin + // container in each complex ruby + void function( $rtc ) { + if ( !$rtc ) return + + $ru = $ + .tag( 'rt', $rtc ) + .map(function( $rt, i ) { + if ( !$rb[ i ] ) return + var ret = createZhuyinRu( $rb[ i ], $rt ) + + try { + $rb[ i ].parentNode.replaceChild( ret, $rb[ i ] ) + } catch ( e ) {} + return ret + }) + + // Remove the container once it's useless + $.remove( $rtc ) + $cloned.setAttribute( 'rightangle', 'true' ) + }( $cloned.querySelector( 'rtc.zhuyin' )) + + // Then, normal annotations other than Zhuyin + $ + .qsa( 'rtc:not(.zhuyin)', $cloned ) + .forEach(function( $rtc, order ) { + var ret + ret = $ + .tag( 'rt', $rtc ) + .map(function( $rt, i ) { + var rbspan = Number( $rt.getAttribute( 'rbspan' ) || 1 ) + var span = 0 + var aRb = [] + var $rb, ret + + if ( rbspan > maxspan ) rbspan = maxspan + + do { + try { + $rb = $ru.shift() + aRb.push( $rb ) + } catch (e) {} + + if ( typeof $rb === 'undefined' ) break + span += Number( $rb.getAttribute( 'span' ) || 1 ) + } while ( rbspan > span ) + + if ( rbspan < span ) { + if ( aRb.length > 1 ) { + console.error( 'An impossible `rbspan` value detected.', ruby ) + return + } + aRb = $.tag( 'rb', aRb[0] ) + $ru = aRb.slice( rbspan ).concat( $ru ) + aRb = aRb.slice( 0, rbspan ) + span = rbspan + } + + ret = createNormalRu( aRb, $rt, { + 'class': clazz, + span: span, + order: order + }) + + try { + aRb[0].parentNode.replaceChild( ret, aRb.shift() ) + aRb.map( $.remove ) + } catch (e) {} + return ret + }) + $ru = ret + if ( order === 1 ) $cloned.setAttribute( 'doubleline', 'true' ) + + // Remove the container once it's useless + $.remove( $rtc ) + }) + return createCustomRuby( frag ) +} + +// Create a new fake `` element so the +// style sheets will render it as a polyfill, +// which also helps to avoid the UA style. +function createCustomRuby( frag ) { + var $ruby = frag.firstChild + var hruby = $.create( 'h-ruby' ) + + hruby.innerHTML = $ruby.innerHTML + $.setAttr( hruby, $ruby.attributes ) + hruby.normalize() + return hruby +} + +function simplifyRubyClass( elem ) { + if ( !elem instanceof Element ) return elem + var clazz = elem.classList + + if ( clazz.contains( 'pinyin' )) clazz.add( 'romanization' ) + else if ( clazz.contains( 'romanization' )) clazz.add( 'annotation' ) + else if ( clazz.contains( 'mps' )) clazz.add( 'zhuyin' ) + else if ( clazz.contains( 'rightangle' )) clazz.add( 'complex' ) + return elem +} + +/** + * Create and return a new `` element + * according to the given contents + */ +function createNormalRu( $rb, $rt, attr ) { + var $ru = $.create( 'h-ru' ) + var $rt = $.clone( $rt ) + var attr = attr || {} + attr.annotation = 'true' + + if ( Array.isArray( $rb )) { + $ru.innerHTML = $rb.map(function( rb ) { + if ( typeof rb === 'undefined' ) return '' + return rb.outerHTML + }).join('') + $rt.outerHTML + } else { + $ru.appendChild( $.clone( $rb )) + $ru.appendChild( $rt ) + } + + $.setAttr( $ru, attr ) + return $ru +} + +/** + * Create and return a new `` element + * in Zhuyin form + */ +function createZhuyinRu( $rb, $rt ) { + var $rb = $.clone( $rb ) + + // Create an element to return + var $ru = $.create( 'h-ru' ) + $ru.setAttribute( 'zhuyin', true ) + + // - + // - + // - + // - + // - + // - + // - + $ru.appendChild( $rb ) + $ru.innerHTML += getZhuyinHTML( $rt ) + return $ru +} + +/** + * Create a Zhuyin-form HTML string + */ +function getZhuyinHTML( rt ) { + // #### Explanation #### + // * `zhuyin`: the entire phonetic annotation + // * `yin`: the plain pronunciation (w/out tone) + // * `diao`: the tone + // * `len`: the length of the plain pronunciation (`yin`) + var zhuyin = typeof rt === 'string' ? rt : rt.textContent + var yin, diao, len + + yin = zhuyin.replace( TYPESET.zhuyin.diao, '' ) + len = yin ? yin.length : 0 + diao = zhuyin + .replace( yin, '' ) + .replace( /[\u02C5]/g, '\u02C7' ) + .replace( /[\u030D]/g, '\u0358' ) + return len === 0 ? '' : '' + yin + '' + diao + '' +} + +/** + * Normalize `ruby` elements + */ +$.extend( Locale, { + + // Address normalisation for both simple and complex + // rubies (interlinear annotations) + renderRuby: function( context, target ) { + var target = target || 'ruby' + var $target = $.qsa( target, context ) + + $.qsa( 'rtc', context ) + .concat( $target ).map( simplifyRubyClass ) + + $target + .forEach(function( $ruby ) { + var clazz = $ruby.classList + var $new + + if ( clazz.contains( 'complex' )) $new = renderComplexRuby( $ruby ) + else if ( clazz.contains( 'zhuyin' )) $new = SUPPORT_IC ? renderInterCharRuby( $ruby ) : renderSimpleRuby( $ruby ) + + // Finally, replace it + if ( $new ) $ruby.parentNode.replaceChild( $new, $ruby ) + }) + }, + + simplifyRubyClass: simplifyRubyClass, + getZhuyinHTML: getZhuyinHTML, + renderComplexRuby: renderComplexRuby, + renderSimpleRuby: renderSimpleRuby, + renderInterCharRuby: renderInterCharRuby + + // ### TODO list ### + // + // * Debug mode + // * Better error-tolerance +}) + +/** + * Normalisation rendering mechanism + */ +$.extend( Locale, { + + // Render and normalise the given context by routine: + // + // ruby -> u, ins -> s, del -> em + // + renderElem: function( context ) { + this.renderRuby( context ) + this.renderDecoLine( context ) + this.renderDecoLine( context, 's, del' ) + this.renderEm( context ) + }, + + // Traverse all target elements and address + // presentational corrections if any two of + // them are adjacent to each other. + renderDecoLine: function( context, target ) { + var $$target = $.qsa( target || 'u, ins', context ) + var i = $$target.length + + traverse: while ( i-- ) { + var $this = $$target[ i ] + var $prev = null + + // Ignore all `` and comments in between, + // and add class `.adjacent` once two targets + // are next to each other. + ignore: do { + $prev = ( $prev || $this ).previousSibling + + if ( !$prev ) { + continue traverse + } else if ( $$target[ i-1 ] === $prev ) { + $this.classList.add( 'adjacent' ) + } + } while ( $.isIgnorable( $prev )) + } + }, + + // Traverse all target elements to render + // emphasis marks. + renderEm: function( context, target ) { + var method = target ? 'qsa' : 'tag' + var target = target || 'em' + var $target = $[ method ]( target, context ) + + $target + .forEach(function( elem ) { + var $elem = Han( elem ) + + if ( Locale.support.textemphasis ) { + $elem + .avoid( 'rt, h-char' ) + .charify({ biaodian: true, punct: true }) + } else { + $elem + .avoid( 'rt, h-char, h-char-group' ) + .jinzify() + .groupify({ western: true }) + .charify({ + hanzi: true, + biaodian: true, + punct: true, + latin: true, + ellinika: true, + kirillica: true + }) + } + }) + } +}) + +Han.normalize = Locale +Han.localize = Locale +Han.support = Locale.support +Han.detectFont = Locale.detectFont + +Han.fn.initCond = function() { + this.condition.classList.add( 'han-js-rendered' ) + Han.normalize.initCond( this.condition ) + return this +} + +void [ + 'Elem', + 'DecoLine', + 'Em', + 'Ruby' +].forEach(function( elem ) { + var method = 'render' + elem + + Han.fn[ method ] = function( target ) { + Han.normalize[ method ]( this.context, target ) + return this + } +}) + +$.extend( Han.support, { + // Assume that all devices support Heiti for we + // use `sans-serif` to do the comparison. + heiti: true, + // 'heiti-gb': true, + + songti: Han.detectFont( '"Han Songti"' ), + 'songti-gb': Han.detectFont( '"Han Songti GB"' ), + + kaiti: Han.detectFont( '"Han Kaiti"' ), + // 'kaiti-gb': Han.detectFont( '"Han Kaiti GB"' ), + + fangsong: Han.detectFont( '"Han Fangsong"' ) + // 'fangsong-gb': Han.detectFont( '"Han Fangsong GB"' ) +}) + +Han.correctBiaodian = function( context ) { + var context = context || document + var finder = Han.find( context ) + + finder + .avoid( 'h-char' ) + .replace( /([‘“])/g, function( portion ) { + var $char = Han.createBDChar( portion.text ) + $char.classList.add( 'bd-open', 'punct' ) + return $char + }) + .replace( /([’”])/g, function( portion ) { + var $char = Han.createBDChar( portion.text ) + $char.classList.add( 'bd-close', 'bd-end', 'punct' ) + return $char + }) + + return Han.support.unicoderange + ? finder + : finder.charify({ biaodian: true }) +} + +Han.correctBasicBD = Han.correctBiaodian +Han.correctBD = Han.correctBiaodian + +$.extend( Han.fn, { + biaodian: null, + + correctBiaodian: function() { + this.biaodian = Han.correctBiaodian( this.context ) + return this + }, + + revertCorrectedBiaodian: function() { + try { + this.biaodian.revert( 'all' ) + } catch (e) {} + return this + } +}) + +// Legacy support (deprecated): +Han.fn.correctBasicBD = Han.fn.correctBiaodian +Han.fn.revertBasicBD = Han.fn.revertCorrectedBiaodian + +var hws = '<>' + +var $hws = $.create( 'h-hws' ) +$hws.setAttribute( 'hidden', '' ) +$hws.innerHTML = ' ' + +function sharingSameParent( $a, $b ) { + return $a && $b && $a.parentNode === $b.parentNode +} + +function properlyPlaceHWSBehind( $node, text ) { + var $elmt = $node + var text = text || '' + + if ( + $.isElmt( $node.nextSibling ) || + sharingSameParent( $node, $node.nextSibling ) + ) { + return text + hws + } else { + // One of the parental elements of the current text + // node would definitely have a next sibling, since + // it is of the first portion and not `isEnd`. + while ( !$elmt.nextSibling ) { + $elmt = $elmt.parentNode + } + if ( $node !== $elmt ) { + $elmt.insertAdjacentHTML( 'afterEnd', '' ) + } + } + return text +} + +function firstStepLabel( portion, mat ) { + return portion.isEnd && portion.index === 0 + ? mat[1] + hws + mat[2] + : portion.index === 0 + ? properlyPlaceHWSBehind( portion.node, portion.text ) + : portion.text +} + +function real$hwsElmt( portion ) { + return portion.index === 0 + ? $.clone( $hws ) + : '' +} + +var last$hwsIdx + +function apostrophe( portion ) { + var $elmt = portion.node.parentNode + + if ( portion.index === 0 ) { + last$hwsIdx = portion.endIndexInNode-2 + } + + if ( + $elmt.nodeName.toLowerCase() === 'h-hws' && ( + portion.index === 1 || portion.indexInMatch === last$hwsIdx + )) { + $elmt.classList.add( 'quote-inner' ) + } + return portion.text +} + +function curveQuote( portion ) { + var $elmt = portion.node.parentNode + + if ( $elmt.nodeName.toLowerCase() === 'h-hws' ) { + $elmt.classList.add( 'quote-outer' ) + } + return portion.text +} + +$.extend( Han, { + renderHWS: function( context, strict ) { + // Elements to be filtered according to the + // HWS rendering mode. + var AVOID = strict + ? 'textarea, code, kbd, samp, pre' + : 'textarea' + + var mode = strict ? 'strict' : 'base' + var context = context || document + var finder = Han.find( context ) + + finder + .avoid( AVOID ) + + // Basic situations: + // - 字a => 字a + // - A字 => A字 + .replace( Han.TYPESET.hws[ mode ][0], firstStepLabel ) + .replace( Han.TYPESET.hws[ mode ][1], firstStepLabel ) + + // Convert text nodes `` into real element nodes: + .replace( new RegExp( '(' + hws + ')+', 'g' ), real$hwsElmt ) + + // Deal with: + // - '' => '字' + // - "" => "字" + .replace( /([\'"])\s(.+?)\s\1/g, apostrophe ) + + // Deal with: + // - “字” + // - ‘字’ + .replace( /\s[‘“]/g, curveQuote ) + .replace( /[’”]\s/g, curveQuote ) + .normalize() + + // Return the finder instance for future usage + return finder + } +}) + +$.extend( Han.fn, { + renderHWS: function( strict ) { + Han.renderHWS( this.context, strict ) + return this + }, + + revertHWS: function() { + $.tag( 'h-hws', this.context ) + .forEach(function( hws ) { + $.remove( hws ) + }) + this.HWS = [] + return this + } +}) + +var HANGABLE_CLASS = 'bd-hangable' +var HANGABLE_AVOID = 'h-char.bd-hangable' +var HANGABLE_CS_HTML = '' + +var matches = Han.find.matches + +function detectSpaceFont() { + var div = $.create( 'div' ) + var ret + + div.innerHTML = 'a ba b' + body.appendChild( div ) + ret = div.firstChild.offsetWidth !== div.lastChild.offsetWidth + $.remove( div ) + return ret +} + +function insertHangableCS( $jinze ) { + var $cs = $jinze.nextSibling + + if ( $cs && matches( $cs, 'h-cs.jinze-outer' )) { + $cs.classList.add( 'hangable-outer' ) + } else { + $jinze.insertAdjacentHTML( + 'afterend', + HANGABLE_CS_HTML + ) + } +} + +Han.support['han-space'] = detectSpaceFont() + +$.extend( Han, { + detectSpaceFont: detectSpaceFont, + isSpaceFontLoaded: detectSpaceFont(), + + renderHanging: function( context ) { + var context = context || document + var finder = Han.find( context ) + + finder + .avoid( 'textarea, code, kbd, samp, pre' ) + .avoid( HANGABLE_AVOID ) + .replace( + TYPESET.jinze.hanging, + function( portion ) { + if ( /^[\x20\t\r\n\f]+$/.test( portion.text )) { + return '' + } + + var $elmt = portion.node.parentNode + var $jinze, $new, $bd, biaodian + + if ( $jinze = $.parent( $elmt, 'h-jinze' )) { + insertHangableCS( $jinze ) + } + + biaodian = portion.text.trim() + + $new = Han.createBDChar( biaodian ) + $new.innerHTML = '' + biaodian + '' + $new.classList.add( HANGABLE_CLASS ) + + $bd = $.parent( $elmt, 'h-char.biaodian' ) + + return !$bd + ? $new + : (function() { + $bd.classList.add( HANGABLE_CLASS ) + + return matches( $elmt, 'h-inner, h-inner *' ) + ? biaodian + : $new.firstChild + })() + } + ) + return finder + } +}) + +$.extend( Han.fn, { + renderHanging: function() { + var classList = this.condition.classList + Han.isSpaceFontLoaded = detectSpaceFont() + + if ( + Han.isSpaceFontLoaded && + classList.contains( 'no-han-space' ) + ) { + classList.remove( 'no-han-space' ) + classList.add( 'han-space' ) + } + + Han.renderHanging( this.context ) + return this + }, + + revertHanging: function() { + $.qsa( + 'h-char.bd-hangable, h-cs.hangable-outer', + this.context + ).forEach(function( $elmt ) { + var classList = $elmt.classList + classList.remove( 'bd-hangable' ) + classList.remove( 'hangable-outer' ) + }) + return this + } +}) + +var JIYA_CLASS = 'bd-jiya' +var JIYA_AVOID = 'h-char.bd-jiya' +var CONSECUTIVE_CLASS = 'bd-consecutive' +var JIYA_CS_HTML = '' + +var matches = Han.find.matches + +function trimBDClass( clazz ) { + return clazz.replace( + /(biaodian|cjk|bd-jiya|bd-consecutive|bd-hangable)/gi, '' + ).trim() +} + +function charifyBiaodian( portion ) { + var biaodian = portion.text + var $elmt = portion.node.parentNode + var $bd = $.parent( $elmt, 'h-char.biaodian' ) + var $new = Han.createBDChar( biaodian ) + var $jinze + + $new.innerHTML = '' + biaodian + '' + $new.classList.add( JIYA_CLASS ) + + if ( $jinze = $.parent( $elmt, 'h-jinze' )) { + insertJiyaCS( $jinze ) + } + + return !$bd + ? $new + : (function() { + $bd.classList.add( JIYA_CLASS ) + + return matches( $elmt, 'h-inner, h-inner *' ) + ? biaodian + : $new.firstChild + })() +} + +var prevBDType, $$prevCS + +function locateConsecutiveBD( portion ) { + var prev = prevBDType + var $elmt = portion.node.parentNode + var $bd = $.parent( $elmt, 'h-char.biaodian' ) + var $jinze = $.parent( $bd, 'h-jinze' ) + var classList + + classList = $bd.classList + + if ( prev ) { + $bd.setAttribute( 'prev', prev ) + } + + if ( $$prevCS && classList.contains( 'bd-open' )) { + $$prevCS.pop().setAttribute( 'next', 'bd-open' ) + } + + $$prevCS = undefined + + if ( portion.isEnd ) { + prevBDType = undefined + classList.add( CONSECUTIVE_CLASS, 'end-portion' ) + } else { + prevBDType = trimBDClass($bd.getAttribute( 'class' )) + classList.add( CONSECUTIVE_CLASS ) + } + + if ( $jinze ) { + $$prevCS = locateCS( $jinze, { + prev: prev, + 'class': trimBDClass($bd.getAttribute( 'class' )) + }) + } + return portion.text +} + +function insertJiyaCS( $jinze ) { + if ( + matches( $jinze, '.tou, .touwei' ) && + !matches( $jinze.previousSibling, 'h-cs.jiya-outer' ) + ) { + $jinze.insertAdjacentHTML( 'beforebegin', JIYA_CS_HTML ) + } + if ( + matches( $jinze, '.wei, .touwei' ) && + !matches( $jinze.nextSibling, 'h-cs.jiya-outer' ) + ) { + $jinze.insertAdjacentHTML( 'afterend', JIYA_CS_HTML ) + } +} + +function locateCS( $jinze, attr ) { + var $prev, $next + + if (matches( $jinze, '.tou, .touwei' )) { + $prev = $jinze.previousSibling + + if (matches( $prev, 'h-cs' )) { + $prev.className = 'jinze-outer jiya-outer' + $prev.setAttribute( 'prev', attr.prev ) + } + } + if (matches( $jinze, '.wei, .touwei' )) { + $next = $jinze.nextSibling + + if (matches( $next, 'h-cs' )) { + $next.className = 'jinze-outer jiya-outer ' + attr[ 'class' ] + $next.removeAttribute( 'prev' ) + } + } + return [ $prev, $next ] +} + +Han.renderJiya = function( context ) { + var context = context || document + var finder = Han.find( context ) + + finder + .avoid( 'textarea, code, kbd, samp, pre, h-cs' ) + + .avoid( JIYA_AVOID ) + .charify({ + avoid: false, + biaodian: charifyBiaodian + }) + // End avoiding `JIYA_AVOID`: + .endAvoid() + + .avoid( 'textarea, code, kbd, samp, pre, h-cs' ) + .replace( TYPESET.group.biaodian[0], locateConsecutiveBD ) + .replace( TYPESET.group.biaodian[1], locateConsecutiveBD ) + + return finder +} + +$.extend( Han.fn, { + renderJiya: function() { + Han.renderJiya( this.context ) + return this + }, + + revertJiya: function() { + $.qsa( + 'h-char.bd-jiya, h-cs.jiya-outer', + this.context + ).forEach(function( $elmt ) { + var classList = $elmt.classList + classList.remove( 'bd-jiya' ) + classList.remove( 'jiya-outer' ) + }) + return this + } +}) + +var QUERY_RU_W_ANNO = 'h-ru[annotation]' +var SELECTOR_TO_IGNORE = 'textarea, code, kbd, samp, pre' + +function createCompareFactory( font, treat, control ) { + return function() { + var a = Han.localize.writeOnCanvas( treat, font ) + var b = Han.localize.writeOnCanvas( control, font ) + return Han.localize.compareCanvases( a, b ) + } +} + +function isVowelCombLigaNormal() { + return createCompareFactory( '"Romanization Sans"', '\u0061\u030D', '\uDB80\uDC61' ) +} + +function isVowelICombLigaNormal() { + return createCompareFactory( '"Romanization Sans"', '\u0069\u030D', '\uDB80\uDC69' ) +} + +function isZhuyinCombLigaNormal() { + return createCompareFactory( '"Zhuyin Kaiti"', '\u31B4\u0358', '\uDB8C\uDDB4' ) +} + +function createSubstFactory( regexToSubst ) { + return function( context ) { + var context = context || document + var finder = Han.find( context ).avoid( SELECTOR_TO_IGNORE ) + + regexToSubst + .forEach(function( pattern ) { + finder + .replace( + new RegExp( pattern[ 0 ], 'ig' ), + function( portion, match ) { + var ret = $.clone( charCombLiga ) + + // Put the original content in an inner container + // for better presentational effect of hidden text + ret.innerHTML = '' + match[0] + '' + ret.setAttribute( 'display-as', pattern[ 1 ] ) + return portion.index === 0 ? ret : '' + } + ) + }) + return finder + } +} + +var charCombLiga = $.create( 'h-char', 'comb-liga' ) + +$.extend( Han, { + isVowelCombLigaNormal: isVowelCombLigaNormal(), + isVowelICombLigaNormal: isVowelICombLigaNormal(), + isZhuyinCombLigaNormal: isZhuyinCombLigaNormal(), + + isCombLigaNormal: isVowelICombLigaNormal()(), // ### Deprecated + + substVowelCombLiga: createSubstFactory( Han.TYPESET[ 'display-as' ][ 'comb-liga-vowel' ] ), + substZhuyinCombLiga: createSubstFactory( Han.TYPESET[ 'display-as' ][ 'comb-liga-zhuyin' ] ), + substCombLigaWithPUA: createSubstFactory( Han.TYPESET[ 'display-as' ][ 'comb-liga-pua' ] ), + + substInaccurateChar: function( context ) { + var context = context || document + var finder = Han.find( context ) + + finder.avoid( SELECTOR_TO_IGNORE ) + + Han.TYPESET[ 'inaccurate-char' ] + .forEach(function( pattern ) { + finder + .replace( + new RegExp( pattern[ 0 ], 'ig' ), + pattern[ 1 ] + ) + }) + } +}) + +$.extend( Han.fn, { + 'comb-liga-vowel': null, + 'comb-liga-vowel-i': null, + 'comb-liga-zhuyin': null, + 'inaccurate-char': null, + + substVowelCombLiga: function() { + this['comb-liga-vowel'] = Han.substVowelCombLiga( this.context ) + return this + }, + + substVowelICombLiga: function() { + this['comb-liga-vowel-i'] = Han.substVowelICombLiga( this.context ) + return this + }, + + substZhuyinCombLiga: function() { + this['comb-liga-zhuyin'] = Han.substZhuyinCombLiga( this.context ) + return this + }, + + substCombLigaWithPUA: function() { + if ( !Han.isVowelCombLigaNormal()) { + this['comb-liga-vowel'] = Han.substVowelCombLiga( this.context ) + } else if ( !Han.isVowelICombLigaNormal()) { + this['comb-liga-vowel-i'] = Han.substVowelICombLiga( this.context ) + } + + if ( !Han.isZhuyinCombLigaNormal()) { + this['comb-liga-zhuyin'] = Han.substZhuyinCombLiga( this.context ) + } + return this + }, + + revertVowelCombLiga: function() { + try { + this['comb-liga-vowel'].revert( 'all' ) + } catch (e) {} + return this + }, + + revertVowelICombLiga: function() { + try { + this['comb-liga-vowel-i'].revert( 'all' ) + } catch (e) {} + return this + }, + + revertZhuyinCombLiga: function() { + try { + this['comb-liga-zhuyin'].revert( 'all' ) + } catch (e) {} + return this + }, + + revertCombLigaWithPUA: function() { + try { + this['comb-liga-vowel'].revert( 'all' ) + this['comb-liga-vowel-i'].revert( 'all' ) + this['comb-liga-zhuyin'].revert( 'all' ) + } catch (e) {} + return this + }, + + substInaccurateChar: function() { + this['inaccurate-char'] = Han.substInaccurateChar( this.context ) + return this + }, + + revertInaccurateChar: function() { + try { + this['inaccurate-char'].revert( 'all' ) + } catch (e) {} + return this + } +}) + +window.addEventListener( 'DOMContentLoaded', function() { + var initContext + + // Use the shortcut under the default situation + if ( root.classList.contains( 'han-init' )) { + Han.init() + + // Consider ‘a configured context’ the special + // case of the default situation. Will have to + // replace the `Han.init` with the instance as + // well (for future usage). + } else if ( initContext = document.querySelector( '.han-init-context' )) { + Han.init = Han( initContext ).render() + } +}) + +// Expose to global namespace +if ( typeof noGlobalNS === 'undefined' || noGlobalNS === false ) { + window.Han = Han +} + +return Han +}); + diff --git a/lib/Han/dist/han.min.css b/lib/Han/dist/han.min.css new file mode 100644 index 0000000..39ce287 --- /dev/null +++ b/lib/Han/dist/han.min.css @@ -0,0 +1,6 @@ +@charset "UTF-8"; + +/*! 漢字標準格式 v3.3.0 | MIT License | css.hanzi.co */ +/*! Han.css: the CSS typography framework optimised for Hanzi */ + +progress,sub,sup{vertical-align:baseline}button,hr,input,select{overflow:visible}[type=checkbox],[type=radio],legend{box-sizing:border-box;padding:0}pre,textarea{overflow:auto}[zhuyin] [length="0"],article blockquote,article blockquote blockquote{margin-right:0}html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent;text-decoration:inherit}a:active,a:hover{outline-width:0}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}svg:not(:root){overflow:hidden}code,kbd,pre,samp{font-size:1em}figure{margin:1em 40px}hr{box-sizing:content-box;height:0}button,input,select,textarea{font:inherit;margin:0}optgroup{font-weight:700}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{cursor:pointer}[disabled]{cursor:default}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}button:-moz-focusring,input:-moz-focusring{outline:ButtonText dotted 1px}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{color:inherit;display:table;max-width:100%;white-space:normal}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}html{line-height:1.3;-webkit-font-smoothing:subpixel-antialiased}ol,ul{padding-left:2em}blockquote,figure{margin-left:2em;margin-right:2em}address,cite:lang(ja),cite:lang(zh),i:lang(ja),i:lang(zh),var:lang(ja),var:lang(zh){font-style:inherit}pre{white-space:pre;word-wrap:normal}em:lang(ja),em:lang(zh){-moz-text-emphasis:filled circle;-webkit-text-emphasis:filled circle;text-emphasis:filled circle;-moz-text-emphasis-position:under;-webkit-text-emphasis-position:under;text-emphasis-position:under;font-style:inherit;border-bottom:2px dotted;padding-bottom:.05em;border-bottom-width:-webkit-calc(0px);padding-bottom:-webkit-calc(0px)}em:lang(ja){-moz-text-emphasis:filled sesame;-webkit-text-emphasis:filled sesame;text-emphasis:filled sesame;-moz-text-emphasis-position:over;-webkit-text-emphasis-position:over;text-emphasis-position:over}dfn:lang(ja),dfn:lang(zh){font-style:inherit;font-weight:bolder}q,q:lang(en),q:lang(zh-CN){quotes:"\201c" "\201d" "\2018" "\2019" "\201c" "\201d" "\2018" "\2019" "\201c" "\201d" "\2018" "\2019"}q:lang(zh){quotes:"\300c" "\300d" "\300e" "\300f" "\300c" "\300d" "\300e" "\300f" "\300c" "\300d" "\300e" "\300f"}q:lang(en-GB){quotes:"\2018" "\2019" "\201c" "\201d" "\2018" "\2019" "\201c" "\201d" "\2018" "\2019" "\201c" "\201d"}q:before{content:open-quote}q:after{content:close-quote}q:lang(ja):after,q:lang(ja):before{content:none}code,kbd,pre,samp{font-family:monospace,monospace,sans-serif}.han-js-rendered del+del.adjacent,.han-js-rendered del+s.adjacent,.han-js-rendered ins.adjacent,.han-js-rendered s+del.adjacent,.han-js-rendered s+s.adjacent,.han-js-rendered u.adjacent,del+del,del+s,ins+ins,ins+u,s+del,s+s,u+ins,u+u{margin-left:.125em}ins,u{padding-bottom:.05em;border-bottom:1px solid;text-decoration:none}ruby rtc rt{display:inline;font-size:inherit}ruby.mps,ruby.zhuyin{display:ruby;-webkit-ruby-position:inter-character;ruby-position:inter-character}ruby.mps>rt,ruby.zhuyin>rt{-moz-transform:scale(.8);-ms-transform:scale(.8);-webkit-transform:scale(.8);transform:scale(.8);-moz-transform-origin:left center;-ms-transform-origin:left center;-webkit-transform-origin:left center;transform-origin:left center;font-size:.5em}ruby.mps>rt:empty,ruby.zhuyin>rt:empty{display:none}.han-js-rendered del+del,.han-js-rendered del+s,.han-js-rendered ins+ins,.han-js-rendered ins+u,.han-js-rendered s+del,.han-js-rendered s+s,.han-js-rendered u+ins,.han-js-rendered u+u{margin-left:auto}.textemphasis $han-text-emphasis-pf h-jinze,.textemphasis em:lang(ja) h-jinze,.textemphasis em:lang(zh) h-jinze{display:inline}.han-js-rendered em:lang(ja),.han-js-rendered em:lang(zh){padding-bottom:auto;border-bottom-width:0}.no-textemphasis em:lang(ja),.no-textemphasis em:lang(zh){line-height:2}.no-textemphasis em:lang(ja) h-char,.no-textemphasis em:lang(zh) h-char{position:relative;font-style:inherit}.no-textemphasis em:lang(ja) h-char:after,.no-textemphasis em:lang(zh) h-char:after,[zhuyin] h-zhuyin{font-style:normal;font-weight:400;-moz-text-emphasis:none;-webkit-text-emphasis:none;text-emphasis:none;text-decoration:none;text-indent:0}.no-textemphasis em:lang(ja) h-char:after,.no-textemphasis em:lang(zh) h-char:after{-moz-transform:scale(.5);-ms-transform:scale(.5);-webkit-transform:scale(.5);transform:scale(.5);position:absolute;left:50%;top:0;margin-left:-250%;overflow:hidden;display:inline-block;height:1em;width:500%;line-height:1;text-align:center;font-family:Georgia,"Times New Roman",Arial ,!important}em:lang(ja) h-char.biaodian,em:lang(ja) h-char.punct,em:lang(zh) h-char.biaodian,em:lang(zh) h-char.punct{-moz-text-emphasis:none;-webkit-text-emphasis:none;text-emphasis:none}.no-textemphasis em:lang(ja) h-char.biaodian:after,.no-textemphasis em:lang(ja) h-char.punct:after,.no-textemphasis em:lang(zh) h-char.biaodian:after,.no-textemphasis em:lang(zh) h-char.punct:after{content:none!important}.no-textemphasis em:lang(zh) h-char:after{margin-top:1em;content:"\25cf"}.no-textemphasis em:lang(ja) h-char:after{margin-top:-.7em;content:"\fe45"}h-ruby.zhuyin h-zhuyin,ruby.mps h-zhuyin,ruby.zhuyin h-zhuyin{position:relative;letter-spacing:0}h-ruby.zhuyin h-diao,ruby.mps h-diao,ruby.zhuyin h-diao{position:absolute;right:-.9em;bottom:.5em;display:block;font-size:1.5em}h-ruby.zhuyin h-diao h-char,ruby.mps h-diao h-char,ruby.zhuyin h-diao h-char{-webkit-writing-mode:horizontal-tb;writing-mode:horizontal-tb}h-ruby.zhuyin [diao="˙"] h-diao,ruby.mps [diao="˙"] h-diao,ruby.zhuyin [diao="˙"] h-diao{top:-.3em;right:auto;bottom:auto;left:0;font-size:1em}h-ruby.zhuyin [diao="󳆴"] h-diao,h-ruby.zhuyin [diao="󳆵"] h-diao,h-ruby.zhuyin [diao="󳆶"] h-diao,h-ruby.zhuyin [diao="󳆷"] h-diao,h-ruby.zhuyin [diao^="ㆴ"] h-diao,h-ruby.zhuyin [diao^="ㆵ"] h-diao,h-ruby.zhuyin [diao^="ㆶ"] h-diao,h-ruby.zhuyin [diao^="ㆷ"] h-diao,ruby.mps [diao="󳆴"] h-diao,ruby.mps [diao="󳆵"] h-diao,ruby.mps [diao="󳆶"] h-diao,ruby.mps [diao="󳆷"] h-diao,ruby.mps [diao^="ㆴ"] h-diao,ruby.mps [diao^="ㆵ"] h-diao,ruby.mps [diao^="ㆶ"] h-diao,ruby.mps [diao^="ㆷ"] h-diao,ruby.zhuyin [diao="󳆴"] h-diao,ruby.zhuyin [diao="󳆵"] h-diao,ruby.zhuyin [diao="󳆶"] h-diao,ruby.zhuyin [diao="󳆷"] h-diao,ruby.zhuyin [diao^="ㆴ"] h-diao,ruby.zhuyin [diao^="ㆵ"] h-diao,ruby.zhuyin [diao^="ㆶ"] h-diao,ruby.zhuyin [diao^="ㆷ"] h-diao{right:-1em;bottom:-.125em;font-size:1em}h-ru[annotation]{position:relative;display:inline-table;border-collapse:collapse;border-spacing:0;line-height:1.1;text-align:center;vertical-align:1em}h-ru[annotation]>rt,h-ru[order="0"]>rt,h-ruby[rightangle][doubleline] h-ru[order="0"]>rt{display:table-header-group}h-ru[annotation]>h-ru[annotation]{vertical-align:-.1em}h-ru[annotation]>h-ru,h-ru[annotation]>rb,h-ru[annotation]>rt{line-height:1;text-align:center}h-ru[annotation]>rt{height:1em;font-size:.5em;white-space:nowrap;word-break:normal}h-ru[annotation]>rt:after,h-ru[annotation]>rt:before{content:"\2006"}h-ru[order="1"]>rt,h-ruby[rightangle] h-ru[order="0"]>rt,h-ruby[rightangle][doubleline] h-ru[order="1"]>rt{display:table-footer-group}[zhuyin],[zhuyin] h-zhuyin,[zhuyin] h-zhuyin>*,h-jinze,h-word{display:inline-block}h-ru[order="0"]>h-ru[order="1"]{vertical-align:.15em}h-ruby[rightangle][doubleline] h-ru[order="0"] rt{line-height:1.5}h-ruby[rightangle][doubleline] h-ru[annotation]{vertical-align:.5em}[zhuyin] h-zhuyin{line-height:normal;position:relative;height:1em;width:.4em;vertical-align:text-top}[zhuyin] h-zhuyin>*{-moz-transform:scale(.4);-ms-transform:scale(.4);-webkit-transform:scale(.4);transform:scale(.4);-moz-transform-origin:left top;-ms-transform-origin:left top;-webkit-transform-origin:left top;transform-origin:left top}[zhuyin] h-yin{position:absolute;left:0;height:1em;vertical-align:top;line-height:1}[zhuyin] h-diao{position:absolute;bottom:0;right:-.9em;line-height:1}[zhuyin] [length="0"] h-zhuyin,[zhuyin] h-diao:empty,[zhuyin] h-yin:empty{display:none}[zhuyin] [length="1"] h-yin{top:.3em}[zhuyin] [length="1"] h-diao{bottom:0}[zhuyin] [length="2"] h-yin{top:.05em}[zhuyin] [length="2"] h-diao{bottom:-.3em}[zhuyin] [length="3"] h-yin{top:-.05em;line-height:.85}[zhuyin] [length="3"] h-diao{bottom:-.35em}[zhuyin] [diao="˙"] h-diao{top:0;right:auto;bottom:auto;left:.06em}[zhuyin] [diao="˙"] [length="1"] h-diao{top:.15em}[zhuyin] [diao="˙"] [length="2"] h-diao{top:-.05em}[zhuyin] [diao="˙"] [length="3"] h-diao{top:-.2em}[zhuyin] [diao="˪"] h-diao,[zhuyin] [diao="˫"] h-diao{-moz-transform:scale(.6);-ms-transform:scale(.6);-webkit-transform:scale(.6);transform:scale(.6);-moz-transform-origin:left top;-ms-transform-origin:left top;-webkit-transform-origin:left top;transform-origin:left top}[zhuyin] [diao="󳆴"] h-diao,[zhuyin] [diao="󳆵"] h-diao,[zhuyin] [diao="󳆶"] h-diao,[zhuyin] [diao="󳆷"] h-diao,[zhuyin] [diao^="ㆴ"] h-diao,[zhuyin] [diao^="ㆵ"] h-diao,[zhuyin] [diao^="ㆶ"] h-diao,[zhuyin] [diao^="ㆷ"] h-diao{bottom:-.6em;margin-right:.3em}[zhuyin]{margin-right:.2em;line-height:1.8}[rightangle] h-ru[annotation]{vertical-align:0;line-height:1}[rightangle] rt:after{content:"";display:inline-block;width:1.2em}h-ru h-ru[zhuyin]{margin-top:-.4em;margin-bottom:-.2em;line-height:1.8}h-jinze,h-word{text-indent:0}@font-face{font-family:"Han Heiti";src:local("Hiragino Sans GB"),local("Lantinghei TC Extralight"),local("Lantinghei SC Extralight"),local(FZLTXHB--B51-0),local(FZLTZHK--GBK1-0),local(".PingFang SC Light"),local(".PingFang TC Light"),local(".PingFang-SC-Light"),local(".PingFang-TC-Light"),local(".PingFang SC"),local(".PingFang TC"),local("Heiti SC Light"),local(STHeitiSC-Light),local("Heiti SC"),local("Heiti TC Light"),local(STHeitiTC-Light),local("Heiti TC"),local("Microsoft Yahei"),local("Microsoft Jhenghei"),local("Noto Sans CJK KR"),local("Noto Sans CJK JP"),local("Noto Sans CJK SC"),local("Noto Sans CJK TC"),local("Source Han Sans K"),local("Source Han Sans KR"),local("Source Han Sans JP"),local("Source Han Sans CN"),local("Source Han Sans HK"),local("Source Han Sans TW"),local("Source Han Sans TWHK"),local("Droid Sans Fallback")}@font-face{unicode-range:U+4E00-9FFF,U+3400-4DB5,U+20000-2A6D6,U+2A700-2B734,U+2B740-2B81D,U+FA0E-FA0F,U+FA11,U+FA13-FA14,U+FA1F,U+FA21,U+FA23,U+FA24,U+FA27-FA29,U+3040-309F,U+30A0-30FF,U+3099-309E,U+FF66-FF9F,U+3007,U+31C0-31E3,U+2F00-2FD5,U+2E80-2EF3;font-family:"Han Heiti";src:local(YuGothic),local("Hiragino Kaku Gothic ProN"),local("Hiragino Kaku Gothic Pro")}@font-face{font-family:"Han Heiti CNS";src:local(".PingFang TC Light"),local(".PingFang-TC-Light"),local(".PingFang TC"),local("Heiti TC Light"),local(STHeitiTC-Light),local("Heiti TC"),local("Lantinghei TC Extralight"),local(FZLTXHB--B51-0),local("Lantinghei TC"),local("Microsoft Jhenghei"),local("Microsoft Yahei"),local("Noto Sans CJK TC"),local("Source Han Sans TC"),local("Source Han Sans TW"),local("Source Han Sans TWHK"),local("Source Han Sans HK"),local("Droid Sans Fallback")}@font-face{font-family:"Han Heiti GB";src:local("Hiragino Sans GB"),local(".PingFang SC Light"),local(".PingFang-SC-Light"),local(".PingFang SC"),local("Lantinghei SC Extralight"),local(FZLTXHK--GBK1-0),local("Lantinghei SC"),local("Heiti SC Light"),local(STHeitiSC-Light),local("Heiti SC"),local("Microsoft Yahei"),local("Noto Sans CJK SC"),local("Source Han Sans SC"),local("Source Han Sans CN"),local("Droid Sans Fallback")}@font-face{font-family:"Han Heiti";font-weight:600;src:local("Hiragino Sans GB W6"),local(HiraginoSansGB-W6),local("Lantinghei TC Demibold"),local("Lantinghei SC Demibold"),local(FZLTZHB--B51-0),local(FZLTZHK--GBK1-0),local(".PingFang-SC-Semibold"),local(".PingFang-TC-Semibold"),local("Heiti SC Medium"),local("STHeitiSC-Medium"),local("Heiti SC"),local("Heiti TC Medium"),local("STHeitiTC-Medium"),local("Heiti TC"),local("Microsoft YaHei Bold"),local("Microsoft Jhenghei Bold"),local(MicrosoftYaHei-Bold),local(MicrosoftJhengHeiBold),local("Microsoft YaHei"),local("Microsoft Jhenghei"),local("Noto Sans CJK KR Bold"),local("Noto Sans CJK JP Bold"),local("Noto Sans CJK SC Bold"),local("Noto Sans CJK TC Bold"),local(NotoSansCJKkr-Bold),local(NotoSansCJKjp-Bold),local(NotoSansCJKsc-Bold),local(NotoSansCJKtc-Bold),local("Source Han Sans K Bold"),local(SourceHanSansK-Bold),local("Source Han Sans K"),local("Source Han Sans KR Bold"),local("Source Han Sans JP Bold"),local("Source Han Sans CN Bold"),local("Source Han Sans HK Bold"),local("Source Han Sans TW Bold"),local("Source Han Sans TWHK Bold"),local("SourceHanSansKR-Bold"),local("SourceHanSansJP-Bold"),local("SourceHanSansCN-Bold"),local("SourceHanSansHK-Bold"),local("SourceHanSansTW-Bold"),local("SourceHanSansTWHK-Bold"),local("Source Han Sans KR"),local("Source Han Sans CN"),local("Source Han Sans HK"),local("Source Han Sans TW"),local("Source Han Sans TWHK")}@font-face{unicode-range:U+4E00-9FFF,U+3400-4DB5,U+20000-2A6D6,U+2A700-2B734,U+2B740-2B81D,U+FA0E-FA0F,U+FA11,U+FA13-FA14,U+FA1F,U+FA21,U+FA23,U+FA24,U+FA27-FA29,U+3040-309F,U+30A0-30FF,U+3099-309E,U+FF66-FF9F,U+3007,U+31C0-31E3,U+2F00-2FD5,U+2E80-2EF3;font-family:"Han Heiti";font-weight:600;src:local("YuGothic Bold"),local("Hiragino Kaku Gothic ProN W6"),local("Hiragino Kaku Gothic Pro W6"),local(YuGo-Bold),local(HiraKakuProN-W6),local(HiraKakuPro-W6)}@font-face{font-family:"Han Heiti CNS";font-weight:600;src:local(".PingFang TC Semibold"),local(".PingFang-TC-Semibold"),local("Heiti TC Medium"),local("STHeitiTC-Medium"),local("Heiti TC"),local("Lantinghei TC Demibold"),local(FZLTXHB--B51-0),local("Microsoft Jhenghei Bold"),local(MicrosoftJhengHeiBold),local("Microsoft Jhenghei"),local("Microsoft YaHei Bold"),local(MicrosoftYaHei-Bold),local("Noto Sans CJK TC Bold"),local(NotoSansCJKtc-Bold),local("Noto Sans CJK TC"),local("Source Han Sans TC Bold"),local("SourceHanSansTC-Bold"),local("Source Han Sans TC"),local("Source Han Sans TW Bold"),local("SourceHanSans-TW"),local("Source Han Sans TW"),local("Source Han Sans TWHK Bold"),local("SourceHanSans-TWHK"),local("Source Han Sans TWHK"),local("Source Han Sans HK"),local("SourceHanSans-HK"),local("Source Han Sans HK")}@font-face{font-family:"Han Heiti GB";font-weight:600;src:local("Hiragino Sans GB W6"),local(HiraginoSansGB-W6),local(".PingFang SC Semibold"),local(".PingFang-SC-Semibold"),local("Lantinghei SC Demibold"),local(FZLTZHK--GBK1-0),local("Heiti SC Medium"),local("STHeitiSC-Medium"),local("Heiti SC"),local("Microsoft YaHei Bold"),local(MicrosoftYaHei-Bold),local("Microsoft YaHei"),local("Noto Sans CJK SC Bold"),local(NotoSansCJKsc-Bold),local("Noto Sans CJK SC"),local("Source Han Sans SC Bold"),local("SourceHanSansSC-Bold"),local("Source Han Sans CN Bold"),local("SourceHanSansCN-Bold"),local("Source Han Sans SC"),local("Source Han Sans CN")}@font-face{font-family:"Han Heiti";src:local("Hiragino Sans GB"),local("Lantinghei TC Extralight"),local("Lantinghei SC Extralight"),local(FZLTXHB--B51-0),local(FZLTZHK--GBK1-0),local(".PingFang SC Light"),local(".PingFang TC Light"),local(".PingFang-SC-Light"),local(".PingFang-TC-Light"),local(".PingFang SC"),local(".PingFang TC"),local("Heiti SC Light"),local("STHeitiSC-Light"),local("Heiti SC"),local("Heiti TC Light"),local("STHeitiTC-Light"),local("Heiti TC"),local("Microsoft Yahei"),local("Microsoft Jhenghei"),local("Noto Sans CJK KR"),local("Noto Sans CJK JP"),local("Noto Sans CJK SC"),local("Noto Sans CJK TC"),local("Source Han Sans K"),local("Source Han Sans KR"),local("Source Han Sans JP"),local("Source Han Sans CN"),local("Source Han Sans HK"),local("Source Han Sans TW"),local("Source Han Sans TWHK"),local("Droid Sans Fallback");unicode-range:U+270C}@font-face{font-family:"Han Heiti";font-weight:600;src:local("Hiragino Sans GB W6"),local(HiraginoSansGB-W6),local("Lantinghei TC Demibold"),local("Lantinghei SC Demibold"),local(FZLTZHB--B51-0),local(FZLTZHK--GBK1-0),local(".PingFang-SC-Semibold"),local(".PingFang-TC-Semibold"),local("Heiti SC Medium"),local("STHeitiSC-Medium"),local("Heiti SC"),local("Heiti TC Medium"),local("STHeitiTC-Medium"),local("Heiti TC"),local("Microsoft YaHei Bold"),local("Microsoft Jhenghei Bold"),local(MicrosoftYaHei-Bold),local(MicrosoftJhengHeiBold),local("Microsoft YaHei"),local("Microsoft Jhenghei"),local("Noto Sans CJK KR Bold"),local("Noto Sans CJK JP Bold"),local("Noto Sans CJK SC Bold"),local("Noto Sans CJK TC Bold"),local(NotoSansCJKkr-Bold),local(NotoSansCJKjp-Bold),local(NotoSansCJKsc-Bold),local(NotoSansCJKtc-Bold),local("Source Han Sans K Bold"),local(SourceHanSansK-Bold),local("Source Han Sans K"),local("Source Han Sans KR Bold"),local("Source Han Sans JP Bold"),local("Source Han Sans CN Bold"),local("Source Han Sans HK Bold"),local("Source Han Sans TW Bold"),local("Source Han Sans TWHK Bold"),local("SourceHanSansKR-Bold"),local("SourceHanSansJP-Bold"),local("SourceHanSansCN-Bold"),local("SourceHanSansHK-Bold"),local("SourceHanSansTW-Bold"),local("SourceHanSansTWHK-Bold"),local("Source Han Sans KR"),local("Source Han Sans CN"),local("Source Han Sans HK"),local("Source Han Sans TW"),local("Source Han Sans TWHK");unicode-range:U+270C}@font-face{font-family:"Han Songti";src:local("Songti SC Regular"),local(STSongti-SC-Regular),local("Songti SC"),local("Songti TC Regular"),local(STSongti-TC-Regular),local("Songti TC"),local(STSong),local("Lisong Pro"),local(SimSun),local(PMingLiU)}@font-face{unicode-range:U+4E00-9FFF,U+3400-4DB5,U+20000-2A6D6,U+2A700-2B734,U+2B740-2B81D,U+FA0E-FA0F,U+FA11,U+FA13-FA14,U+FA1F,U+FA21,U+FA23,U+FA24,U+FA27-FA29,U+3040-309F,U+30A0-30FF,U+3099-309E,U+FF66-FF9F,U+3007,U+31C0-31E3,U+2F00-2FD5,U+2E80-2EF3;font-family:"Han Songti";src:local(YuMincho),local("Hiragino Mincho ProN"),local("Hiragino Mincho Pro"),local("MS Mincho")}@font-face{font-family:"Han Songti CNS";src:local("Songti TC Regular"),local(STSongti-TC-Regular),local("Songti TC"),local("Lisong Pro"),local("Songti SC Regular"),local(STSongti-SC-Regular),local("Songti SC"),local(STSong),local(PMingLiU),local(SimSun)}@font-face{font-family:"Han Songti GB";src:local("Songti SC Regular"),local(STSongti-SC-Regular),local("Songti SC"),local(STSong),local(SimSun),local(PMingLiU)}@font-face{font-family:"Han Songti";font-weight:600;src:local("STSongti SC Bold"),local("STSongti TC Bold"),local(STSongti-SC-Bold),local(STSongti-TC-Bold),local("STSongti SC"),local("STSongti TC")}@font-face{unicode-range:U+4E00-9FFF,U+3400-4DB5,U+20000-2A6D6,U+2A700-2B734,U+2B740-2B81D,U+FA0E-FA0F,U+FA11,U+FA13-FA14,U+FA1F,U+FA21,U+FA23,U+FA24,U+FA27-FA29,U+3040-309F,U+30A0-30FF,U+3099-309E,U+FF66-FF9F,U+3007,U+31C0-31E3,U+2F00-2FD5,U+2E80-2EF3;font-family:"Han Songti";font-weight:600;src:local("YuMincho Demibold"),local("Hiragino Mincho ProN W6"),local("Hiragino Mincho Pro W6"),local(YuMin-Demibold),local(HiraMinProN-W6),local(HiraMinPro-W6),local(YuMincho),local("Hiragino Mincho ProN"),local("Hiragino Mincho Pro")}@font-face{font-family:"Han Songti CNS";font-weight:600;src:local("STSongti TC Bold"),local("STSongti SC Bold"),local(STSongti-TC-Bold),local(STSongti-SC-Bold),local("STSongti TC"),local("STSongti SC")}@font-face{font-family:"Han Songti GB";font-weight:600;src:local("STSongti SC Bold"),local(STSongti-SC-Bold),local("STSongti SC")}@font-face{font-family:"Han Songti";src:local("Songti SC Regular"),local(STSongti-SC-Regular),local("Songti SC"),local("Songti TC Regular"),local(STSongti-TC-Regular),local("Songti TC"),local(STSongti),local("Lisong Pro"),local("MS Mincho"),local(SimSun),local(PMingLiU);unicode-range:U+270C}@font-face{font-family:"Han Songti";font-weight:600;src:local("Songti TC Bold"),local("Songti SC Bold"),local(STSongti-TC-Bold),local(STSongti-SC-Bold),local("Songti TC"),local("Songti SC");unicode-range:U+270C}@font-face{font-family:"Han Songti CNS";src:local("Songti TC Regular"),local("Lisong Pro"),local("Songti TC"),local("Songti SC Regular"),local(STSong),local("Songti SC"),local("MS Mincho"),local(PMingLiU),local(SimSun);unicode-range:U+270C}@font-face{font-family:"Han Songti CNS";font-weight:600;src:local("Songti TC Bold"),local("Songti SC Bold"),local(STSongti-TC-Bold),local(STSongti-SC-Bold),local("Songti TC"),local("Songti SC");unicode-range:U+270C}@font-face{font-family:"Han Songti GB";src:local("Songti SC"),local(STSong),local(SimSun);unicode-range:U+270C}@font-face{font-family:"Han Songti GB";font-weight:600;src:local("Songti SC Bold"),local(STSongti-SC-Bold),local("Songti SC");unicode-range:U+270C}@font-face{font-family:cursive;src:local("Kaiti TC Regular"),local(STKaiTi-TC-Regular),local("Kaiti TC"),local("Kaiti SC"),local(STKaiti),local(BiauKai),local("標楷體"),local(DFKaiShu-SB-Estd-BF),local(Kaiti),local(DFKai-SB)}@font-face{unicode-range:U+4E00-9FFF,U+3400-4DB5,U+20000-2A6D6,U+2A700-2B734,U+2B740-2B81D,U+FA0E-FA0F,U+FA11,U+FA13-FA14,U+FA1F,U+FA21,U+FA23,U+FA24,U+FA27-FA29,U+3040-309F,U+30A0-30FF,U+3099-309E,U+FF66-FF9F,U+3007,U+31C0-31E3,U+2F00-2FD5,U+2E80-2EF3;font-family:"Han Kaiti";src:local("Kaiti TC Regular"),local(STKaiTi-TC-Regular),local("Kaiti TC"),local("Kaiti SC"),local(STKaiti),local(BiauKai),local("標楷體"),local(DFKaiShu-SB-Estd-BF),local(Kaiti),local(DFKai-SB)}@font-face{unicode-range:U+4E00-9FFF,U+3400-4DB5,U+20000-2A6D6,U+2A700-2B734,U+2B740-2B81D,U+FA0E-FA0F,U+FA11,U+FA13-FA14,U+FA1F,U+FA21,U+FA23,U+FA24,U+FA27-FA29,U+3040-309F,U+30A0-30FF,U+3099-309E,U+FF66-FF9F,U+3007,U+31C0-31E3,U+2F00-2FD5,U+2E80-2EF3;font-family:"Han Kaiti CNS";src:local(BiauKai),local("標楷體"),local(DFKaiShu-SB-Estd-BF),local("Kaiti TC Regular"),local(STKaiTi-TC-Regular),local("Kaiti TC")}@font-face{unicode-range:U+4E00-9FFF,U+3400-4DB5,U+20000-2A6D6,U+2A700-2B734,U+2B740-2B81D,U+FA0E-FA0F,U+FA11,U+FA13-FA14,U+FA1F,U+FA21,U+FA23,U+FA24,U+FA27-FA29,U+3040-309F,U+30A0-30FF,U+3099-309E,U+FF66-FF9F,U+3007,U+31C0-31E3,U+2F00-2FD5,U+2E80-2EF3;font-family:"Han Kaiti GB";src:local("Kaiti SC Regular"),local(STKaiTi-SC-Regular),local("Kaiti SC"),local(STKaiti),local(Kai),local(Kaiti),local(DFKai-SB)}@font-face{font-family:cursive;font-weight:600;src:local("Kaiti TC Bold"),local(STKaiTi-TC-Bold),local("Kaiti SC Bold"),local(STKaiti-SC-Bold),local("Kaiti TC"),local("Kaiti SC")}@font-face{font-family:"Han Kaiti";font-weight:600;src:local("Kaiti TC Bold"),local(STKaiTi-TC-Bold),local("Kaiti SC Bold"),local(STKaiti-SC-Bold),local("Kaiti TC"),local("Kaiti SC")}@font-face{font-family:"Han Kaiti CNS";font-weight:600;src:local("Kaiti TC Bold"),local(STKaiTi-TC-Bold),local("Kaiti TC")}@font-face{font-family:"Han Kaiti GB";font-weight:600;src:local("Kaiti SC Bold"),local(STKaiti-SC-Bold)}@font-face{unicode-range:U+4E00-9FFF,U+3400-4DB5,U+20000-2A6D6,U+2A700-2B734,U+2B740-2B81D,U+FA0E-FA0F,U+FA11,U+FA13-FA14,U+FA1F,U+FA21,U+FA23,U+FA24,U+FA27-FA29,U+3040-309F,U+30A0-30FF,U+3099-309E,U+FF66-FF9F,U+3007,U+31C0-31E3,U+2F00-2FD5,U+2E80-2EF3;font-family:"Han Fangsong";src:local(STFangsong),local(FangSong)}@font-face{unicode-range:U+4E00-9FFF,U+3400-4DB5,U+20000-2A6D6,U+2A700-2B734,U+2B740-2B81D,U+FA0E-FA0F,U+FA11,U+FA13-FA14,U+FA1F,U+FA21,U+FA23,U+FA24,U+FA27-FA29,U+3040-309F,U+30A0-30FF,U+3099-309E,U+FF66-FF9F,U+3007,U+31C0-31E3,U+2F00-2FD5,U+2E80-2EF3;font-family:"Han Fangsong CNS";src:local(STFangsong),local(FangSong)}@font-face{unicode-range:U+4E00-9FFF,U+3400-4DB5,U+20000-2A6D6,U+2A700-2B734,U+2B740-2B81D,U+FA0E-FA0F,U+FA11,U+FA13-FA14,U+FA1F,U+FA21,U+FA23,U+FA24,U+FA27-FA29,U+3040-309F,U+30A0-30FF,U+3099-309E,U+FF66-FF9F,U+3007,U+31C0-31E3,U+2F00-2FD5,U+2E80-2EF3;font-family:"Han Fangsong GB";src:local(STFangsong),local(FangSong)}@font-face{font-family:"Biaodian Sans";src:local("Hiragino Sans GB"),local("Heiti SC"),local(STHeiti),local("MS Gothic"),local(SimSun);unicode-range:U+FF0E}@font-face{font-family:"Biaodian Serif";src:local("Hiragino Mincho ProN"),local("Hiragino Mincho Pro"),local("Songti SC"),local(STSong),local(SimSun);unicode-range:U+FF0E}@font-face{font-family:"Biaodian Pro Sans";src:local("Hiragino Sans GB"),local("Heiti SC"),local(STHeiti),local("MS Gothic"),local(SimSun);unicode-range:U+FF0E}@font-face{font-family:"Biaodian Pro Serif";src:local("Hiragino Mincho ProN"),local("Hiragino Mincho Pro"),local("Songti SC"),local(STSong),local(SimSun);unicode-range:U+FF0E}@font-face{font-family:"Biaodian Pro Sans CNS";src:local("Hiragino Sans GB"),local("Heiti SC"),local(STHeiti),local("MS Gothic"),local(SimSun);unicode-range:U+FF0E}@font-face{font-family:"Biaodian Pro Serif CNS";src:local("Hiragino Mincho ProN"),local("Hiragino Mincho Pro"),local("Songti SC"),local(STSong),local(SimSun);unicode-range:U+FF0E}@font-face{font-family:"Biaodian Pro Sans GB";src:local("Hiragino Sans GB"),local("Heiti SC"),local(STHeiti),local("MS Gothic"),local(SimSun);unicode-range:U+FF0E}@font-face{font-family:"Biaodian Pro Serif GB";src:local("Hiragino Mincho ProN"),local("Hiragino Mincho Pro"),local("Songti SC"),local(STSong),local(SimSun);unicode-range:U+FF0E}@font-face{font-family:"Biaodian Sans";src:local("Hiragino Sans GB"),local("Heiti SC"),local(STHeiti),local(SimSun);unicode-range:U+00B7}@font-face{font-family:"Biaodian Serif";src:local("Songti SC"),local(STSong),local("Heiti SC"),local(SimSun);unicode-range:U+00B7}@font-face{font-family:"Biaodian Pro Sans";src:local("Hiragino Sans GB"),local("Heiti SC"),local(STHeiti),local(SimSun);unicode-range:U+00B7}@font-face{font-family:"Biaodian Pro Serif";src:local("Songti SC"),local(STSong),local("Heiti SC"),local(SimSun);unicode-range:U+00B7}@font-face{font-family:"Biaodian Pro Sans CNS";src:local("Hiragino Sans GB"),local("Heiti SC"),local(STHeiti),local(SimSun);unicode-range:U+00B7}@font-face{font-family:"Biaodian Pro Serif CNS";src:local("Songti SC"),local(STSong),local("Heiti SC"),local(SimSun);unicode-range:U+00B7}@font-face{font-family:"Biaodian Pro Sans GB";src:local("Hiragino Sans GB"),local("Heiti SC"),local(STHeiti),local(SimSun);unicode-range:U+00B7}@font-face{font-family:"Biaodian Pro Serif GB";src:local("Songti SC"),local(STSong),local("Heiti SC"),local(SimSun);unicode-range:U+00B7}@font-face{font-family:"Biaodian Sans";src:url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype"),local("Hiragino Sans GB"),local("Hiragino Kaku Gothic ProN"),local("Hiragino Kaku Gothic Pro"),local("Microsoft Yahei"),local(SimSun);unicode-range:U+2014}@font-face{font-family:"Biaodian Serif";src:url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype"),local("Hiragino Mincho ProN"),local("Hiragino Mincho Pro"),local("Songti SC"),local(STSong),local("Microsoft Yahei"),local(SimSun);unicode-range:U+2014}@font-face{font-family:"Yakumono Sans";src:url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype"),local("Hiragino Kaku Gothic ProN"),local("Hiragino Kaku Gothic Pro"),local("Arial Unicode MS"),local("MS Gothic");unicode-range:U+2014}@font-face{font-family:"Yakumono Serif";src:url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype"),local("Hiragino Mincho ProN"),local("Hiragino Mincho Pro"),local("MS Mincho"),local("Microsoft Yahei");unicode-range:U+2014}@font-face{font-family:"Biaodian Pro Sans";src:url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype"),local("Hiragino Sans GB"),local("Hiragino Kaku Gothic ProN"),local("Hiragino Kaku Gothic Pro"),local("Microsoft Yahei"),local(SimSun);unicode-range:U+2014}@font-face{font-family:"Biaodian Pro Serif";src:url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype"),local("Hiragino Mincho ProN"),local("Hiragino Mincho Pro"),local("Songti SC"),local(STSong),local("Microsoft Yahei"),local(SimSun);unicode-range:U+2014}@font-face{font-family:"Biaodian Pro Sans CNS";src:url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype"),local("Hiragino Sans GB"),local("Hiragino Kaku Gothic ProN"),local("Hiragino Kaku Gothic Pro"),local("Microsoft Yahei"),local(SimSun);unicode-range:U+2014}@font-face{font-family:"Biaodian Pro Serif CNS";src:url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype"),local("Hiragino Mincho ProN"),local("Hiragino Mincho Pro"),local("Songti SC"),local(STSong),local("Microsoft Yahei"),local(SimSun);unicode-range:U+2014}@font-face{font-family:"Biaodian Pro Sans GB";src:url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype"),local("Hiragino Sans GB"),local("Hiragino Kaku Gothic ProN"),local("Hiragino Kaku Gothic Pro"),local("Microsoft Yahei"),local(SimSun);unicode-range:U+2014}@font-face{font-family:"Biaodian Pro Serif GB";src:url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype"),local("Hiragino Mincho ProN"),local("Hiragino Mincho Pro"),local("Songti SC"),local(STSong),local("Microsoft Yahei"),local(SimSun);unicode-range:U+2014}@font-face{font-family:"Biaodian Sans";src:url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype"),local("Hiragino Sans GB"),local("Hiragino Kaku Gothic ProN"),local("Hiragino Kaku Gothic Pro"),local(Meiryo),local("MS Gothic"),local(SimSun),local(PMingLiU);unicode-range:U+2026}@font-face{font-family:"Biaodian Serif";src:url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype"),local("Hiragino Mincho ProN"),local("Hiragino Mincho Pro"),local("Songti SC"),local("MS Mincho"),local(SimSun),local(PMingLiU);unicode-range:U+2026}@font-face{font-family:"Yakumono Sans";src:url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype"),local("Hiragino Kaku Gothic ProN"),local("Hiragino Kaku Gothic Pro"),local(Meiryo),local("MS Gothic");unicode-range:U+2026}@font-face{font-family:"Yakumono Serif";src:url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype"),local("Hiragino Mincho ProN"),local("Hiragino Mincho Pro"),local("MS Mincho");unicode-range:U+2026}@font-face{font-family:"Biaodian Pro Sans";src:url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype"),local("Hiragino Sans GB"),local("Hiragino Kaku Gothic ProN"),local("Hiragino Kaku Gothic Pro"),local(SimSun),local(PMingLiU);unicode-range:U+2026}@font-face{font-family:"Biaodian Pro Serif";src:url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype"),local("Hiragino Mincho ProN"),local("Hiragino Mincho Pro"),local("Songti SC"),local(SimSun),local(PMingLiU);unicode-range:U+2026}@font-face{font-family:"Biaodian Pro Sans CNS";src:url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype"),local("Hiragino Sans GB"),local("Hiragino Kaku Gothic ProN"),local("Hiragino Kaku Gothic Pro"),local(SimSun),local(PMingLiU);unicode-range:U+2026}@font-face{font-family:"Biaodian Pro Serif CNS";src:url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype"),local("Hiragino Mincho ProN"),local("Hiragino Mincho Pro"),local("Songti SC"),local(STSongti),local(SimSun),local(PMingLiU);unicode-range:U+2026}@font-face{font-family:"Biaodian Pro Sans GB";src:url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype"),local("Hiragino Sans GB"),local("Hiragino Kaku Gothic ProN"),local("Hiragino Kaku Gothic Pro"),local(SimSun),local(PMingLiU);unicode-range:U+2026}@font-face{font-family:"Biaodian Pro Serif GB";src:url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype"),local("Hiragino Mincho ProN"),local("Hiragino Mincho Pro"),local("Songti SC"),local(STSongti),local(SimSun),local(PMingLiU);unicode-range:U+2026}@font-face{font-family:"Biaodian Pro Sans GB";src:local("Hiragino Sans GB"),local("Heiti SC"),local(STHeiti),local(SimSun),local(PMingLiU);unicode-range:U+201C-201D,U+2018-2019}@font-face{font-family:"Biaodian Pro Sans GB";font-weight:700;src:local("Hiragino Sans GB"),local("Heiti SC"),local(STHeiti),local(SimSun),local(PMingLiU);unicode-range:U+201C-201D,U+2018-2019}@font-face{font-family:"Biaodian Pro Serif GB";src:local("Lisong Pro"),local("Heiti SC"),local(STHeiti),local(SimSun),local(PMingLiU);unicode-range:U+201C-201D,U+2018-2019}@font-face{font-family:"Biaodian Pro Serif GB";font-weight:700;src:local("Lisong Pro"),local("Heiti SC"),local(STHeiti),local(SimSun),local(PMingLiU);unicode-range:U+201C-201D,U+2018-2019}@font-face{font-family:"Biaodian Sans";src:local(Georgia),local("Times New Roman"),local(Arial),local("Droid Sans Fallback");unicode-range:U+25CF}@font-face{font-family:"Biaodian Serif";src:local(Georgia),local("Times New Roman"),local(Arial),local("Droid Sans Fallback");unicode-range:U+25CF}@font-face{font-family:"Biaodian Pro Sans";src:local(Georgia),local("Times New Roman"),local(Arial),local("Droid Sans Fallback");unicode-range:U+25CF}@font-face{font-family:"Biaodian Pro Serif";src:local(Georgia),local("Times New Roman"),local(Arial),local("Droid Sans Fallback");unicode-range:U+25CF}@font-face{font-family:"Biaodian Pro Sans CNS";src:local(Georgia),local("Times New Roman"),local(Arial),local("Droid Sans Fallback");unicode-range:U+25CF}@font-face{font-family:"Biaodian Pro Serif CNS";src:local(Georgia),local("Times New Roman"),local(Arial),local("Droid Sans Fallback");unicode-range:U+25CF}@font-face{font-family:"Biaodian Pro Sans GB";src:local(Georgia),local("Times New Roman"),local(Arial),local("Droid Sans Fallback");unicode-range:U+25CF}@font-face{font-family:"Biaodian Pro Serif GB";src:local(Georgia),local("Times New Roman"),local(Arial),local("Droid Sans Fallback");unicode-range:U+25CF}@font-face{font-family:"Biaodian Pro Sans";src:local("Hiragino Kaku Gothic ProN"),local("Hiragino Kaku Gothic Pro"),local("MS Gothic");unicode-range:U+3002,U+FF0C,U+3001,U+FF1B,U+FF1A,U+FF1F,U+FF01,U+FF0D,U+FF0F,U+FF3C}@font-face{font-family:"Biaodian Pro Serif";src:local("Hiragino Mincho ProN"),local("Hiragino Mincho Pro"),local("MS Mincho");unicode-range:U+3002,U+FF0C,U+3001,U+FF1B,U+FF1A,U+FF1F,U+FF01,U+FF0D,U+FF0F,U+FF3C}@font-face{font-family:"Biaodian Pro Sans CNS";src:local("Heiti TC"),local("Lihei Pro"),local("Microsoft Jhenghei"),local(PMingLiU);unicode-range:U+3002,U+FF0C,U+3001}@font-face{font-family:"Biaodian Pro Sans CNS";src:local("Hiragino Kaku Gothic ProN"),local("Hiragino Kaku Gothic Pro"),local("Heiti TC"),local("Lihei Pro"),local("Microsoft Jhenghei"),local(PMingLiU),local("MS Gothic");unicode-range:U+FF1B,U+FF1A,U+FF1F,U+FF01}@font-face{font-family:"Biaodian Pro Sans CNS";src:local("Hiragino Mincho ProN"),local("Hiragino Mincho Pro"),local("MS Mincho");unicode-range:U+FF0D,U+FF0F,U+FF3C}@font-face{font-family:"Biaodian Pro Serif CNS";src:local(STSongti-TC-Regular),local("Lisong Pro"),local("Heiti TC"),local(PMingLiU);unicode-range:U+3002,U+FF0C,U+3001}@font-face{font-family:"Biaodian Pro Serif CNS";src:local("Hiragino Mincho ProN"),local("Hiragino Mincho Pro"),local(PMingLiU),local("MS Mincho");unicode-range:U+FF1B,U+FF1A,U+FF1F,U+FF01,U+FF0D,U+FF0F,U+FF3C}@font-face{font-family:"Biaodian Pro Sans GB";src:local("Hiragino Sans GB"),local("Heiti SC"),local(STHeiti),local("Hiragino Kaku Gothic ProN"),local("Hiragino Kaku Gothic Pro"),local(SimSun),local("MS Gothic");unicode-range:U+3002,U+FF0C,U+3001,U+FF1B,U+FF1A,U+FF1F,U+FF01,U+FF0D,U+FF0F,U+FF3C}@font-face{font-family:"Biaodian Pro Serif GB";src:local("Songti SC"),local(STSongti),local("Hiragino Mincho ProN"),local("Hiragino Mincho Pro"),local("Hiragino Sans GB"),local("Heiti SC"),local(STHeiti),local(SimSun),local("MS Mincho");unicode-range:U+3002,U+FF0C,U+3001,U+FF1B,U+FF1A,U+FF1F,U+FF01}@font-face{font-family:"Biaodian Pro Serif GB";src:local("Hiragino Mincho ProN"),local("Hiragino Mincho Pro"),local(PMingLiU),local("MS Mincho");unicode-range:U+FF0D,U+FF0F,U+FF3C}@font-face{font-family:"Biaodian Pro Sans";src:local("Hiragino Kaku Gothic ProN"),local("Hiragino Kaku Gothic Pro"),local("Yu Gothic"),local(YuGothic),local(SimSun),local(PMingLiU);unicode-range:U+300C-300F,U+300A-300B,U+3008-3009,U+FF08-FF09,U+3014-3015}@font-face{font-family:"Biaodian Pro Serif";src:local("Hiragino Mincho ProN"),local("Hiragino Mincho Pro"),local("Yu Mincho"),local(YuMincho),local(SimSun),local(PMingLiU);unicode-range:U+300C-300F,U+300A-300B,U+3008-3009,U+FF08-FF09,U+3014-3015}@font-face{font-family:"Biaodian Pro Sans CNS";src:local("Hiragino Kaku Gothic ProN"),local("Hiragino Kaku Gothic Pro"),local("Yu Gothic"),local(YuGothic),local(SimSun),local(PMingLiU);unicode-range:U+300C-300F,U+300A-300B,U+3008-3009,U+FF08-FF09,U+3014-3015}@font-face{font-family:"Biaodian Pro Serif CNS";src:local("Hiragino Mincho ProN"),local("Hiragino Mincho Pro"),local("Yu Mincho"),local(YuMincho),local(SimSun),local(PMingLiU);unicode-range:U+300C-300F,U+300A-300B,U+3008-3009,U+FF08-FF09,U+3014-3015}@font-face{font-family:"Biaodian Pro Sans GB";src:local("Hiragino Kaku Gothic ProN"),local("Hiragino Kaku Gothic Pro"),local("Yu Gothic"),local(YuGothic),local(SimSun),local(PMingLiU);unicode-range:U+300C-300F,U+300A-300B,U+3008-3009,U+FF08-FF09,U+3014-3015}@font-face{font-family:"Biaodian Pro Serif GB";src:local("Hiragino Mincho ProN"),local("Hiragino Mincho Pro"),local("Yu Mincho"),local(YuMincho),local(SimSun),local(PMingLiU);unicode-range:U+300C-300F,U+300A-300B,U+3008-3009,U+FF08-FF09,U+3014-3015}@font-face{font-family:"Biaodian Basic";src:url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype");unicode-range:U+2014,U+2026,U+00B7}@font-face{font-family:"Biaodian Basic";font-weight:700;src:url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype");unicode-range:U+2014,U+2026,U+00B7}@font-face{font-family:"Biaodian Sans";font-weight:700;src:url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype");unicode-range:U+2014,U+2026,U+00B7}@font-face{font-family:"Biaodian Pro Sans";font-weight:700;src:url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype");unicode-range:U+2014,U+2026,U+00B7}@font-face{font-family:"Biaodian Pro Sans";font-weight:700;src:url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype");unicode-range:U+2014,U+2026,U+00B7}@font-face{font-family:"Biaodian Pro Sans CNS";font-weight:700;src:url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype");unicode-range:U+2014,U+2026,U+00B7}@font-face{font-family:"Biaodian Pro Sans GB";font-weight:700;src:url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype");unicode-range:U+2014,U+2026,U+00B7}@font-face{font-family:"Biaodian Pro Serif";font-weight:700;src:url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype");unicode-range:U+2014,U+2026,U+00B7}@font-face{font-family:"Biaodian Pro Serif CNS";font-weight:700;src:url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype");unicode-range:U+2014,U+2026,U+00B7}@font-face{font-family:"Biaodian Pro Serif GB";font-weight:700;src:url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype");unicode-range:U+2014,U+2026,U+00B7}@font-face{font-family:"Latin Italic Serif";src:local("Georgia Italic"),local("Times New Roman Italic"),local(Georgia-Italic),local(TimesNewRomanPS-ItalicMT),local(Times-Italic)}@font-face{font-family:"Latin Italic Serif";font-weight:700;src:local("Georgia Bold Italic"),local("Times New Roman Bold Italic"),local(Georgia-BoldItalic),local(TimesNewRomanPS-BoldItalicMT),local(Times-Italic)}@font-face{font-family:"Latin Italic Sans";src:local("Helvetica Neue Italic"),local("Helvetica Oblique"),local("Arial Italic"),local(HelveticaNeue-Italic),local(Helvetica-LightOblique),local(Arial-ItalicMT)}@font-face{font-family:"Latin Italic Sans";font-weight:700;src:local("Helvetica Neue Bold Italic"),local("Helvetica Bold Oblique"),local("Arial Bold Italic"),local(HelveticaNeue-BoldItalic),local(Helvetica-BoldOblique),local(Arial-BoldItalicMT)}@font-face{unicode-range:U+0030-0039;font-family:"Numeral TF Sans";src:local(Skia),local("Neutraface 2 Text"),local(Candara),local(Corbel)}@font-face{unicode-range:U+0030-0039;font-family:"Numeral TF Serif";src:local(Georgia),local("Hoefler Text"),local("Big Caslon")}@font-face{unicode-range:U+0030-0039;font-family:"Numeral TF Italic Serif";src:local("Georgia Italic"),local("Hoefler Text Italic"),local(Georgia-Italic),local(HoeflerText-Italic)}@font-face{unicode-range:U+0030-0039;font-family:"Numeral LF Sans";src:local("Helvetica Neue"),local(Helvetica),local(Arial)}@font-face{unicode-range:U+0030-0039;font-family:"Numeral LF Italic Sans";src:local("Helvetica Neue Italic"),local("Helvetica Oblique"),local("Arial Italic"),local(HelveticaNeue-Italic),local(Helvetica-LightOblique),local(Arial-ItalicMT)}@font-face{unicode-range:U+0030-0039;font-family:"Numeral LF Italic Sans";font-weight:700;src:local("Helvetica Neue Bold Italic"),local("Helvetica Bold Oblique"),local("Arial Bold Italic"),local(HelveticaNeue-BoldItalic),local(Helvetica-BoldOblique),local(Arial-BoldItalicMT)}@font-face{unicode-range:U+0030-0039;font-family:"Numeral LF Serif";src:local(Palatino),local("Palatino Linotype"),local("Times New Roman")}@font-face{unicode-range:U+0030-0039;font-family:"Numeral LF Italic Serif";src:local("Palatino Italic"),local("Palatino Italic Linotype"),local("Times New Roman Italic"),local(Palatino-Italic),local(Palatino-Italic-Linotype),local(TimesNewRomanPS-ItalicMT)}@font-face{unicode-range:U+0030-0039;font-family:"Numeral LF Italic Serif";font-weight:700;src:local("Palatino Bold Italic"),local("Palatino Bold Italic Linotype"),local("Times New Roman Bold Italic"),local(Palatino-BoldItalic),local(Palatino-BoldItalic-Linotype),local(TimesNewRomanPS-BoldItalicMT)}@font-face{font-family:"Numeral TF Sans";src:local(lying-to-firefox);unicode-range:U+270C}@font-face{font-family:"Numeral TF Serif";src:local(lying-to-firefox);unicode-range:U+270C}@font-face{font-family:"Numeral TF Italic Serif";src:local(lying-to-firefox);unicode-range:U+270C}@font-face{font-family:"Numeral LF Sans";src:local(lying-to-firefox);unicode-range:U+270C}@font-face{font-family:"Numeral LF Italic Sans";src:local(lying-to-firefox);unicode-range:U+270C}@font-face{font-family:"Numeral LF Italic Sans";font-weight:700;src:local(lying-to-firefox);unicode-range:U+270C}@font-face{font-family:"Numeral LF Serif";src:local(lying-to-firefox);unicode-range:U+270C}@font-face{font-family:"Numeral LF Italic Serif";src:local(lying-to-firefox);unicode-range:U+270C}@font-face{font-family:"Numeral LF Italic Serif";font-weight:700;src:local(lying-to-firefox);unicode-range:U+270C}@font-face{src:url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype");unicode-range:U+3105-312D,U+31A0-31BA,U+02D9,U+02CA,U+02C5,U+02C7,U+02CB,U+02EA-02EB,U+030D,U+0358,U+F31B4-F31B7,U+F0061,U+F0065,U+F0069,U+F006F,U+F0075;font-family:"Zhuyin Kaiti"}@font-face{unicode-range:U+3105-312D,U+31A0-31BA,U+02D9,U+02CA,U+02C5,U+02C7,U+02CB,U+02EA-02EB,U+030D,U+0358,U+F31B4-F31B7,U+F0061,U+F0065,U+F0069,U+F006F,U+F0075;font-family:"Zhuyin Heiti";src:local("Hiragino Sans GB"),local("Heiti TC"),local("Microsoft Jhenghei"),url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype")}@font-face{font-family:"Zhuyin Heiti";src:local("Heiti TC"),local("Microsoft Jhenghei"),url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype");unicode-range:U+3127}@font-face{src:url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype");font-family:"Zhuyin Heiti";unicode-range:U+02D9,U+02CA,U+02C5,U+02C7,U+02CB,U+02EA-02EB,U+31B4,U+31B5,U+31B6,U+31B7,U+030D,U+0358,U+F31B4-F31B7,U+F0061,U+F0065,U+F0069,U+F006F,U+F0075}@font-face{src:url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype");font-family:"Romanization Sans";unicode-range:U+030D,U+0358,U+F31B4-F31B7,U+F0061,U+F0065,U+F0069,U+F006F,U+F0075}article strong :lang(ja-Latn),article strong :lang(zh-Latn),article strong :not(:lang(zh)):not(:lang(ja)),article strong:lang(ja-Latn),article strong:lang(zh-Latn),article strong:not(:lang(zh)):not(:lang(ja)),html :lang(ja-Latn),html :lang(zh-Latn),html :not(:lang(zh)):not(:lang(ja)),html:lang(ja-Latn),html:lang(zh-Latn),html:not(:lang(zh)):not(:lang(ja)){font-family:"Helvetica Neue",Helvetica,Arial,"Han Heiti",sans-serif}[lang*=Hant],[lang=zh-TW],[lang=zh-HK],[lang^=zh],article strong:lang(zh),article strong:lang(zh-Hant),html:lang(zh),html:lang(zh-Hant){font-family:"Biaodian Pro Sans CNS","Helvetica Neue",Helvetica,Arial,"Zhuyin Heiti","Han Heiti",sans-serif}.no-unicoderange [lang*=Hant],.no-unicoderange [lang=zh-TW],.no-unicoderange [lang=zh-HK],.no-unicoderange [lang^=zh],.no-unicoderange article strong:lang(zh),.no-unicoderange article strong:lang(zh-Hant),html:lang(zh).no-unicoderange,html:lang(zh-Hant).no-unicoderange{font-family:"Helvetica Neue",Helvetica,Arial,"Han Heiti",sans-serif}[lang*=Hans],[lang=zh-CN],article strong:lang(zh-CN),article strong:lang(zh-Hans),html:lang(zh-CN),html:lang(zh-Hans){font-family:"Biaodian Pro Sans GB","Helvetica Neue",Helvetica,Arial,"Han Heiti GB",sans-serif}.no-unicoderange [lang*=Hans],.no-unicoderange [lang=zh-CN],.no-unicoderange article strong:lang(zh-CN),.no-unicoderange article strong:lang(zh-Hans),html:lang(zh-CN).no-unicoderange,html:lang(zh-Hans).no-unicoderange{font-family:"Helvetica Neue",Helvetica,Arial,"Han Heiti GB",sans-serif}[lang^=ja],article strong:lang(ja),html:lang(ja){font-family:"Yakumono Sans","Helvetica Neue",Helvetica,Arial,sans-serif}.no-unicoderange [lang^=ja],.no-unicoderange article strong:lang(ja),html:lang(ja).no-unicoderange{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}article blockquote i :lang(ja-Latn),article blockquote i :lang(zh-Latn),article blockquote i :not(:lang(zh)):not(:lang(ja)),article blockquote i:lang(ja-Latn),article blockquote i:lang(zh-Latn),article blockquote i:not(:lang(zh)):not(:lang(ja)),article blockquote var :lang(ja-Latn),article blockquote var :lang(zh-Latn),article blockquote var :not(:lang(zh)):not(:lang(ja)),article blockquote var:lang(ja-Latn),article blockquote var:lang(zh-Latn),article blockquote var:not(:lang(zh)):not(:lang(ja)){font-family:"Latin Italic Sans","Helvetica Neue",Helvetica,Arial,"Han Heiti",sans-serif}article blockquote i:lang(zh),article blockquote i:lang(zh-Hant),article blockquote var:lang(zh),article blockquote var:lang(zh-Hant){font-family:"Biaodian Pro Sans CNS","Latin Italic Sans","Helvetica Neue",Helvetica,Arial,"Zhuyin Heiti","Han Heiti",sans-serif}.no-unicoderange article blockquote i:lang(zh),.no-unicoderange article blockquote i:lang(zh-Hant),.no-unicoderange article blockquote var:lang(zh),.no-unicoderange article blockquote var:lang(zh-Hant){font-family:"Latin Italic Sans","Helvetica Neue",Helvetica,Arial,"Han Heiti",sans-serif}article blockquote i:lang(zh-CN),article blockquote i:lang(zh-Hans),article blockquote var:lang(zh-CN),article blockquote var:lang(zh-Hans){font-family:"Biaodian Pro Sans GB","Latin Italic Sans","Helvetica Neue",Helvetica,Arial,"Han Heiti GB",sans-serif}.no-unicoderange article blockquote i:lang(zh-CN),.no-unicoderange article blockquote i:lang(zh-Hans),.no-unicoderange article blockquote var:lang(zh-CN),.no-unicoderange article blockquote var:lang(zh-Hans){font-family:"Latin Italic Sans","Helvetica Neue",Helvetica,Arial,"Han Heiti GB",sans-serif}article blockquote i:lang(ja),article blockquote var:lang(ja){font-family:"Yakumono Sans","Latin Italic Sans","Helvetica Neue",Helvetica,Arial,sans-serif}.no-unicoderange article blockquote i:lang(ja),.no-unicoderange article blockquote var:lang(ja){font-family:"Latin Italic Sans","Helvetica Neue",Helvetica,Arial,sans-serif}article figure blockquote :lang(ja-Latn),article figure blockquote :lang(zh-Latn),article figure blockquote :not(:lang(zh)):not(:lang(ja)),article figure blockquote:lang(ja-Latn),article figure blockquote:lang(zh-Latn),article figure blockquote:not(:lang(zh)):not(:lang(ja)){font-family:Georgia,"Times New Roman","Han Songti",cursive,serif}article figure blockquote:lang(zh),article figure blockquote:lang(zh-Hant){font-family:"Biaodian Pro Serif CNS","Numeral LF Serif",Georgia,"Times New Roman","Zhuyin Kaiti","Han Songti",serif}.no-unicoderange article figure blockquote:lang(zh),.no-unicoderange article figure blockquote:lang(zh-Hant){font-family:"Numeral LF Serif",Georgia,"Times New Roman","Han Songti",serif}article figure blockquote:lang(zh-CN),article figure blockquote:lang(zh-Hans){font-family:"Biaodian Pro Serif GB","Numeral LF Serif",Georgia,"Times New Roman","Han Songti GB",serif}.no-unicoderange article figure blockquote:lang(zh-CN),.no-unicoderange article figure blockquote:lang(zh-Hans){font-family:"Numeral LF Serif",Georgia,"Times New Roman","Han Songti GB",serif}article figure blockquote:lang(ja){font-family:"Yakumono Serif","Numeral LF Serif",Georgia,"Times New Roman",serif}.no-unicoderange article figure blockquote:lang(ja){font-family:"Numeral LF Serif",Georgia,"Times New Roman",serif}article blockquote :lang(ja-Latn),article blockquote :lang(zh-Latn),article blockquote :not(:lang(zh)):not(:lang(ja)),article blockquote:lang(ja-Latn),article blockquote:lang(zh-Latn),article blockquote:not(:lang(zh)):not(:lang(ja)){font-family:Georgia,"Times New Roman","Han Kaiti",cursive,serif}article blockquote:lang(zh),article blockquote:lang(zh-Hant){font-family:"Biaodian Pro Serif CNS","Numeral LF Serif",Georgia,"Times New Roman","Zhuyin Kaiti","Han Kaiti",cursive,serif}.no-unicoderange article blockquote:lang(zh),.no-unicoderange article blockquote:lang(zh-Hant){font-family:"Numeral LF Serif",Georgia,"Times New Roman","Han Kaiti",cursive,serif}article blockquote:lang(zh-CN),article blockquote:lang(zh-Hans){font-family:"Biaodian Pro Serif GB","Numeral LF Serif",Georgia,"Times New Roman","Han Kaiti GB",cursive,serif}.no-unicoderange article blockquote:lang(zh-CN),.no-unicoderange article blockquote:lang(zh-Hans){font-family:"Numeral LF Serif",Georgia,"Times New Roman","Han Kaiti GB",cursive,serif}article blockquote:lang(ja){font-family:"Yakumono Serif","Numeral LF Serif",Georgia,"Times New Roman",cursive,serif}.no-unicoderange article blockquote:lang(ja){font-family:"Numeral LF Serif",Georgia,"Times New Roman",cursive,serif}i :lang(ja-Latn),i :lang(zh-Latn),i :not(:lang(zh)):not(:lang(ja)),i:lang(ja-Latn),i:lang(zh-Latn),i:not(:lang(zh)):not(:lang(ja)),var :lang(ja-Latn),var :lang(zh-Latn),var :not(:lang(zh)):not(:lang(ja)),var:lang(ja-Latn),var:lang(zh-Latn),var:not(:lang(zh)):not(:lang(ja)){font-family:"Latin Italic Serif",Georgia,"Times New Roman","Han Kaiti",cursive,serif}i:lang(zh),i:lang(zh-Hant),var:lang(zh),var:lang(zh-Hant){font-family:"Biaodian Pro Serif CNS","Numeral LF Italic Serif","Latin Italic Serif",Georgia,"Times New Roman","Zhuyin Kaiti","Han Kaiti",cursive,serif}.no-unicoderange i:lang(zh),.no-unicoderange i:lang(zh-Hant),.no-unicoderange var:lang(zh),.no-unicoderange var:lang(zh-Hant){font-family:"Numeral LF Italic Serif","Latin Italic Serif",Georgia,"Times New Roman","Han Kaiti",cursive,serif}i:lang(zh-CN),i:lang(zh-Hans),var:lang(zh-CN),var:lang(zh-Hans){font-family:"Biaodian Pro Serif GB","Numeral LF Italic Serif","Latin Italic Serif",Georgia,"Times New Roman","Han Kaiti GB",cursive,serif}.no-unicoderange i:lang(zh-CN),.no-unicoderange i:lang(zh-Hans),.no-unicoderange var:lang(zh-CN),.no-unicoderange var:lang(zh-Hans){font-family:"Numeral LF Italic Serif","Latin Italic Serif",Georgia,"Times New Roman","Han Kaiti GB",cursive,serif}i:lang(ja),var:lang(ja){font-family:"Yakumono Serif","Numeral LF Italic Serif","Latin Italic Serif",Georgia,"Times New Roman",cursive,serif}.no-unicoderange i:lang(ja),.no-unicoderange var:lang(ja){font-family:"Numeral LF Italic Serif","Latin Italic Serif",Georgia,"Times New Roman",cursive,serif}code :lang(ja-Latn),code :lang(zh-Latn),code :not(:lang(zh)):not(:lang(ja)),code:lang(ja-Latn),code:lang(zh-Latn),code:not(:lang(zh)):not(:lang(ja)),kbd :lang(ja-Latn),kbd :lang(zh-Latn),kbd :not(:lang(zh)):not(:lang(ja)),kbd:lang(ja-Latn),kbd:lang(zh-Latn),kbd:not(:lang(zh)):not(:lang(ja)),pre :lang(ja-Latn),pre :lang(zh-Latn),pre :not(:lang(zh)):not(:lang(ja)),pre:lang(ja-Latn),pre:lang(zh-Latn),pre:not(:lang(zh)):not(:lang(ja)),samp :lang(ja-Latn),samp :lang(zh-Latn),samp :not(:lang(zh)):not(:lang(ja)),samp:lang(ja-Latn),samp:lang(zh-Latn),samp:not(:lang(zh)):not(:lang(ja)){font-family:Menlo,Consolas,Courier,"Han Heiti",monospace,monospace,sans-serif}code:lang(zh),code:lang(zh-Hant),kbd:lang(zh),kbd:lang(zh-Hant),pre:lang(zh),pre:lang(zh-Hant),samp:lang(zh),samp:lang(zh-Hant){font-family:"Biaodian Pro Sans CNS",Menlo,Consolas,Courier,"Zhuyin Heiti","Han Heiti",monospace,monospace,sans-serif}.no-unicoderange code:lang(zh),.no-unicoderange code:lang(zh-Hant),.no-unicoderange kbd:lang(zh),.no-unicoderange kbd:lang(zh-Hant),.no-unicoderange pre:lang(zh),.no-unicoderange pre:lang(zh-Hant),.no-unicoderange samp:lang(zh),.no-unicoderange samp:lang(zh-Hant){font-family:Menlo,Consolas,Courier,"Han Heiti",monospace,monospace,sans-serif}code:lang(zh-CN),code:lang(zh-Hans),kbd:lang(zh-CN),kbd:lang(zh-Hans),pre:lang(zh-CN),pre:lang(zh-Hans),samp:lang(zh-CN),samp:lang(zh-Hans){font-family:"Biaodian Pro Sans GB",Menlo,Consolas,Courier,"Han Heiti GB",monospace,monospace,sans-serif}.no-unicoderange code:lang(zh-CN),.no-unicoderange code:lang(zh-Hans),.no-unicoderange kbd:lang(zh-CN),.no-unicoderange kbd:lang(zh-Hans),.no-unicoderange pre:lang(zh-CN),.no-unicoderange pre:lang(zh-Hans),.no-unicoderange samp:lang(zh-CN),.no-unicoderange samp:lang(zh-Hans){font-family:Menlo,Consolas,Courier,"Han Heiti GB",monospace,monospace,sans-serif}code:lang(ja),kbd:lang(ja),pre:lang(ja),samp:lang(ja){font-family:"Yakumono Sans",Menlo,Consolas,Courier,monospace,monospace,sans-serif}.no-unicoderange code:lang(ja),.no-unicoderange kbd:lang(ja),.no-unicoderange pre:lang(ja),.no-unicoderange samp:lang(ja){font-family:Menlo,Consolas,Courier,monospace,monospace,sans-serif}.no-unicoderange h-char.bd-liga,.no-unicoderange h-char[unicode=b7],h-ruby [annotation] rt,h-ruby h-zhuyin,h-ruby h-zhuyin h-diao,h-ruby.romanization rt,html,ruby [annotation] rt,ruby h-zhuyin,ruby h-zhuyin h-diao,ruby.romanization rt{-moz-font-feature-settings:"liga";-ms-font-feature-settings:"liga";-webkit-font-feature-settings:"liga";font-feature-settings:"liga"}[lang*=Hant],[lang*=Hans],[lang=zh-TW],[lang=zh-HK],[lang=zh-CN],[lang^=zh],article blockquote i,article blockquote var,article strong,code,html,kbd,pre,samp{-moz-font-feature-settings:"liga=1, locl=0";-ms-font-feature-settings:"liga","locl" 0;-webkit-font-feature-settings:"liga","locl" 0;font-feature-settings:"liga","locl" 0}.no-unicoderange h-char.bd-cop:lang(zh-HK),.no-unicoderange h-char.bd-cop:lang(zh-Hant),.no-unicoderange h-char.bd-cop:lang(zh-TW){font-family:-apple-system,"Han Heiti CNS"}.no-unicoderange h-char.bd-liga,.no-unicoderange h-char[unicode=b7]{font-family:"Biaodian Basic","Han Heiti"}.no-unicoderange h-char[unicode="2018"]:lang(zh-CN),.no-unicoderange h-char[unicode="2018"]:lang(zh-Hans),.no-unicoderange h-char[unicode="2019"]:lang(zh-CN),.no-unicoderange h-char[unicode="2019"]:lang(zh-Hans),.no-unicoderange h-char[unicode="201c"]:lang(zh-CN),.no-unicoderange h-char[unicode="201c"]:lang(zh-Hans),.no-unicoderange h-char[unicode="201d"]:lang(zh-CN),.no-unicoderange h-char[unicode="201d"]:lang(zh-Hans){font-family:"Han Heiti GB"}i,var{font-style:inherit}.no-unicoderange h-ruby h-zhuyin,.no-unicoderange h-ruby h-zhuyin h-diao,.no-unicoderange ruby h-zhuyin,.no-unicoderange ruby h-zhuyin h-diao,h-ruby h-diao,ruby h-diao{font-family:"Zhuyin Kaiti",cursive,serif}h-ruby [annotation] rt,h-ruby.romanization rt,ruby [annotation] rt,ruby.romanization rt{font-family:"Romanization Sans","Helvetica Neue",Helvetica,Arial,"Han Heiti",sans-serif}.no-kaiti i,.no-kaiti var{padding-bottom:.05em;border-bottom:3px double #d3d3d3}article h1+blockquote,article h1+h2,article h1+h3,article h1+h4,article h1+h5,article h1+h6,article h1+ol,article h1+p,article h1+section>blockquote:first-child,article h1+section>h2:first-child,article h1+section>h3:first-child,article h1+section>h4:first-child,article h1+section>h5:first-child,article h1+section>h6:first-child,article h1+section>ol:first-child,article h1+section>p:first-child,article h1+section>ul:first-child,article h1+ul,article h2+blockquote,article h2+h2,article h2+h3,article h2+h4,article h2+h5,article h2+h6,article h2+ol,article h2+p,article h2+section>blockquote:first-child,article h2+section>h2:first-child,article h2+section>h3:first-child,article h2+section>h4:first-child,article h2+section>h5:first-child,article h2+section>h6:first-child,article h2+section>ol:first-child,article h2+section>p:first-child,article h2+section>ul:first-child,article h2+ul,article h3+blockquote,article h3+h3,article h3+h4,article h3+h5,article h3+h6,article h3+ol,article h3+p,article h3+section>blockquote:first-child,article h3+section>h3:first-child,article h3+section>h4:first-child,article h3+section>h5:first-child,article h3+section>h6:first-child,article h3+section>ol:first-child,article h3+section>p:first-child,article h3+section>ul:first-child,article h3+ul,article h4+blockquote,article h4+h4,article h4+h5,article h4+h6,article h4+ol,article h4+p,article h4+section>blockquote:first-child,article h4+section>h4:first-child,article h4+section>h5:first-child,article h4+section>h6:first-child,article h4+section>ol:first-child,article h4+section>p:first-child,article h4+section>ul:first-child,article h4+ul,article h5+blockquote,article h5+h5,article h5+h6,article h5+ol,article h5+p,article h5+section>blockquote:first-child,article h5+section>h5:first-child,article h5+section>h6:first-child,article h5+section>ol:first-child,article h5+section>p:first-child,article h5+section>ul:first-child,article h5+ul,article h6+blockquote,article h6+h6,article h6+ol,article h6+p,article h6+section>blockquote:first-child,article h6+section>h6:first-child,article h6+section>ol:first-child,article h6+section>p:first-child,article h6+section>ul:first-child,article h6+ul{margin-top:-1em}article{line-height:1.7;-moz-hyphens:auto;-ms-hyphens:auto;-webkit-hyphens:auto;hyphens:auto}article li,article p{text-align:justify;text-justify:inter-ideograph}.poem-like p,p.poem-like{margin-left:2em}@media only screen and (max-width:480px){.poem-like p,article blockquote,p.poem-like{margin-left:1em}blockquote,figure{margin-left:1em;margin-right:1em}}figure blockquote{margin:0}blockquote blockquote{margin-left:1em;margin-right:1em}h-hws,h-hws[hidden]{display:inline;visibility:hidden;font:.89em Arial}code h-hws,code h-hws[hidden],h-hws.quote-inner,h-hws.quote-outer:lang(zh-CN),h-hws.quote-outer:lang(zh-Hans),h-hws[hidden].quote-inner,h-hws[hidden].quote-outer:lang(zh-CN),h-hws[hidden].quote-outer:lang(zh-Hans),kbd h-hws,kbd h-hws[hidden],pre h-hws,pre h-hws[hidden],samp h-hws,samp h-hws[hidden]{display:none}@font-face{src:url(./font/han-space.woff?v3.3.0) format("woff"),url(./font/han-space.otf?v3.3.0) format("opentype");font-family:"Han Space";unicode-range:U+20}h-char.bd-hangable:lang(zh) h-cs,h-char.bd-hangable:lang(zh) h-cs[hidden],h-char.bd-hangable:lang(zh-HK) h-cs,h-char.bd-hangable:lang(zh-HK) h-cs[hidden],h-char.bd-hangable:lang(zh-Hant) h-cs,h-char.bd-hangable:lang(zh-Hant) h-cs[hidden],h-char.bd-hangable:lang(zh-TW) h-cs,h-char.bd-hangable:lang(zh-TW) h-cs[hidden],h-cs,h-cs[hidden]{display:inline;visibility:inherit;font-family:inherit;font-size:inherit}h-cs.hangable-outer,h-cs.hangable-outer[hidden]{display:inline;font:1em "Han Space"}h-cs.hangable-outer:lang(zh-HK),h-cs.hangable-outer:lang(zh-Hant),h-cs.hangable-outer:lang(zh-TW),h-cs.hangable-outer[hidden]:lang(zh-HK),h-cs.hangable-outer[hidden]:lang(zh-Hant),h-cs.hangable-outer[hidden]:lang(zh-TW){display:none}h-char.bd-hangable:lang(ja),h-char.bd-hangable:lang(zh-CN),h-char.bd-hangable:lang(zh-Hans){position:relative}h-char.bd-hangable:lang(ja):after,h-char.bd-hangable:lang(zh-CN):after,h-char.bd-hangable:lang(zh-Hans):after{display:none!important}h-char.bd-hangable:lang(ja):before,h-char.bd-hangable:lang(zh-CN):before,h-char.bd-hangable:lang(zh-Hans):before{display:inline!important;content:" ";font:1em "Han Space",Menlo,Consolas,Courier}h-char.bd-hangable:lang(ja)>h-inner,h-char.bd-hangable:lang(zh-CN)>h-inner,h-char.bd-hangable:lang(zh-Hans)>h-inner{-moz-text-emphasis:none;-webkit-text-emphasis:none;text-emphasis:none;font-style:normal;font-weight:400;text-decoration:none;text-indent:0;position:absolute;left:0;top:0;display:inline-block;line-height:1.1}h-ru h-char.bd-hangable:lang(ja)>h-inner,h-ru h-char.bd-hangable:lang(zh-CN)>h-inner,h-ru h-char.bd-hangable:lang(zh-Hans)>h-inner,ruby h-char.bd-hangable:lang(ja)>h-inner,ruby h-char.bd-hangable:lang(zh-CN)>h-inner,ruby h-char.bd-hangable:lang(zh-Hans)>h-inner{position:relative}h-char.bd-jiya.bd-end:after,h-char.bd-jiya.bd-open:before,h-cs,h-cs[hidden]{display:none;visibility:hidden;content:" ";font:.825em Courier;letter-spacing:0;white-space:normal}h-char.bd-jiya.bd-close:after,h-char.bd-jiya.bd-cop:after,h-char.bd-jiya.bd-open:before,h-char.bd-jiya[unicode=ff0e]:after,h-cs.jinze-outer,h-cs.jinze-outer[hidden]{display:inline}h-char.bd-jiya.bd-open>h-inner{margin-left:-.5em}h-char.bd-jiya.bd-close>h-inner,h-char.bd-jiya.bd-cop>h-inner,h-char.bd-jiya[unicode=ff0e]>h-inner{letter-spacing:-.5em}h-char.bd-consecutive.bd-end:not(.end-portion):after,h-char.bd-consecutive.bd-open[prev=bd-open]:before,h-char.bd-jiya.bd-cop:lang(zh-HK):after,h-char.bd-jiya.bd-cop:lang(zh-Hant):after,h-char.bd-jiya.bd-cop:lang(zh-TW):after,h-cs.jiya-outer.bd-end:not(.end-portion){display:none}h-char.bd-jiya.bd-cop:lang(zh-HK)>h-inner,h-char.bd-jiya.bd-cop:lang(zh-Hant)>h-inner,h-char.bd-jiya.bd-cop:lang(zh-TW)>h-inner{letter-spacing:inherit}h-cs.jiya-outer.bd-end[next=bd-open]{display:inline}h-char.bd-consecutive.bd-open[prev*=bd-cop]:lang(zh-HK):before,h-char.bd-consecutive.bd-open[prev*=bd-cop]:lang(zh-Hant):before,h-char.bd-consecutive.bd-open[prev*=bd-cop]:lang(zh-TW):before,h-cs.jiya-outer.bd-end:lang(zh-HK),h-cs.jiya-outer.bd-end:lang(zh-Hant),h-cs.jiya-outer.bd-end:lang(zh-TW),h-cs.jiya-outer[prev*=bd-cop]:lang(zh-HK),h-cs.jiya-outer[prev*=bd-cop]:lang(zh-Hant),h-cs.jiya-outer[prev*=bd-cop]:lang(zh-TW){display:none}h-char.bd-consecutive[unicode=b7]:not(.end-portion),h-char.bd-consecutive[unicode="30fb"]:not(.end-portion){letter-spacing:-.5em}h-char.bd-consecutive.bd-liga:not(.end-portion){margin-right:-.25em}h-char[display-as]{position:relative;display:inline-block}h-char[display-as] h-inner{color:transparent}h-char[display-as]:after{position:absolute;left:0;display:inline-block;content:attr(display-as)}h-char[display-as].comb-liga:after{font-family:"Romanization Sans","Zhuyin Kaiti"} \ No newline at end of file diff --git a/lib/Han/dist/han.min.js b/lib/Han/dist/han.min.js new file mode 100644 index 0000000..a557ad3 --- /dev/null +++ b/lib/Han/dist/han.min.js @@ -0,0 +1,5 @@ +/*! 漢字標準格式 v3.3.0 | MIT License | css.hanzi.co */ +/*! Han.css: the CSS typography framework optimised for Hanzi */ + +void function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=b(a,!0):"function"==typeof define&&define.amd?define(function(){return b(a,!0)}):b(a)}("undefined"!=typeof window?window:this,function(a,b){"use strict";function c(a){return"function"==typeof a||a instanceof Element?a:void 0}function d(a){var b=0===a.index&&a.isEnd?"biaodian cjk":"biaodian cjk portion "+(0===a.index?"is-first":a.isEnd?"is-end":"is-inner"),c=S.create("h-char-group",b);return c.innerHTML=a.text,c}function e(a){var b=S.create("div"),c=a.charCodeAt(0).toString(16);return b.innerHTML=''+a+"",b.firstChild}function f(a){return a.match(R["char"].biaodian.open)?"bd-open":a.match(R["char"].biaodian.close)?"bd-close bd-end":a.match(R["char"].biaodian.end)?/(?:\u3001|\u3002|\uff0c)/i.test(a)?"bd-end bd-cop":"bd-end":a.match(new RegExp(Q.biaodian.liga))?"bd-liga":a.match(new RegExp(Q.biaodian.middle))?"bd-middle":""}function g(a,b){var c,d=S.create("canvas");return d.width="50",d.height="20",d.style.display="none",L.appendChild(d),c=d.getContext("2d"),c.textBaseline="top",c.font="15px "+b+", sans-serif",c.fillStyle="black",c.strokeStyle="black",c.fillText(a,0,0),{node:d,context:c,remove:function(){S.remove(d,L)}}}function h(a,b){var c,d=a.context,e=b.context;try{for(var f=1;20>=f;f++)for(var g=1;50>=g;g++){if("undefined"==typeof c&&d.getImageData(g,f,1,1).data[3]!==e.getImageData(g,f,1,1).data[3]){c=!1;break}if("boolean"==typeof c)break;50===g&&20===f&&"undefined"==typeof c&&(c=!0)}return a.remove(),b.remove(),a=null,b=null,c}catch(h){}return!1}function i(a,b,c){var a=a,b=b||"sans-serif",c=c||"\u8fadQ";return b=g(c,b),a=g(c,a),!h(a,b)}function j(a){var b,c=S.create("!"),d=a.classList;return c.appendChild(S.clone(a)),S.tag("rt",c.firstChild).forEach(function(a){var c,e=S.create("!"),f=[];do{if(c=(c||a).previousSibling,!c||c.nodeName.match(/((?:h\-)?r[ubt])/i))break;e.insertBefore(S.clone(c),e.firstChild),f.push(c)}while(!c.nodeName.match(/((?:h\-)?r[ubt])/i));b=d.contains("zhuyin")?p(e,a):o(e,a);try{a.parentNode.replaceChild(b,a),f.map(S.remove)}catch(g){}}),m(c)}function k(a){var b=S.create("!");return b.appendChild(S.clone(a)),S.tag("rt",b.firstChild).forEach(function(a){var b,c,d=S.create("!"),e=[];do{if(b=(b||a).previousSibling,!b||b.nodeName.match(/((?:h\-)?r[ubt])/i))break;d.insertBefore(S.clone(b),d.firstChild),e.push(b)}while(!b.nodeName.match(/((?:h\-)?r[ubt])/i));c=S.create("rt"),c.innerHTML=q(a),a.parentNode.replaceChild(c,a)}),b.firstChild}function l(a){var b,c,d,e,f=S.create("!"),g=a.classList;return f.appendChild(S.clone(a)),b=f.firstChild,c=d=S.tag("rb",b),e=c.length,void function(a){a&&(d=S.tag("rt",a).map(function(a,b){if(c[b]){var d=p(c[b],a);try{c[b].parentNode.replaceChild(d,c[b])}catch(e){}return d}}),S.remove(a),b.setAttribute("rightangle","true"))}(b.querySelector("rtc.zhuyin")),S.qsa("rtc:not(.zhuyin)",b).forEach(function(a,c){var f;f=S.tag("rt",a).map(function(a,b){var f,h,i=Number(a.getAttribute("rbspan")||1),j=0,k=[];i>e&&(i=e);do{try{f=d.shift(),k.push(f)}catch(l){}if("undefined"==typeof f)break;j+=Number(f.getAttribute("span")||1)}while(i>j);if(j>i){if(k.length>1)return void console.error("An impossible `rbspan` value detected.",ruby);k=S.tag("rb",k[0]),d=k.slice(i).concat(d),k=k.slice(0,i),j=i}h=o(k,a,{"class":g,span:j,order:c});try{k[0].parentNode.replaceChild(h,k.shift()),k.map(S.remove)}catch(l){}return h}),d=f,1===c&&b.setAttribute("doubleline","true"),S.remove(a)}),m(f)}function m(a){var b=a.firstChild,c=S.create("h-ruby");return c.innerHTML=b.innerHTML,S.setAttr(c,b.attributes),c.normalize(),c}function n(a){if(!a instanceof Element)return a;var b=a.classList;return b.contains("pinyin")?b.add("romanization"):b.contains("romanization")?b.add("annotation"):b.contains("mps")?b.add("zhuyin"):b.contains("rightangle")&&b.add("complex"),a}function o(a,b,c){var d=S.create("h-ru"),b=S.clone(b),c=c||{};return c.annotation="true",Array.isArray(a)?d.innerHTML=a.map(function(a){return"undefined"==typeof a?"":a.outerHTML}).join("")+b.outerHTML:(d.appendChild(S.clone(a)),d.appendChild(b)),S.setAttr(d,c),d}function p(a,b){var a=S.clone(a),c=S.create("h-ru");return c.setAttribute("zhuyin",!0),c.appendChild(a),c.innerHTML+=q(b),c}function q(a){var b,c,d,e="string"==typeof a?a:a.textContent;return b=e.replace(R.zhuyin.diao,""),d=b?b.length:0,c=e.replace(b,"").replace(/[\u02C5]/g,"\u02c7").replace(/[\u030D]/g,"\u0358"),0===d?"":''+b+""+c+""}function r(a,b){return a&&b&&a.parentNode===b.parentNode}function s(a,b){var c=a,b=b||"";if(S.isElmt(a.nextSibling)||r(a,a.nextSibling))return b+X;for(;!c.nextSibling;)c=c.parentNode;return a!==c&&c.insertAdjacentHTML("afterEnd",""),b}function t(a,b){return a.isEnd&&0===a.index?b[1]+X+b[2]:0===a.index?s(a.node,a.text):a.text}function u(a){return 0===a.index?S.clone(Y):""}function v(a){var b=a.node.parentNode;return 0===a.index&&(Z=a.endIndexInNode-2),"h-hws"!==b.nodeName.toLowerCase()||1!==a.index&&a.indexInMatch!==Z||b.classList.add("quote-inner"),a.text}function w(a){var b=a.node.parentNode;return"h-hws"===b.nodeName.toLowerCase()&&b.classList.add("quote-outer"),a.text}function x(){var a,b=S.create("div");return b.innerHTML="a ba b",L.appendChild(b),a=b.firstChild.offsetWidth!==b.lastChild.offsetWidth,S.remove(b),a}function y(a){var b=a.nextSibling;b&&ba(b,"h-cs.jinze-outer")?b.classList.add("hangable-outer"):a.insertAdjacentHTML("afterend",aa)}function z(a){return a.replace(/(biaodian|cjk|bd-jiya|bd-consecutive|bd-hangable)/gi,"").trim()}function A(a){var b,c=a.text,d=a.node.parentNode,e=S.parent(d,"h-char.biaodian"),f=O.createBDChar(c);return f.innerHTML=""+c+"",f.classList.add(ea),(b=S.parent(d,"h-jinze"))&&C(b),e?function(){return e.classList.add(ea),ba(d,"h-inner, h-inner *")?c:f.firstChild}():f}function B(a){var b,c=ca,d=a.node.parentNode,e=S.parent(d,"h-char.biaodian"),f=S.parent(e,"h-jinze");return b=e.classList,c&&e.setAttribute("prev",c),da&&b.contains("bd-open")&&da.pop().setAttribute("next","bd-open"),da=void 0,a.isEnd?(ca=void 0,b.add(ga,"end-portion")):(ca=z(e.getAttribute("class")),b.add(ga)),f&&(da=D(f,{prev:c,"class":z(e.getAttribute("class"))})),a.text}function C(a){ba(a,".tou, .touwei")&&!ba(a.previousSibling,"h-cs.jiya-outer")&&a.insertAdjacentHTML("beforebegin",ha),ba(a,".wei, .touwei")&&!ba(a.nextSibling,"h-cs.jiya-outer")&&a.insertAdjacentHTML("afterend",ha)}function D(a,b){var c,d;return ba(a,".tou, .touwei")&&(c=a.previousSibling,ba(c,"h-cs")&&(c.className="jinze-outer jiya-outer",c.setAttribute("prev",b.prev))),ba(a,".wei, .touwei")&&(d=a.nextSibling,ba(d,"h-cs")&&(d.className="jinze-outer jiya-outer "+b["class"],d.removeAttribute("prev"))),[c,d]}function E(a,b,c){return function(){var d=O.localize.writeOnCanvas(b,a),e=O.localize.writeOnCanvas(c,a);return O.localize.compareCanvases(d,e)}}function F(){return E('"Romanization Sans"',"a\u030d","\udb80\udc61")}function G(){return E('"Romanization Sans"',"i\u030d","\udb80\udc69")}function H(){return E('"Zhuyin Kaiti"',"\u31b4\u0358","\udb8c\uddb4")}function I(a){return function(b){var b=b||J,c=O.find(b).avoid(ia);return a.forEach(function(a){c.replace(new RegExp(a[0],"ig"),function(b,c){var d=S.clone(ja);return d.innerHTML=""+c[0]+"",d.setAttribute("display-as",a[1]),0===b.index?d:""})}),c}}var J=a.document,K=J.documentElement,L=J.body,M="3.3.0",N=["initCond","renderElem","renderJiya","renderHanging","correctBiaodian","renderHWS","substCombLigaWithPUA"],O=function(a,b){return new O.fn.init(a,b)},P=function(){return arguments[0]&&(this.context=arguments[0]),arguments[1]&&(this.condition=arguments[1]),this};O.version=M,O.fn=O.prototype={version:M,constructor:O,context:L,condition:K,routine:N,init:P,setRoutine:function(a){return Array.isArray(a)&&(this.routine=a),this},render:function(a){var b=this,a=Array.isArray(a)?a:this.routine;return a.forEach(function(a){"string"==typeof a&&"function"==typeof b[a]?b[a]():Array.isArray(a)&&"function"==typeof b[a[0]]&&b[a.shift()].apply(b,a)}),this}},O.fn.init.prototype=O.fn,O.init=function(){return O.init=O().render()};var Q={punct:{base:"[\u2026,.;:!?\u203d_]",sing:"[\u2010-\u2014\u2026]",middle:"[\\/~\\-&\u2010-\u2014_]",open:"['\"\u2018\u201c\\(\\[\xa1\xbf\u2e18\xab\u2039\u201a\u201c\u201e]",close:"['\"\u201d\u2019\\)\\]\xbb\u203a\u201b\u201d\u201f]",end:"['\"\u201d\u2019\\)\\]\xbb\u203a\u201b\u201d\u201f\u203c\u203d\u2047-\u2049,.;:!?]"},biaodian:{base:"[\ufe30\uff0e\u3001\uff0c\u3002\uff1a\uff1b\uff1f\uff01\u30fc]",liga:"[\u2014\u2026\u22ef]",middle:"[\xb7\uff3c\uff0f\uff0d\u30a0\uff06\u30fb\uff3f]",open:"[\u300c\u300e\u300a\u3008\uff08\u3014\uff3b\uff5b\u3010\u3016]",close:"[\u300d\u300f\u300b\u3009\uff09\u3015\uff3d\uff5d\u3011\u3017]",end:"[\u300d\u300f\u300b\u3009\uff09\u3015\uff3d\uff5d\u3011\u3017\ufe30\uff0e\u3001\uff0c\u3002\uff1a\uff1b\uff1f\uff01\u30fc]"},hanzi:{base:"[\u4e00-\u9fff\u3400-\u4db5\u31c0-\u31e3\u3007\ufa0e\ufa0f\ufa11\ufa13\ufa14\ufa1f\ufa21\ufa23\ufa24\ufa27-\ufa29]|[\ud800-\udbff][\udc00-\udfff]",desc:"[\u2ff0-\u2ffa]",radical:"[\u2f00-\u2fd5\u2e80-\u2ef3]"},latin:{base:"[A-Za-z0-9\xc0-\xff\u0100-\u017f\u0180-\u024f\u2c60-\u2c7f\ua720-\ua7ff\u1e00-\u1eff]",combine:"[\u0300-\u0341\u1dc0-\u1dff]"},ellinika:{base:"[0-9\u0370-\u03ff\u1f00-\u1fff]",combine:"[\u0300-\u0345\u1dc0-\u1dff]"},kirillica:{base:"[0-9\u0400-\u0482\u048a-\u04ff\u0500-\u052f\ua640-\ua66e\ua67e-\ua697]",combine:"[\u0483-\u0489\u2de0-\u2dff\ua66f-\ua67d\ua69f]"},kana:{base:"[\u30a2\u30a4\u30a6\u30a8\u30aa-\u30fa\u3042\u3044\u3046\u3048\u304a-\u3094\u309f\u30ff]|\ud82c[\udc00-\udc01]",small:"[\u3041\u3043\u3045\u3047\u3049\u30a1\u30a3\u30a5\u30a7\u30a9\u3063\u3083\u3085\u3087\u308e\u3095\u3096\u30c3\u30e3\u30e5\u30e7\u30ee\u30f5\u30f6\u31f0-\u31ff]",combine:"[\u3099-\u309c]",half:"[\uff66-\uff9f]",mark:"[\u30a0\u309d\u309e\u30fb-\u30fe]"},eonmun:{base:"[\uac00-\ud7a3]",letter:"[\u1100-\u11ff\u314f-\u3163\u3131-\u318e\ua960-\ua97c\ud7b0-\ud7fb]",half:"[\uffa1-\uffdc]"},zhuyin:{base:"[\u3105-\u312d\u31a0-\u31ba]",initial:"[\u3105-\u3119\u312a-\u312c\u31a0-\u31a3]",medial:"[\u3127-\u3129]","final":"[\u311a-\u3129\u312d\u31a4-\u31b3\u31b8-\u31ba]",tone:"[\u02d9\u02ca\u02c5\u02c7\u02cb\u02ea\u02eb]",checked:"[\u31b4-\u31b7][\u0358\u030d]?"}},R=function(){var a="[\\x20\\t\\r\\n\\f]",b=Q.punct.open,c=(Q.punct.close,Q.punct.end),d=Q.punct.middle,e=Q.punct.sing,f=b+"|"+c+"|"+d,g=Q.biaodian.open,h=Q.biaodian.close,i=Q.biaodian.end,j=Q.biaodian.middle,k=Q.biaodian.liga+"{2}",l=g+"|"+i+"|"+j,m=Q.kana.base+Q.kana.combine+"?",n=Q.kana.small+Q.kana.combine+"?",o=Q.kana.half,p=Q.eonmun.base+"|"+Q.eonmun.letter,q=Q.eonmun.half,r=Q.hanzi.base+"|"+Q.hanzi.desc+"|"+Q.hanzi.radical+"|"+m,s=Q.ellinika.combine,t=Q.latin.base+s+"*",u=Q.ellinika.base+s+"*",v=Q.kirillica.combine,w=Q.kirillica.base+v+"*",x=t+"|"+u+"|"+w,y="['\u2019]",z=r+"|(?:"+x+"|"+y+")+",A=Q.zhuyin.initial,B=Q.zhuyin.medial,C=Q.zhuyin["final"],D=Q.zhuyin.tone+"|"+Q.zhuyin.checked;return{"char":{punct:{all:new RegExp("("+f+")","g"),open:new RegExp("("+b+")","g"),end:new RegExp("("+c+")","g"),sing:new RegExp("("+e+")","g")},biaodian:{all:new RegExp("("+l+")","g"),open:new RegExp("("+g+")","g"),close:new RegExp("("+h+")","g"),end:new RegExp("("+i+")","g"),liga:new RegExp("("+k+")","g")},hanzi:new RegExp("("+r+")","g"),latin:new RegExp("("+t+")","ig"),ellinika:new RegExp("("+u+")","ig"),kirillica:new RegExp("("+w+")","ig"),kana:new RegExp("("+m+"|"+n+"|"+o+")","g"),eonmun:new RegExp("("+p+"|"+q+")","g")},group:{biaodian:[new RegExp("(("+l+"){2,})","g"),new RegExp("("+k+g+")","g")],punct:null,hanzi:new RegExp("("+r+")+","g"),western:new RegExp("("+t+"|"+u+"|"+w+"|"+f+")+","ig"),kana:new RegExp("("+m+"|"+n+"|"+o+")+","g"),eonmun:new RegExp("("+p+"|"+q+"|"+f+")+","g")},jinze:{hanging:new RegExp(a+"*([\u3001\uff0c\u3002\uff0e])(?!"+i+")","ig"),touwei:new RegExp("("+g+"+)("+z+")("+i+"+)","ig"),tou:new RegExp("("+g+"+)("+z+")","ig"),wei:new RegExp("("+z+")("+i+"+)","ig"),middle:new RegExp("("+z+")("+j+")("+z+")","ig")},zhuyin:{form:new RegExp("^\u02d9?("+A+")?("+B+")?("+C+")?("+D+")?$"),diao:new RegExp("("+D+")","g")},hws:{base:[new RegExp("("+r+")("+x+"|"+b+")","ig"),new RegExp("("+x+"|"+c+")("+r+")","ig")],strict:[new RegExp("("+r+")"+a+"?("+x+"|"+b+")","ig"),new RegExp("("+x+"|"+c+")"+a+"?("+r+")","ig")]},"display-as":{"ja-font-for-hant":["\u67e5 \u67fb","\u555f \u5553","\u9109 \u9115","\u503c \u5024","\u6c61 \u6c5a"],"comb-liga-pua":[["a[\u030d\u0358]","\udb80\udc61"],["e[\u030d\u0358]","\udb80\udc65"],["i[\u030d\u0358]","\udb80\udc69"],["o[\u030d\u0358]","\udb80\udc6f"],["u[\u030d\u0358]","\udb80\udc75"],["\u31b4[\u030d\u0358]","\udb8c\uddb4"],["\u31b5[\u030d\u0358]","\udb8c\uddb5"],["\u31b6[\u030d\u0358]","\udb8c\uddb6"],["\u31b7[\u030d\u0358]","\udb8c\uddb7"]],"comb-liga-vowel":[["a[\u030d\u0358]","\udb80\udc61"],["e[\u030d\u0358]","\udb80\udc65"],["i[\u030d\u0358]","\udb80\udc69"],["o[\u030d\u0358]","\udb80\udc6f"],["u[\u030d\u0358]","\udb80\udc75"]],"comb-liga-zhuyin":[["\u31b4[\u030d\u0358]","\udb8c\uddb4"],["\u31b5[\u030d\u0358]","\udb8c\uddb5"],["\u31b6[\u030d\u0358]","\udb8c\uddb6"],["\u31b7[\u030d\u0358]","\udb8c\uddb7"]]},"inaccurate-char":[["[\u2022\u2027]","\xb7"],["\u22ef\u22ef","\u2026\u2026"],["\u2500\u2500","\u2014\u2014"],["\u2035","\u2018"],["\u2032","\u2019"],["\u2036","\u201c"],["\u2033","\u201d"]]}}();O.UNICODE=Q,O.TYPESET=R,O.UNICODE.cjk=O.UNICODE.hanzi,O.UNICODE.greek=O.UNICODE.ellinika,O.UNICODE.cyrillic=O.UNICODE.kirillica,O.UNICODE.hangul=O.UNICODE.eonmun,O.UNICODE.zhuyin.ruyun=O.UNICODE.zhuyin.checked,O.TYPESET["char"].cjk=O.TYPESET["char"].hanzi,O.TYPESET["char"].greek=O.TYPESET["char"].ellinika,O.TYPESET["char"].cyrillic=O.TYPESET["char"].kirillica,O.TYPESET["char"].hangul=O.TYPESET["char"].eonmun,O.TYPESET.group.hangul=O.TYPESET.group.eonmun,O.TYPESET.group.cjk=O.TYPESET.group.hanzi;var S={id:function(a,b){return(b||J).getElementById(a)},tag:function(a,b){return this.makeArray((b||J).getElementsByTagName(a))},qs:function(a,b){return(b||J).querySelector(a)},qsa:function(a,b){return this.makeArray((b||J).querySelectorAll(a))},parent:function(a,b){return b?function(){if("function"==typeof S.matches){for(;!S.matches(a,b);){if(!a||a===J.documentElement){a=void 0;break}a=a.parentNode}return a}}():a?a.parentNode:void 0},create:function(a,b){var c="!"===a?J.createDocumentFragment():""===a?J.createTextNode(b||""):J.createElement(a);try{b&&(c.className=b)}catch(d){}return c},clone:function(a,b){return a.cloneNode("boolean"==typeof b?b:!0)},remove:function(a){return a.parentNode.removeChild(a)},setAttr:function(a,b){if("object"==typeof b){var c=b.length;if("object"==typeof b[0]&&"name"in b[0])for(var d=0;c>d;d++)void 0!==b[d].value&&a.setAttribute(b[d].name,b[d].value);else for(var e in b)b.hasOwnProperty(e)&&void 0!==b[e]&&a.setAttribute(e,b[e]);return a}},isElmt:function(a){return a&&a.nodeType===Node.ELEMENT_NODE},isIgnorable:function(a){return a?"WBR"===a.nodeName||a.nodeType===Node.COMMENT_NODE:!1},makeArray:function(a){return Array.prototype.slice.call(a)},extend:function(a,b){if(("object"==typeof a||"function"==typeof a)&&"object"==typeof b)for(var c in b)b.hasOwnProperty(c)&&(a[c]=b[c]);return a}},T=function(b){function c(a,b,c){var d=Element.prototype,e=d.matches||d.mozMatchesSelector||d.msMatchesSelector||d.webkitMatchesSelector;return a instanceof Element?e.call(a,b):c&&/^[39]$/.test(a.nodeType)?!0:!1}var d="0.2.1",e=b.NON_INLINE_PROSE,f=b.PRESETS.prose.filterElements,g=a||{},h=g.document||void 0;if("undefined"==typeof h)throw new Error("Fibre requires a DOM-supported environment.");var i=function(a,b){return new i.fn.init(a,b)};return i.version=d,i.matches=c,i.fn=i.prototype={constructor:i,version:d,finder:[],context:void 0,portionMode:"retain",selector:{},preset:"prose",init:function(a,b){if(b&&(this.preset=null),this.selector={context:null,filter:[],avoid:[],boundary:[]},!a)throw new Error("A context is required for Fibre to initialise.");return a instanceof Node?a instanceof Document?this.context=a.body||a:this.context=a:"string"==typeof a&&(this.context=h.querySelector(a),this.selector.context=a),this},filterFn:function(a){var b=this.selector.filter.join(", ")||"*",d=this.selector.avoid.join(", ")||null,e=c(a,b,!0)&&!c(a,d);return"prose"===this.preset?f(a)&&e:e},boundaryFn:function(a){var b=this.selector.boundary.join(", ")||null,d=c(a,b);return"prose"===this.preset?e(a)||d:d},filter:function(a){return"string"==typeof a&&this.selector.filter.push(a),this},endFilter:function(a){return a?this.selector.filter=[]:this.selector.filter.pop(),this},avoid:function(a){return"string"==typeof a&&this.selector.avoid.push(a),this},endAvoid:function(a){return a?this.selector.avoid=[]:this.selector.avoid.pop(),this},addBoundary:function(a){return"string"==typeof a&&this.selector.boundary.push(a),this},removeBoundary:function(){return this.selector.boundary=[],this},setMode:function(a){return this.portionMode="first"===a?"first":"retain",this},replace:function(a,c){var d=this;return d.finder.push(b(d.context,{find:a,replace:c,filterElements:function(a){return d.filterFn(a)},forceContext:function(a){return d.boundaryFn(a)},portionMode:d.portionMode})),d},wrap:function(a,c){var d=this;return d.finder.push(b(d.context,{find:a,wrap:c,filterElements:function(a){return d.filterFn(a)},forceContext:function(a){return d.boundaryFn(a)},portionMode:d.portionMode})),d},revert:function(a){var b=this.finder.length,a=Number(a)||(0===a?Number(0):"all"===a?b:1);if("undefined"==typeof b||0===b)return this;a>b&&(a=b);for(var c=a;c>0;c--)this.finder.pop().revert();return this}},i.fn.filterOut=i.fn.avoid,i.fn.init.prototype=i.fn,i}(function(){function a(a){return String(a).replace(/([.*+?^=!:${}()|[\]\/\\])/g,"\\$1")}function b(){return c.apply(null,arguments)||d.apply(null,arguments)}function c(a,c,e,f,g){if(c&&!c.nodeType&&arguments.length<=2)return!1;var h="function"==typeof e;h&&(e=function(a){return function(b,c){return a(b.text,c.startIndex)}}(e));var i=d(c,{find:a,wrap:h?null:e,replace:h?e:"$"+(f||"&"),prepMatch:function(a,b){if(!a[0])throw"findAndReplaceDOMText cannot handle zero-length matches";if(f>0){var c=a[f];a.index+=a[0].indexOf(c),a[0]=c}return a.endIndex=a.index+a[0].length,a.startIndex=a.index,a.index=b,a},filterElements:g});return b.revert=function(){return i.revert()},!0}function d(a,b){return new e(a,b)}function e(a,c){var d=c.preset&&b.PRESETS[c.preset];if(c.portionMode=c.portionMode||f,d)for(var e in d)i.call(d,e)&&!i.call(c,e)&&(c[e]=d[e]);this.node=a,this.options=c,this.prepMatch=c.prepMatch||this.prepMatch,this.reverts=[],this.matches=this.search(),this.matches.length&&this.processMatches()}var f="retain",g="first",h=J,i=({}.toString,{}.hasOwnProperty);return b.NON_PROSE_ELEMENTS={br:1,hr:1,script:1,style:1,img:1,video:1,audio:1,canvas:1,svg:1,map:1,object:1,input:1,textarea:1,select:1,option:1,optgroup:1,button:1},b.NON_CONTIGUOUS_PROSE_ELEMENTS={address:1,article:1,aside:1,blockquote:1,dd:1,div:1,dl:1,fieldset:1,figcaption:1,figure:1,footer:1,form:1,h1:1,h2:1,h3:1,h4:1,h5:1,h6:1,header:1,hgroup:1,hr:1,main:1,nav:1,noscript:1,ol:1,output:1,p:1,pre:1,section:1,ul:1,br:1,li:1,summary:1,dt:1,details:1,rp:1,rt:1,rtc:1,script:1,style:1,img:1,video:1,audio:1,canvas:1,svg:1,map:1,object:1,input:1,textarea:1,select:1,option:1,optgroup:1,button:1,table:1,tbody:1,thead:1,th:1,tr:1,td:1,caption:1,col:1,tfoot:1,colgroup:1},b.NON_INLINE_PROSE=function(a){return i.call(b.NON_CONTIGUOUS_PROSE_ELEMENTS,a.nodeName.toLowerCase())},b.PRESETS={prose:{forceContext:b.NON_INLINE_PROSE,filterElements:function(a){return!i.call(b.NON_PROSE_ELEMENTS,a.nodeName.toLowerCase())}}},b.Finder=e,e.prototype={search:function(){function b(a){for(var g=0,j=a.length;j>g;++g){var k=a[g];if("string"==typeof k){if(f.global)for(;c=f.exec(k);)h.push(i.prepMatch(c,d++,e));else(c=k.match(f))&&h.push(i.prepMatch(c,0,e));e+=k.length}else b(k)}}var c,d=0,e=0,f=this.options.find,g=this.getAggregateText(),h=[],i=this;return f="string"==typeof f?RegExp(a(f),"g"):f,b(g),h},prepMatch:function(a,b,c){if(!a[0])throw new Error("findAndReplaceDOMText cannot handle zero-length matches");return a.endIndex=c+a.index+a[0].length,a.startIndex=c+a.index,a.index=b,a},getAggregateText:function(){function a(d,e){if(3===d.nodeType)return[d.data];if(b&&!b(d))return[];var e=[""],f=0;if(d=d.firstChild)do if(3!==d.nodeType){var g=a(d);c&&1===d.nodeType&&(c===!0||c(d))?(e[++f]=g,e[++f]=""):("string"==typeof g[0]&&(e[f]+=g.shift()),g.length&&(e[++f]=g,e[++f]=""))}else e[f]+=d.data;while(d=d.nextSibling);return e}var b=this.options.filterElements,c=this.options.forceContext;return a(this.node)},processMatches:function(){var a,b,c,d=this.matches,e=this.node,f=this.options.filterElements,g=[],h=e,i=d.shift(),j=0,k=0,l=0,m=[e];a:for(;;){if(3===h.nodeType&&(!b&&h.length+j>=i.endIndex?b={node:h,index:l++,text:h.data.substring(i.startIndex-j,i.endIndex-j),indexInMatch:j-i.startIndex,indexInNode:i.startIndex-j,endIndexInNode:i.endIndex-j,isEnd:!0}:a&&g.push({node:h,index:l++,text:h.data,indexInMatch:j-i.startIndex,indexInNode:0}),!a&&h.length+j>i.startIndex&&(a={node:h,index:l++,indexInMatch:0,indexInNode:i.startIndex-j,endIndexInNode:i.endIndex-j,text:h.data.substring(i.startIndex-j,i.endIndex-j)}),j+=h.data.length),c=1===h.nodeType&&f&&!f(h),a&&b){if(h=this.replaceMatch(i,a,g,b),j-=b.node.data.length-b.endIndexInNode,a=null,b=null,g=[],i=d.shift(),l=0,k++,!i)break}else if(!c&&(h.firstChild||h.nextSibling)){h.firstChild?(m.push(h),h=h.firstChild):h=h.nextSibling;continue}for(;;){if(h.nextSibling){h=h.nextSibling;break}if(h=m.pop(),h===e)break a}}},revert:function(){for(var a=this.reverts.length;a--;)this.reverts[a]();this.reverts=[]},prepareReplacementString:function(a,b,c,d){var e=this.options.portionMode;return e===g&&b.indexInMatch>0?"":(a=a.replace(/\$(\d+|&|`|')/g,function(a,b){var d;switch(b){case"&":d=c[0];break;case"`":d=c.input.substring(0,c.startIndex);break;case"'":d=c.input.substring(c.endIndex);break;default:d=c[+b]}return d}),e===g?a:b.isEnd?a.substring(b.indexInMatch):a.substring(b.indexInMatch,b.indexInMatch+b.text.length))},getPortionReplacementNode:function(a,b,c){var d=this.options.replace||"$&",e=this.options.wrap;if(e&&e.nodeType){var f=h.createElement("div");f.innerHTML=e.outerHTML||(new XMLSerializer).serializeToString(e),e=f.firstChild}if("function"==typeof d)return d=d(a,b,c),d&&d.nodeType?d:h.createTextNode(String(d));var g="string"==typeof e?h.createElement(e):e;return d=h.createTextNode(this.prepareReplacementString(d,a,b,c)),d.data&&g?(g.appendChild(d),g):d},replaceMatch:function(a,b,c,d){var e,f,g=b.node,i=d.node;if(g===i){var j=g;b.indexInNode>0&&(e=h.createTextNode(j.data.substring(0,b.indexInNode)),j.parentNode.insertBefore(e,j));var k=this.getPortionReplacementNode(d,a);return j.parentNode.insertBefore(k,j),d.endIndexInNoden;++n){var p=c[n],q=this.getPortionReplacementNode(p,a);p.node.parentNode.replaceChild(q,p.node),this.reverts.push(function(a,b){return function(){b.parentNode.replaceChild(a.node,b)}}(p,q)),m.push(q)}var r=this.getPortionReplacementNode(d,a);return g.parentNode.insertBefore(e,g),g.parentNode.insertBefore(l,g),g.parentNode.removeChild(g),i.parentNode.insertBefore(r,i),i.parentNode.insertBefore(f,i),i.parentNode.removeChild(i),this.reverts.push(function(){e.parentNode.removeChild(e),l.parentNode.replaceChild(g,l),f.parentNode.removeChild(f),r.parentNode.replaceChild(i,r)}),r}},b}()),U=function(){var a=S.create("div");return a.appendChild(S.create("","0-")),a.appendChild(S.create("","2")),a.normalize(),2!==a.firstChild.length}();S.extend(T.fn,{normalize:function(){return U&&this.context.normalize(),this},jinzify:function(a){return this.filter(a||null).avoid("h-jinze").replace(R.jinze.touwei,function(a,b){var c=S.create("h-jinze","touwei");return c.innerHTML=b[0],0===a.index&&a.isEnd||1===a.index?c:""}).replace(R.jinze.wei,function(a,b){var c=S.create("h-jinze","wei");return c.innerHTML=b[0],0===a.index?c:""}).replace(R.jinze.tou,function(a,b){var c=S.create("h-jinze","tou");return c.innerHTML=b[0],0===a.index&&a.isEnd||1===a.index?c:""}).replace(R.jinze.middle,function(a,b){var c=S.create("h-jinze","middle");return c.innerHTML=b[0],0===a.index&&a.isEnd||1===a.index?c:""}).endAvoid().endFilter()},groupify:function(a){var a=S.extend({biaodian:!1,hanzi:!1,kana:!1,eonmun:!1,western:!1},a||{});return this.avoid("h-word, h-char-group"),a.biaodian&&this.replace(R.group.biaodian[0],d).replace(R.group.biaodian[1],d),(a.hanzi||a.cjk)&&this.wrap(R.group.hanzi,S.clone(S.create("h-char-group","hanzi cjk"))),a.western&&this.wrap(R.group.western,S.clone(S.create("h-word","western"))),a.kana&&this.wrap(R.group.kana,S.clone(S.create("h-char-group","kana"))),(a.eonmun||a.hangul)&&this.wrap(R.group.eonmun,S.clone(S.create("h-word","eonmun hangul"))),this.endAvoid(),this},charify:function(a){var a=S.extend({avoid:!0,biaodian:!1,punct:!1,hanzi:!1,latin:!1,ellinika:!1,kirillica:!1,kana:!1,eonmun:!1},a||{});return a.avoid&&this.avoid("h-char"),a.biaodian&&this.replace(R["char"].biaodian.all,c(a.biaodian)||function(a){return e(a.text)}).replace(R["char"].biaodian.liga,c(a.biaodian)||function(a){return e(a.text)}),(a.hanzi||a.cjk)&&this.wrap(R["char"].hanzi,c(a.hanzi||a.cjk)||S.clone(S.create("h-char","hanzi cjk"))),a.punct&&this.wrap(R["char"].punct.all,c(a.punct)||S.clone(S.create("h-char","punct"))),a.latin&&this.wrap(R["char"].latin,c(a.latin)||S.clone(S.create("h-char","alphabet latin"))),(a.ellinika||a.greek)&&this.wrap(R["char"].ellinika,c(a.ellinika||a.greek)||S.clone(S.create("h-char","alphabet ellinika greek"))),(a.kirillica||a.cyrillic)&&this.wrap(R["char"].kirillica,c(a.kirillica||a.cyrillic)||S.clone(S.create("h-char","alphabet kirillica cyrillic"))),a.kana&&this.wrap(R["char"].kana,c(a.kana)||S.clone(S.create("h-char","kana"))),(a.eonmun||a.hangul)&&this.wrap(R["char"].eonmun,c(a.eonmun||a.hangul)||S.clone(S.create("h-char","eonmun hangul"))),this.endAvoid(),this}}),S.extend(O,{isNodeNormalizeNormal:U,find:T,createBDGroup:d,createBDChar:e}),S.matches=O.find.matches,void["setMode","wrap","replace","revert","addBoundary","removeBoundary","avoid","endAvoid","filter","endFilter","jinzify","groupify","charify"].forEach(function(a){O.fn[a]=function(){return this.finder||(this.finder=O.find(this.context)),this.finder[a](arguments[0],arguments[1]),this}});var V={};V.writeOnCanvas=g,V.compareCanvases=h,V.detectFont=i,V.support=function(){function b(a){var b,c=a.charAt(0).toUpperCase()+a.slice(1),d=(a+" "+e.join(c+" ")+c).split(" ");return d.forEach(function(a){"string"==typeof f.style[a]&&(b=!0)}),b||!1}function c(a,b){var c,d,e,f=L||S.create("body"),g=S.create("div"),h=L?g:f,b="function"==typeof b?b:function(){};return c=[""].join(""),h.innerHTML+=c,f.appendChild(g),L||(f.style.background="",f.style.overflow="hidden",e=K.style.overflow,K.style.overflow="hidden",K.appendChild(f)),d=b(h,a),S.remove(h),L||(K.style.overflow=e),!!d}function d(b,c){var d;return a.getComputedStyle?d=J.defaultView.getComputedStyle(b,null).getPropertyValue(c):b.currentStyle&&(d=b.currentStyle[c]),d}var e="Webkit Moz ms".split(" "),f=S.create("h-test");return{columnwidth:b("columnWidth"),fontface:function(){var a;return c('@font-face { font-family: font; src: url("//"); }',function(b,c){var d=S.qsa("style",b)[0],e=d.sheet||d.styleSheet,f=e?e.cssRules&&e.cssRules[0]?e.cssRules[0].cssText:e.cssText||"":"";a=/src/i.test(f)&&0===f.indexOf(c.split(" ")[0])}),a}(),ruby:function(){var a,b=S.create("ruby"),c=S.create("rt"),e=S.create("rp");return b.appendChild(e),b.appendChild(c),K.appendChild(b),a="none"===d(e,"display")||"ruby"===d(b,"display")&&"ruby-text"===d(c,"display")?!0:!1,K.removeChild(b),b=null,c=null,e=null,a}(),"ruby-display":function(){var a=S.create("div");return a.innerHTML='',"ruby"===a.querySelector("h-test-a").style.display&&"ruby-text-container"===a.querySelector("h-test-b").style.display}(),"ruby-interchar":function(){var a,b="inter-character",c=S.create("div");return c.innerHTML='',a=c.querySelector("h-test").style,a.rubyPosition===b||a.WebkitRubyPosition===b||a.MozRubyPosition===b||a.msRubyPosition===b}(),textemphasis:b("textEmphasis"),unicoderange:function(){var a;return c('@font-face{font-family:test-for-unicode-range;src:local(Arial),local("Droid Sans")}@font-face{font-family:test-for-unicode-range;src:local("Times New Roman"),local(Times),local("Droid Serif");unicode-range:U+270C}',function(){a=!V.detectFont("test-for-unicode-range",'Arial, "Droid Sans"',"Q")}),a}(),writingmode:b("writingMode")}}(),V.initCond=function(a){var b,a=a||K,c="";for(var d in V.support)b=(V.support[d]?"":"no-")+d,a.classList.add(b),c+=b+" ";return c};var W=V.support["ruby-interchar"];S.extend(V,{renderRuby:function(a,b){var b=b||"ruby",c=S.qsa(b,a);S.qsa("rtc",a).concat(c).map(n),c.forEach(function(a){var b,c=a.classList;c.contains("complex")?b=l(a):c.contains("zhuyin")&&(b=W?k(a):j(a)),b&&a.parentNode.replaceChild(b,a)})},simplifyRubyClass:n,getZhuyinHTML:q,renderComplexRuby:l,renderSimpleRuby:j,renderInterCharRuby:k}),S.extend(V,{renderElem:function(a){this.renderRuby(a),this.renderDecoLine(a),this.renderDecoLine(a,"s, del"),this.renderEm(a)},renderDecoLine:function(a,b){var c=S.qsa(b||"u, ins",a),d=c.length;a:for(;d--;){var e=c[d],f=null;do{if(f=(f||e).previousSibling,!f)continue a;c[d-1]===f&&e.classList.add("adjacent")}while(S.isIgnorable(f))}},renderEm:function(a,b){var c=b?"qsa":"tag",b=b||"em",d=S[c](b,a);d.forEach(function(a){var b=O(a);V.support.textemphasis?b.avoid("rt, h-char").charify({biaodian:!0,punct:!0}):b.avoid("rt, h-char, h-char-group").jinzify().groupify({western:!0}).charify({hanzi:!0,biaodian:!0,punct:!0,latin:!0,ellinika:!0,kirillica:!0})})}}),O.normalize=V,O.localize=V,O.support=V.support,O.detectFont=V.detectFont,O.fn.initCond=function(){return this.condition.classList.add("han-js-rendered"),O.normalize.initCond(this.condition),this},void["Elem","DecoLine","Em","Ruby"].forEach(function(a){var b="render"+a;O.fn[b]=function(a){return O.normalize[b](this.context,a),this}}),S.extend(O.support,{heiti:!0,songti:O.detectFont('"Han Songti"'),"songti-gb":O.detectFont('"Han Songti GB"'),kaiti:O.detectFont('"Han Kaiti"'),fangsong:O.detectFont('"Han Fangsong"')}),O.correctBiaodian=function(a){var a=a||J,b=O.find(a);return b.avoid("h-char").replace(/([\u2018\u201c])/g,function(a){var b=O.createBDChar(a.text);return b.classList.add("bd-open","punct"),b}).replace(/([\u2019\u201d])/g,function(a){var b=O.createBDChar(a.text);return b.classList.add("bd-close","bd-end","punct"),b}),O.support.unicoderange?b:b.charify({biaodian:!0})},O.correctBasicBD=O.correctBiaodian,O.correctBD=O.correctBiaodian,S.extend(O.fn,{biaodian:null,correctBiaodian:function(){return this.biaodian=O.correctBiaodian(this.context),this},revertCorrectedBiaodian:function(){try{this.biaodian.revert("all")}catch(a){}return this}}),O.fn.correctBasicBD=O.fn.correctBiaodian,O.fn.revertBasicBD=O.fn.revertCorrectedBiaodian;var X="<>",Y=S.create("h-hws");Y.setAttribute("hidden",""),Y.innerHTML=" ";var Z;S.extend(O,{renderHWS:function(a,b){var c=b?"textarea, code, kbd, samp, pre":"textarea",d=b?"strict":"base",a=a||J,e=O.find(a); +return e.avoid(c).replace(O.TYPESET.hws[d][0],t).replace(O.TYPESET.hws[d][1],t).replace(new RegExp("("+X+")+","g"),u).replace(/([\'"])\s(.+?)\s\1/g,v).replace(/\s[\u2018\u201c]/g,w).replace(/[\u2019\u201d]\s/g,w).normalize(),e}}),S.extend(O.fn,{renderHWS:function(a){return O.renderHWS(this.context,a),this},revertHWS:function(){return S.tag("h-hws",this.context).forEach(function(a){S.remove(a)}),this.HWS=[],this}});var $="bd-hangable",_="h-char.bd-hangable",aa='',ba=O.find.matches;O.support["han-space"]=x(),S.extend(O,{detectSpaceFont:x,isSpaceFontLoaded:x(),renderHanging:function(a){var a=a||J,b=O.find(a);return b.avoid("textarea, code, kbd, samp, pre").avoid(_).replace(R.jinze.hanging,function(a){if(/^[\x20\t\r\n\f]+$/.test(a.text))return"";var b,c,d,e,f=a.node.parentNode;return(b=S.parent(f,"h-jinze"))&&y(b),e=a.text.trim(),c=O.createBDChar(e),c.innerHTML=""+e+"",c.classList.add($),d=S.parent(f,"h-char.biaodian"),d?function(){return d.classList.add($),ba(f,"h-inner, h-inner *")?e:c.firstChild}():c}),b}}),S.extend(O.fn,{renderHanging:function(){var a=this.condition.classList;return O.isSpaceFontLoaded=x(),O.isSpaceFontLoaded&&a.contains("no-han-space")&&(a.remove("no-han-space"),a.add("han-space")),O.renderHanging(this.context),this},revertHanging:function(){return S.qsa("h-char.bd-hangable, h-cs.hangable-outer",this.context).forEach(function(a){var b=a.classList;b.remove("bd-hangable"),b.remove("hangable-outer")}),this}});var ca,da,ea="bd-jiya",fa="h-char.bd-jiya",ga="bd-consecutive",ha='',ba=O.find.matches;O.renderJiya=function(a){var a=a||J,b=O.find(a);return b.avoid("textarea, code, kbd, samp, pre, h-cs").avoid(fa).charify({avoid:!1,biaodian:A}).endAvoid().avoid("textarea, code, kbd, samp, pre, h-cs").replace(R.group.biaodian[0],B).replace(R.group.biaodian[1],B),b},S.extend(O.fn,{renderJiya:function(){return O.renderJiya(this.context),this},revertJiya:function(){return S.qsa("h-char.bd-jiya, h-cs.jiya-outer",this.context).forEach(function(a){var b=a.classList;b.remove("bd-jiya"),b.remove("jiya-outer")}),this}});var ia="textarea, code, kbd, samp, pre",ja=S.create("h-char","comb-liga");return S.extend(O,{isVowelCombLigaNormal:F(),isVowelICombLigaNormal:G(),isZhuyinCombLigaNormal:H(),isCombLigaNormal:G()(),substVowelCombLiga:I(O.TYPESET["display-as"]["comb-liga-vowel"]),substZhuyinCombLiga:I(O.TYPESET["display-as"]["comb-liga-zhuyin"]),substCombLigaWithPUA:I(O.TYPESET["display-as"]["comb-liga-pua"]),substInaccurateChar:function(a){var a=a||J,b=O.find(a);b.avoid(ia),O.TYPESET["inaccurate-char"].forEach(function(a){b.replace(new RegExp(a[0],"ig"),a[1])})}}),S.extend(O.fn,{"comb-liga-vowel":null,"comb-liga-vowel-i":null,"comb-liga-zhuyin":null,"inaccurate-char":null,substVowelCombLiga:function(){return this["comb-liga-vowel"]=O.substVowelCombLiga(this.context),this},substVowelICombLiga:function(){return this["comb-liga-vowel-i"]=O.substVowelICombLiga(this.context),this},substZhuyinCombLiga:function(){return this["comb-liga-zhuyin"]=O.substZhuyinCombLiga(this.context),this},substCombLigaWithPUA:function(){return O.isVowelCombLigaNormal()?O.isVowelICombLigaNormal()||(this["comb-liga-vowel-i"]=O.substVowelICombLiga(this.context)):this["comb-liga-vowel"]=O.substVowelCombLiga(this.context),O.isZhuyinCombLigaNormal()||(this["comb-liga-zhuyin"]=O.substZhuyinCombLiga(this.context)),this},revertVowelCombLiga:function(){try{this["comb-liga-vowel"].revert("all")}catch(a){}return this},revertVowelICombLiga:function(){try{this["comb-liga-vowel-i"].revert("all")}catch(a){}return this},revertZhuyinCombLiga:function(){try{this["comb-liga-zhuyin"].revert("all")}catch(a){}return this},revertCombLigaWithPUA:function(){try{this["comb-liga-vowel"].revert("all"),this["comb-liga-vowel-i"].revert("all"),this["comb-liga-zhuyin"].revert("all")}catch(a){}return this},substInaccurateChar:function(){return this["inaccurate-char"]=O.substInaccurateChar(this.context),this},revertInaccurateChar:function(){try{this["inaccurate-char"].revert("all")}catch(a){}return this}}),a.addEventListener("DOMContentLoaded",function(){var a;K.classList.contains("han-init")?O.init():(a=J.querySelector(".han-init-context"))&&(O.init=O(a).render())}),("undefined"==typeof b||b===!1)&&(a.Han=O),O}); \ No newline at end of file diff --git a/lib/algolia-instant-search/instantsearch.min.css b/lib/algolia-instant-search/instantsearch.min.css new file mode 100644 index 0000000..590f6f9 --- /dev/null +++ b/lib/algolia-instant-search/instantsearch.min.css @@ -0,0 +1 @@ +/*! instantsearch.js 1.5.0 | © Algolia Inc. and other contributors; Licensed MIT | github.com/algolia/instantsearch.js */.ais-search-box--powered-by{font-size:.8em;text-align:right;margin-top:2px}.ais-search-box--powered-by-link{display:inline-block;width:45px;height:16px;text-indent:101%;overflow:hidden;white-space:nowrap;background-image:url(data:image/png;base64,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);background-repeat:no-repeat;background-size:contain;vertical-align:middle}.ais-pagination--item{display:inline-block;padding:3px}.ais-range-slider--value,.ais-range-slider--value-sub{font-size:.8em;padding-top:15px}.ais-pagination--item__disabled{visibility:hidden}.ais-hierarchical-menu--list__lvl1,.ais-hierarchical-menu--list__lvl2{margin-left:10px}.ais-range-slider--target{position:relative;direction:ltr;background:#F3F4F7;height:6px;margin-top:2em;margin-bottom:2em}.ais-range-slider--base{height:100%;position:relative;z-index:1;border-top:1px solid #DDD;border-bottom:1px solid #DDD;border-left:2px solid #DDD;border-right:2px solid #DDD}.ais-range-slider--origin{position:absolute;right:0;top:0;left:0;bottom:0}.ais-range-slider--connect{background:#46AEDA}.ais-range-slider--background{background:#F3F4F7}.ais-range-slider--handle{width:20px;height:20px;position:relative;z-index:1;background:#FFF;border:1px solid #46AEDA;border-radius:50%;cursor:pointer}.ais-range-slider--handle-lower{left:-10px;bottom:7px}.ais-range-slider--handle-upper{right:10px;bottom:7px}.ais-range-slider--tooltip{position:absolute;background:#FFF;top:-22px;font-size:.8em}.ais-range-slider--pips{box-sizing:border-box;position:absolute;height:3em;top:100%;left:0;width:100%}.ais-range-slider--value{width:40px;position:absolute;text-align:center;margin-left:-20px}.ais-range-slider--marker{position:absolute;background:#DDD;margin-left:-1px;width:1px;height:5px}.ais-range-slider--marker-sub{background:#DDD;width:2px;margin-left:-2px;height:13px}.ais-range-slider--marker-large{background:#DDD;width:2px;margin-left:-2px;height:12px}.ais-star-rating--star,.ais-star-rating--star__empty{display:inline-block;width:1em;height:1em}.ais-range-slider--marker-large:first-child{margin-left:0}.ais-star-rating--item{vertical-align:middle}.ais-star-rating--item__active{font-weight:700}.ais-star-rating--star:before{content:'\2605';color:#FBAE00}.ais-star-rating--star__empty:before{content:'\2606';color:#FBAE00}.ais-star-rating--link__disabled .ais-star-rating--star:before,.ais-star-rating--link__disabled .ais-star-rating--star__empty:before{color:#C9C9C9}.ais-root__collapsible .ais-header{cursor:pointer}.ais-root__collapsed .ais-body,.ais-root__collapsed .ais-footer{display:none} \ No newline at end of file diff --git a/lib/algolia-instant-search/instantsearch.min.js b/lib/algolia-instant-search/instantsearch.min.js new file mode 100644 index 0000000..2bd5d59 --- /dev/null +++ b/lib/algolia-instant-search/instantsearch.min.js @@ -0,0 +1,15 @@ +/*! instantsearch.js 1.5.0 | © Algolia Inc. and other contributors; Licensed MIT | github.com/algolia/instantsearch.js */ +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.instantsearch=t():e.instantsearch=t()}(this,function(){return function(e){function t(r){if(n[r])return n[r].exports;var o=n[r]={exports:{},id:r,loaded:!1};return e[r].call(o.exports,o,o.exports,t),o.loaded=!0,o.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{"default":e}}var o=n(1),i=r(o);e.exports=i["default"]},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(t,"__esModule",{value:!0}),n(2),n(3);var o=n(4),i=r(o),a=n(5),s=r(a),u=n(99),l=r(u),c=n(222),f=r(c),p=n(400),d=r(p),h=n(404),m=r(h),v=n(408),g=r(v),y=n(411),b=r(y),_=n(416),C=r(_),w=n(420),x=r(w),P=n(422),E=r(P),R=n(424),S=r(R),O=n(425),T=r(O),k=n(432),N=r(k),j=n(437),A=r(j),M=n(439),F=r(M),I=n(443),D=r(I),U=n(444),L=r(U),H=n(447),V=r(H),B=n(450),q=r(B),W=n(220),K=r(W),Q=(0,i["default"])(s["default"]);Q.widgets={clearAll:f["default"],currentRefinedValues:d["default"],hierarchicalMenu:m["default"],hits:g["default"],hitsPerPageSelector:b["default"],menu:C["default"],refinementList:x["default"],numericRefinementList:E["default"],numericSelector:S["default"],pagination:T["default"],priceRanges:N["default"],searchBox:A["default"],rangeSlider:F["default"],sortBySelector:D["default"],starRating:L["default"],stats:V["default"],toggle:q["default"]},Q.version=K["default"],Q.createQueryString=l["default"].url.getQueryStringFromState,t["default"]=Q},function(e,t){"use strict";Object.freeze||(Object.freeze=function(e){if(Object(e)!==e)throw new TypeError("Object.freeze can only be called on Objects.");return e})},function(e,t){"use strict";var n={};if(!Object.setPrototypeOf&&!n.__proto__){var r=Object.getPrototypeOf;Object.getPrototypeOf=function(e){return e.__proto__?e.__proto__:r.call(Object,e)}}},function(e,t){"use strict";function n(e){var t=function(){for(var t=arguments.length,n=Array(t),o=0;t>o;o++)n[o]=arguments[o];return new(r.apply(e,[null].concat(n)))};return t.__proto__=e,t.prototype=e.prototype,t}var r=Function.prototype.bind;e.exports=n},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{"default":e}}function o(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function i(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function s(){return"#"}function u(e,t){if(!t.getConfiguration)return e;var n=t.getConfiguration(e);return(0,y["default"])({},e,n,function(e,t){return Array.isArray(e)?(0,_["default"])(e,t):void 0})}Object.defineProperty(t,"__esModule",{value:!0});var l=Object.assign||function(e){for(var t=1;te;e+=2){var t=re[e],n=re[e+1];t(n),re[e]=void 0,re[e+1]=void 0}G=0}function v(){try{var e=n(11);return Q=e.runOnLoop||e.runOnContext,f()}catch(t){return h()}}function g(e,t){var n=this,r=n._state;if(r===se&&!e||r===ue&&!t)return this;var o=new this.constructor(b),i=n._result;if(r){var a=arguments[r-1];X(function(){F(r,o,a,i)})}else N(n,o,e,t);return o}function y(e){var t=this;if(e&&"object"==typeof e&&e.constructor===t)return e;var n=new t(b);return S(n,e),n}function b(){}function _(){return new TypeError("You cannot resolve a promise with itself")}function C(){return new TypeError("A promises callback cannot return that same promise.")}function w(e){try{return e.then}catch(t){return le.error=t,le}}function x(e,t,n,r){try{e.call(t,n,r)}catch(o){return o}}function P(e,t,n){X(function(e){var r=!1,o=x(n,t,function(n){r||(r=!0,t!==n?S(e,n):T(e,n))},function(t){r||(r=!0,k(e,t))},"Settle: "+(e._label||" unknown promise"));!r&&o&&(r=!0,k(e,o))},e)}function E(e,t){t._state===se?T(e,t._result):t._state===ue?k(e,t._result):N(t,void 0,function(t){S(e,t)},function(t){k(e,t)})}function R(e,t,n){t.constructor===e.constructor&&n===oe&&constructor.resolve===ie?E(e,t):n===le?k(e,le.error):void 0===n?T(e,t):s(n)?P(e,t,n):T(e,t)}function S(e,t){e===t?k(e,_()):a(t)?R(e,t,w(t)):T(e,t)}function O(e){e._onerror&&e._onerror(e._result),j(e)}function T(e,t){e._state===ae&&(e._result=t,e._state=se,0!==e._subscribers.length&&X(j,e))}function k(e,t){e._state===ae&&(e._state=ue,e._result=t,X(O,e))}function N(e,t,n,r){var o=e._subscribers,i=o.length;e._onerror=null,o[i]=t,o[i+se]=n,o[i+ue]=r,0===i&&e._state&&X(j,e)}function j(e){var t=e._subscribers,n=e._state;if(0!==t.length){for(var r,o,i=e._result,a=0;aa;a++)N(r.resolve(e[a]),void 0,t,n);return o}function L(e){var t=this,n=new t(b);return k(n,e),n}function H(){throw new TypeError("You must pass a resolver function as the first argument to the promise constructor")}function V(){throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.")}function B(e){this._id=he++,this._state=void 0,this._result=void 0,this._subscribers=[],b!==e&&("function"!=typeof e&&H(),this instanceof B?I(this,e):V())}function q(e,t){this._instanceConstructor=e,this.promise=new e(b),Array.isArray(t)?(this._input=t,this.length=t.length,this._remaining=t.length,this._result=new Array(this.length),0===this.length?T(this.promise,this._result):(this.length=this.length||0,this._enumerate(),0===this._remaining&&T(this.promise,this._result))):k(this.promise,this._validationError())}function W(){var e;if("undefined"!=typeof o)e=o;else if("undefined"!=typeof self)e=self;else try{e=Function("return this")()}catch(t){throw new Error("polyfill failed because global object is unavailable in this environment")}var n=e.Promise;n&&"[object Promise]"===Object.prototype.toString.call(n.resolve())&&!n.cast||(e.Promise=me)}var K;K=Array.isArray?Array.isArray:function(e){return"[object Array]"===Object.prototype.toString.call(e)};var Q,$,z,Y=K,G=0,X=function(e,t){re[G]=e,re[G+1]=t,G+=2,2===G&&($?$(m):z())},J="undefined"!=typeof window?window:void 0,Z=J||{},ee=Z.MutationObserver||Z.WebKitMutationObserver,te="undefined"!=typeof e&&"[object process]"==={}.toString.call(e),ne="undefined"!=typeof Uint8ClampedArray&&"undefined"!=typeof importScripts&&"undefined"!=typeof MessageChannel,re=new Array(1e3);z=te?c():ee?p():ne?d():void 0===J?v():h();var oe=g,ie=y,ae=void 0,se=1,ue=2,le=new A,ce=new A,fe=D,pe=U,de=L,he=0,me=B;B.all=fe,B.race=pe,B.resolve=ie,B.reject=de,B._setScheduler=u,B._setAsap=l,B._asap=X,B.prototype={constructor:B,then:oe,"catch":function(e){return this.then(null,e)}};var ve=q;q.prototype._validationError=function(){return new Error("Array Methods must be provided an Array")},q.prototype._enumerate=function(){for(var e=this.length,t=this._input,n=0;this._state===ae&&e>n;n++)this._eachEntry(t[n],n)},q.prototype._eachEntry=function(e,t){var n=this._instanceConstructor,r=n.resolve;if(r===ie){var o=w(e);if(o===oe&&e._state!==ae)this._settledAt(e._state,t,e._result);else if("function"!=typeof o)this._remaining--,this._result[t]=e;else if(n===me){var i=new n(b);R(i,e,o),this._willSettleAt(i,t)}else this._willSettleAt(new n(function(t){t(e)}),t)}else this._willSettleAt(r(e),t)},q.prototype._settledAt=function(e,t,n){var r=this.promise;r._state===ae&&(this._remaining--,e===ue?k(r,n):this._result[t]=n),0===this._remaining&&T(r,this._result)},q.prototype._willSettleAt=function(e,t){var n=this;N(e,void 0,function(e){n._settledAt(se,t,e)},function(e){n._settledAt(ue,t,e)})};var ge=W,ye={Promise:me,polyfill:ge};n(12).amd?(r=function(){return ye}.call(t,n,t,i),!(void 0!==r&&(i.exports=r))):"undefined"!=typeof i&&i.exports?i.exports=ye:"undefined"!=typeof this&&(this.ES6Promise=ye),ge()}).call(this)}).call(t,n(9),function(){return this}(),n(10)(e))},function(e,t){function n(){l=!1,a.length?u=a.concat(u):c=-1,u.length&&r()}function r(){if(!l){var e=setTimeout(n);l=!0;for(var t=u.length;t;){for(a=u,u=[];++c1)for(var n=1;n=u.hosts[e.hostType].length&&(d||!h)?u._promise.reject(r):(u.hostIndex[e.hostType]=++u.hostIndex[e.hostType]%u.hosts[e.hostType].length,r instanceof c.RequestTimeout?v():(d||(f=1/0),t(n,s)))}function v(){return u.hostIndex[e.hostType]=++u.hostIndex[e.hostType]%u.hosts[e.hostType].length,s.timeout=u.requestTimeout*(f+1),t(n,s)}var g;if(u._useCache&&(g=e.url),u._useCache&&r&&(g+="_body_"+s.body),u._useCache&&a&&void 0!==a[g])return i("serving response from cache"),u._promise.resolve(JSON.parse(a[g]));if(f>=u.hosts[e.hostType].length)return!h||d?(i("could not get any response"),u._promise.reject(new c.AlgoliaSearchError("Cannot connect to the AlgoliaSearch API. Send an email to support@algolia.com to report and resolve the issue. Application id was: "+u.applicationID))):(i("switching to fallback"),f=0,s.method=e.fallback.method,s.url=e.fallback.url,s.jsonBody=e.fallback.body,s.jsonBody&&(s.body=l(s.jsonBody)),o=u._computeRequestHeaders(),s.timeout=u.requestTimeout*(f+1),u.hostIndex[e.hostType]=0,d=!0,t(u._request.fallback,s));var y=u.hosts[e.hostType][u.hostIndex[e.hostType]]+s.url,b={body:s.body,jsonBody:s.jsonBody,method:s.method,headers:o,timeout:s.timeout,debug:i};return i("method: %s, url: %s, headers: %j, timeout: %d",b.method,y,b.headers,b.timeout),n===u._request.fallback&&i("using fallback"),n.call(u,y,b).then(p,m)}var r,o,i=n(42)("algoliasearch:"+e.url),a=e.cache,u=this,f=0,d=!1,h=u._useFallback&&u._request.fallback&&e.fallback;this.apiKey.length>p&&void 0!==e.body&&void 0!==e.body.params?(e.body.apiKey=this.apiKey,o=this._computeRequestHeaders(!1)):o=this._computeRequestHeaders(),void 0!==e.body&&(r=l(e.body)),i("request start");var m=t(u._request,{url:e.url,method:e.method,body:r,jsonBody:e.body,timeout:u.requestTimeout*(f+1)});return e.callback?void m.then(function(t){s(function(){e.callback(null,t)},u._setTimeout||setTimeout)},function(t){s(function(){e.callback(t)},u._setTimeout||setTimeout)}):m},_getSearchParams:function(e,t){if(void 0===e||null===e)return t;for(var n in e)null!==n&&void 0!==e[n]&&e.hasOwnProperty(n)&&(t+=""===t?"":"&",t+=n+"="+encodeURIComponent("[object Array]"===Object.prototype.toString.call(e[n])?l(e[n]):e[n]));return t},_computeRequestHeaders:function(e){var t=n(15),r={"x-algolia-agent":this._ua,"x-algolia-application-id":this.applicationID};return e!==!1&&(r["x-algolia-api-key"]=this.apiKey),this.userToken&&(r["x-algolia-usertoken"]=this.userToken),this.securityTags&&(r["x-algolia-tagfilters"]=this.securityTags),this.extraHeaders&&t(this.extraHeaders,function(e){r[e.name]=e.value}),r}},r.prototype.Index.prototype={clearCache:function(){this.cache={}},addObject:function(e,t,n){var r=this;return 1!==arguments.length&&"function"!=typeof t||(n=t,t=void 0),this.as._jsonRequest({method:void 0!==t?"PUT":"POST",url:"/1/indexes/"+encodeURIComponent(r.indexName)+(void 0!==t?"/"+encodeURIComponent(t):""),body:e,hostType:"write",callback:n})},addObjects:function(e,t){var r=n(34),o="Usage: index.addObjects(arrayOfObjects[, callback])";if(!r(e))throw new Error(o);for(var i=this,a={requests:[]},s=0;sa&&(t=a),"published"!==e.status?c._promise.delay(t).then(n):e})}function r(e){s(function(){t(null,e)},c._setTimeout||setTimeout)}function o(e){s(function(){t(e)},c._setTimeout||setTimeout)}var i=100,a=5e3,u=0,l=this,c=l.as,f=n();return t?void f.then(r,o):f},clearIndex:function(e){var t=this;return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(t.indexName)+"/clear",hostType:"write",callback:e})},getSettings:function(e){var t=this;return this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(t.indexName)+"/settings",hostType:"read",callback:e})},setSettings:function(e,t){var n=this;return this.as._jsonRequest({method:"PUT",url:"/1/indexes/"+encodeURIComponent(n.indexName)+"/settings",hostType:"write",body:e,callback:t})},listUserKeys:function(e){var t=this;return this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(t.indexName)+"/keys",hostType:"read",callback:e})},getUserKeyACL:function(e,t){var n=this;return this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(n.indexName)+"/keys/"+e,hostType:"read",callback:t})},deleteUserKey:function(e,t){var n=this;return this.as._jsonRequest({method:"DELETE",url:"/1/indexes/"+encodeURIComponent(n.indexName)+"/keys/"+e,hostType:"write",callback:t})},addUserKey:function(e,t,r){var o=n(34),i="Usage: index.addUserKey(arrayOfAcls[, params, callback])";if(!o(e))throw new Error(i);1!==arguments.length&&"function"!=typeof t||(r=t,t=null);var a={acl:e};return t&&(a.validity=t.validity,a.maxQueriesPerIPPerHour=t.maxQueriesPerIPPerHour,a.maxHitsPerQuery=t.maxHitsPerQuery,a.description=t.description,t.queryParameters&&(a.queryParameters=this.as._getSearchParams(t.queryParameters,"")),a.referers=t.referers),this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/keys",body:a,hostType:"write",callback:r})},addUserKeyWithValidity:u(function(e,t,n){return this.addUserKey(e,t,n)},a("index.addUserKeyWithValidity()","index.addUserKey()")),updateUserKey:function(e,t,r,o){var i=n(34),a="Usage: index.updateUserKey(key, arrayOfAcls[, params, callback])";if(!i(t))throw new Error(a);2!==arguments.length&&"function"!=typeof r||(o=r,r=null);var s={acl:t};return r&&(s.validity=r.validity,s.maxQueriesPerIPPerHour=r.maxQueriesPerIPPerHour,s.maxHitsPerQuery=r.maxHitsPerQuery,s.description=r.description,r.queryParameters&&(s.queryParameters=this.as._getSearchParams(r.queryParameters,"")),s.referers=r.referers),this.as._jsonRequest({method:"PUT",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/keys/"+e,body:s,hostType:"write",callback:o})},_search:function(e,t,n){return this.as._jsonRequest({cache:this.cache,method:"POST",url:t||"/1/indexes/"+encodeURIComponent(this.indexName)+"/query",body:{params:e},hostType:"read",fallback:{method:"GET",url:"/1/indexes/"+encodeURIComponent(this.indexName),body:{params:e}},callback:n})},as:null,indexName:null,typeAheadArgs:null,typeAheadValueOption:null}},function(e,t,n){"use strict";function r(e,t){var r=n(15),o=this;"function"==typeof Error.captureStackTrace?Error.captureStackTrace(this,this.constructor):o.stack=(new Error).stack||"Cannot get a stacktrace, browser is too old",this.name=this.constructor.name,this.message=e||"Unknown error",t&&r(t,function(e,t){o[t]=e})}function o(e,t){function n(){var n=Array.prototype.slice.call(arguments,0);"string"!=typeof n[0]&&n.unshift(t),r.apply(this,n),this.name="AlgoliaSearch"+e+"Error"}return i(n,r),n}var i=n(7);i(r,Error),e.exports={AlgoliaSearchError:r,UnparsableJSON:o("UnparsableJSON","Could not parse the incoming response as JSON, see err.more for details"),RequestTimeout:o("RequestTimeout","Request timedout before getting a response"),Network:o("Network","Network issue, see err.more for details"),JSONPScriptFail:o("JSONPScriptFail"," + + + + + + + + + + CoderShmily's Blog + + + + - + + + + + + + + + + + + + + - + + +

    - -
    - - + - + + + + - - + + + + - + + + -
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - \ No newline at end of file + From 3b6d4c2a7b97fb08687a33574ec4f703befb6064 Mon Sep 17 00:00:00 2001 From: shmily Date: Fri, 5 May 2017 15:22:22 +0800 Subject: [PATCH 074/148] Customize commit message --- .../index.html" | 24 +- .../index.html" | 24 +- .../index.html" | 24 +- .../index.html" | 24 +- .../index.html" | 24 +- .../index.html" | 24 +- .../index.html" | 24 +- .../index.html" | 24 +- .../index.html" | 20 +- .../index.html" | 24 +- .../index.html" | 24 +- .../index.html" | 24 +- .../index.html" | 24 +- .../index.html" | 24 +- archives/2015/05/index.html | 20 +- archives/2015/06/index.html | 20 +- archives/2015/index.html | 20 +- archives/2015/page/2/index.html | 20 +- archives/2016/11/index.html | 20 +- archives/2016/12/index.html | 20 +- archives/2016/index.html | 20 +- archives/index.html | 20 +- archives/page/2/index.html | 20 +- categories/Swift/index.html | 20 +- categories/iOS/index.html | 28 +- categories/iOS/page/2/index.html | 20 +- css/main.css | 355 +++++++++++++++--- index.html | 74 ++-- page/2/index.html | 40 +- 29 files changed, 645 insertions(+), 404 deletions(-) diff --git "a/2015/05/01/Swift \345\205\245\351\227\250/index.html" "b/2015/05/01/Swift \345\205\245\351\227\250/index.html" index fff606d..2d79bb0 100644 --- "a/2015/05/01/Swift \345\205\245\351\227\250/index.html" +++ "b/2015/05/01/Swift \345\205\245\351\227\250/index.html" @@ -5,7 +5,7 @@ - + @@ -124,7 +124,7 @@ var NexT = window.NexT || {}; var CONFIG = { root: '/', - scheme: 'Muse', + scheme: 'Mist', sidebar: {"position":"left","display":"post","offset":12,"offset_float":0,"b2t":false,"scrollpercent":false}, fancybox: true, motion: true, @@ -216,7 +216,7 @@
    - Home + Startseite @@ -226,7 +226,7 @@
    - Archives + Archiv @@ -296,7 +296,7 @@

    Swift 入门

    - +
    @@ -729,7 +729,7 @@

    2 - categories + Kategorien @@ -797,13 +797,13 @@

    - Powered by Hexo + Erstellt mit Hexo diff --git "a/2015/05/02/\345\215\225\344\276\213\346\250\241\345\274\217\347\232\204ARC\345\222\214MRC\345\256\236\347\216\260/index.html" "b/2015/05/02/\345\215\225\344\276\213\346\250\241\345\274\217\347\232\204ARC\345\222\214MRC\345\256\236\347\216\260/index.html" index 91bda23..1a0a473 100644 --- "a/2015/05/02/\345\215\225\344\276\213\346\250\241\345\274\217\347\232\204ARC\345\222\214MRC\345\256\236\347\216\260/index.html" +++ "b/2015/05/02/\345\215\225\344\276\213\346\250\241\345\274\217\347\232\204ARC\345\222\214MRC\345\256\236\347\216\260/index.html" @@ -5,7 +5,7 @@ - + @@ -107,7 +107,7 @@ var NexT = window.NexT || {}; var CONFIG = { root: '/', - scheme: 'Muse', + scheme: 'Mist', sidebar: {"position":"left","display":"post","offset":12,"offset_float":0,"b2t":false,"scrollpercent":false}, fancybox: true, motion: true, @@ -199,7 +199,7 @@
    - Home + Startseite @@ -209,7 +209,7 @@
    - Archives + Archiv @@ -279,7 +279,7 @@

    单例模式的ARC和MRC实现 - +

    单例模式的ARC和MRC实现 - + @@ -463,10 +463,10 @@

    @@ -487,7 +487,7 @@

    14 - posts + Artikel @@ -498,7 +498,7 @@

    2 - categories + Kategorien @@ -566,13 +566,13 @@

    - Powered by Hexo + Erstellt mit Hexo diff --git "a/2015/05/03/KVC \345\222\214 KVO\346\267\261\345\205\245/index.html" "b/2015/05/03/KVC \345\222\214 KVO\346\267\261\345\205\245/index.html" index 52f5180..7910d5b 100644 --- "a/2015/05/03/KVC \345\222\214 KVO\346\267\261\345\205\245/index.html" +++ "b/2015/05/03/KVC \345\222\214 KVO\346\267\261\345\205\245/index.html" @@ -5,7 +5,7 @@ - + @@ -107,7 +107,7 @@ var NexT = window.NexT || {}; var CONFIG = { root: '/', - scheme: 'Muse', + scheme: 'Mist', sidebar: {"position":"left","display":"post","offset":12,"offset_float":0,"b2t":false,"scrollpercent":false}, fancybox: true, motion: true, @@ -199,7 +199,7 @@
    - Home + Startseite @@ -209,7 +209,7 @@
    - Archives + Archiv @@ -279,7 +279,7 @@

    KVC 和 KVO深入

    - +

    @@ -525,7 +525,7 @@

    14 - posts + Artikel @@ -536,7 +536,7 @@

    2 - categories + Kategorien @@ -604,13 +604,13 @@

    - Powered by Hexo + Erstellt mit Hexo diff --git "a/2015/05/04/Objective-C Runtime(\344\272\214) \345\257\271\350\261\241\346\250\241\345\236\213/index.html" "b/2015/05/04/Objective-C Runtime(\344\272\214) \345\257\271\350\261\241\346\250\241\345\236\213/index.html" index 8b40a64..5e411e4 100644 --- "a/2015/05/04/Objective-C Runtime(\344\272\214) \345\257\271\350\261\241\346\250\241\345\236\213/index.html" +++ "b/2015/05/04/Objective-C Runtime(\344\272\214) \345\257\271\350\261\241\346\250\241\345\236\213/index.html" @@ -5,7 +5,7 @@ - + @@ -110,7 +110,7 @@ var NexT = window.NexT || {}; var CONFIG = { root: '/', - scheme: 'Muse', + scheme: 'Mist', sidebar: {"position":"left","display":"post","offset":12,"offset_float":0,"b2t":false,"scrollpercent":false}, fancybox: true, motion: true, @@ -202,7 +202,7 @@
    - Home + Startseite @@ -212,7 +212,7 @@
    - Archives + Archiv @@ -282,7 +282,7 @@

    Objective-C Runtime(二) 对象 - +

    Objective-C Runtime(二) 对象 - + @@ -497,10 +497,10 @@

    @@ -521,7 +521,7 @@

    14 - posts + Artikel @@ -532,7 +532,7 @@

    2 - categories + Kategorien @@ -600,13 +600,13 @@

    - Powered by Hexo + Erstellt mit Hexo diff --git "a/2015/05/05/Objective-C Runtime(\344\270\200) \346\246\202\350\277\260/index.html" "b/2015/05/05/Objective-C Runtime(\344\270\200) \346\246\202\350\277\260/index.html" index 7c0ad96..abef9b4 100644 --- "a/2015/05/05/Objective-C Runtime(\344\270\200) \346\246\202\350\277\260/index.html" +++ "b/2015/05/05/Objective-C Runtime(\344\270\200) \346\246\202\350\277\260/index.html" @@ -5,7 +5,7 @@ - + @@ -107,7 +107,7 @@ var NexT = window.NexT || {}; var CONFIG = { root: '/', - scheme: 'Muse', + scheme: 'Mist', sidebar: {"position":"left","display":"post","offset":12,"offset_float":0,"b2t":false,"scrollpercent":false}, fancybox: true, motion: true, @@ -199,7 +199,7 @@
    - Home + Startseite @@ -209,7 +209,7 @@
    - Archives + Archiv @@ -279,7 +279,7 @@

    Objective-C Runtime(一) 概述< - +

    Objective-C Runtime(一) 概述< - + @@ -496,10 +496,10 @@
    @@ -520,7 +520,7 @@
    14 - posts + Artikel @@ -531,7 +531,7 @@
    2 - categories + Kategorien @@ -599,13 +599,13 @@
    - Powered by Hexo + Erstellt mit Hexo diff --git "a/2015/05/06/Objective-C Runtime(\344\270\211) \346\266\210\346\201\257\344\274\240\351\200\222/index.html" "b/2015/05/06/Objective-C Runtime(\344\270\211) \346\266\210\346\201\257\344\274\240\351\200\222/index.html" index 8008464..6040e92 100644 --- "a/2015/05/06/Objective-C Runtime(\344\270\211) \346\266\210\346\201\257\344\274\240\351\200\222/index.html" +++ "b/2015/05/06/Objective-C Runtime(\344\270\211) \346\266\210\346\201\257\344\274\240\351\200\222/index.html" @@ -5,7 +5,7 @@ - + @@ -107,7 +107,7 @@ var NexT = window.NexT || {}; var CONFIG = { root: '/', - scheme: 'Muse', + scheme: 'Mist', sidebar: {"position":"left","display":"post","offset":12,"offset_float":0,"b2t":false,"scrollpercent":false}, fancybox: true, motion: true, @@ -199,7 +199,7 @@
    - Home + Startseite @@ -209,7 +209,7 @@
    - Archives + Archiv @@ -279,7 +279,7 @@

    Objective-C Runtime(三) 消息 - +

    Objective-C Runtime(三) 消息 - + @@ -481,10 +481,10 @@

    总结 @@ -505,7 +505,7 @@

    总结 14 - posts + Artikel @@ -516,7 +516,7 @@

    总结 2 - categories + Kategorien @@ -584,13 +584,13 @@

    总结 - Powered by Hexo + Erstellt mit Hexo diff --git "a/2015/05/07/Objective-C Runtime(\345\233\233) \345\212\250\346\200\201\346\226\271\346\263\225\345\206\263\350\256\256/index.html" "b/2015/05/07/Objective-C Runtime(\345\233\233) \345\212\250\346\200\201\346\226\271\346\263\225\345\206\263\350\256\256/index.html" index a5f6892..de8a5c9 100644 --- "a/2015/05/07/Objective-C Runtime(\345\233\233) \345\212\250\346\200\201\346\226\271\346\263\225\345\206\263\350\256\256/index.html" +++ "b/2015/05/07/Objective-C Runtime(\345\233\233) \345\212\250\346\200\201\346\226\271\346\263\225\345\206\263\350\256\256/index.html" @@ -5,7 +5,7 @@ - + @@ -134,7 +134,7 @@ var NexT = window.NexT || {}; var CONFIG = { root: '/', - scheme: 'Muse', + scheme: 'Mist', sidebar: {"position":"left","display":"post","offset":12,"offset_float":0,"b2t":false,"scrollpercent":false}, fancybox: true, motion: true, @@ -226,7 +226,7 @@
    - Home + Startseite @@ -236,7 +236,7 @@
    - Archives + Archiv @@ -306,7 +306,7 @@

    Objective-C Runtime(四) 动态 - +