YYKit 源碼講解(3)

接下來我們看Base文件夾下的UIKIt文件夾的內容卫袒。

1.UIColor+YYAdd

這里看了這個類桃熄,里面有許多顏色之間的轉換卦停,因此借此機會弦悉,順便看看顏色之間的轉換原理

RGB2HSL

HSL 色調飽和亮度模式 摘自文章

H色調 0~360 圓環(huán)形式 以角度表示

S 飽和度 0~1 之間的小數(shù)

L 亮度 0~1 之間的小數(shù)

什么是純色

先來看一下windows的拾色器




最上頭黑色框里面那些顏色 最最最頂端的部分耿戚。

是不是感覺他們最鮮艷 最惹眼湿故,嗯 因為他們RGB之間的差異化最大

RGB產生顏色的原理就是RGB三個能量值產生差異化 組合。

所以我們才能看到這些花花綠綠的顏色膜蛔。

純色一個特點那就是最大值跟最小值的差是255 坛猪,差異達到最大。

也就是說RGB一定有一個顏色是0 一個是255飞几,否則不能稱之為純色

純亮度表示就是只能量值沒有差異 也指灰度圖

純色的計算

通過觀察windows畫圖板拾色器 就是上面中間那個破圖砚哆。我們知道 如果飽和度固定為1 亮度固定為0.5 独撇,那么色調即純色 純色即色調屑墨。純色的定義參見上面。

從RGB值的變化規(guī)律可以看出色調的變化是連續(xù)平緩 首尾相接的 可以看成是一個360度的圓 紅色是0度纷铣。他的變化規(guī)律是:


三個規(guī)律

1至始至終都有一個值是0 一個值是255卵史。

2整個過程中同一時間總是只有一個值在變

3三個數(shù)的全排列 那么總共有6種組合

但是首先有一點要明確: 上面餅圖的一塊 就是60度 值是255

我們把色調分成1~360的表現(xiàn)形式,但是RGB是以(255,255,255)的表現(xiàn)形式 那么他們之間怎么對應呢搜立?那就是60度=255

每前進一度scale+=(255*6)*(1/360)

RGB可以表達255*255*255=16581375種顏色 但是他可以表達的純色只有255*6=1530種

所以HSL 標示的顏色能少點(所以RGB 轉換成HSL 肯定是要少顏色值的)

通過上面我們知道了H的色值標示范圍

接下來我們看看HLS的定義

HSL在數(shù)學上定義為在 RGB 空間中的顏色的R,GB的坐標的變換以躯。

從 RGB 到 HSL ?的轉換

設 (r,g,b) 分別是一個顏色的紅、綠和藍坐標啄踊,它們的值是在 0 到 1 之間的實數(shù)忧设。設max等價于r,gb中的最大者。設min等于這些值中的最小者颠通。要找到在 HSL 空間中的 (h,s,l) 值址晕,這里的h∈ [0, 360)是角度的色相角,而s,l∈ [0,1] 是飽和度和亮度顿锰,計算為:


谨垃、启搂、




h的值通常規(guī)范化到位于 0 到 360°之間。而h= 0 用于max=min的(就是灰色)時候而不是留下h未定義刘陶。

從 RGB 到 HSV 的轉換

色相和HSL 一樣sv不一樣而已



從 HSL 到 RGB 的轉換

給定 HSL 空間中的 (h,s,l) 值定義的一個顏色胳赌,帶有h在指示色相角度的值域 [0, 360)中,分別表示飽和度和亮度的sl在值域 [0, 1] 中匙隔,相應在 RGB 空間中的 (r,g,b) 三原色疑苫,帶有分別對應于紅色、綠色和藍色的r,gb也在值域 [0, 1] 中纷责,它們可計算為:

首先缀匕,如果s= 0,則結果的顏色是非彩色的碰逸、或灰色的乡小。在這個特殊情況,r,gb都等于l饵史。注意h的值在這種情況下是未定義的满钟。

s≠ 0 的時候,可以使用下列過程




這里定義了好多顏色轉換是c語言寫的胳喷。這里不想做過多介紹

void YY_RGB2HSL(CGFloat r, CGFloat g, CGFloat b,CGFloat *h, CGFloat *s, CGFloat *l)

void YY_HSL2RGB(CGFloat h, CGFloat s, CGFloat l,CGFloat *r, CGFloat *g, CGFloat *b)

void YY_RGB2HSB(CGFloat r, CGFloat g, CGFloat b,CGFloat *h, CGFloat *s, CGFloat *v)

void YY_HSB2RGB(CGFloat h, CGFloat s, CGFloat v,CGFloat *r, CGFloat *g, CGFloat *b)

void YY_RGB2CMYK(CGFloat r, CGFloat g, CGFloat b,CGFloat *c, CGFloat *m, CGFloat *y, CGFloat *k)

void YY_CMYK2RGB(CGFloat c, CGFloat m, CGFloat y, CGFloat k,CGFloat *r, CGFloat *g, CGFloat *b)

void YY_HSB2HSL(CGFloat h, CGFloat s, CGFloat b,CGFloat *hh, CGFloat *ss, CGFloat *ll)

void YY_HSL2HSB(CGFloat h, CGFloat s, CGFloat l,CGFloat *hh, CGFloat *ss, CGFloat *bb)



顏色之間的相互轉換

+ (UIColor *)colorWithHue:(CGFloat)hue saturation:(CGFloat)saturation lightness:(CGFloat)lightness alpha:(CGFloat)alpha

就是用hsL 顏色空間湃番,由于系統(tǒng)默認的是rgb 將hsl 轉換成了RGB

+ (UIColor *)colorWithCyan:(CGFloat)cyan magenta:(CGFloat)magenta yellow:(CGFloat)yellow black:(CGFloat)black alpha:(CGFloat)alpha

cmyk 轉換成rgb

+ (UIColor *)colorWithRGB:(uint32_t)rgbValue {

return [UIColor colorWithRed:((rgbValue & 0xFF0000) >> 16) / 255.0f

green:((rgbValue & 0xFF00) >> 8) / 255.0f

blue:(rgbValue & 0xFF) / 255.0f

alpha:1];

這個傳入的是一個顏色值,位操作

+ (UIColor *)colorWithRGBA:(uint32_t)rgbaValue {

return [UIColor colorWithRed:((rgbaValue & 0xFF000000) >> 24) / 255.0f

green:((rgbaValue & 0xFF0000) >> 16) / 255.0f

blue:((rgbaValue & 0xFF00) >> 8) / 255.0f

alpha:(rgbaValue & 0xFF) / 255.0f];

}


帶有alpha 通道的RGBA

+ (UIColor *)colorWithRGB:(uint32_t)rgbValue alpha:(CGFloat)alpha {

return [UIColor colorWithRed:((rgbValue & 0xFF0000) >> 16) / 255.0f

green:((rgbValue & 0xFF00) >> 8) / 255.0f

blue:(rgbValue & 0xFF) / 255.0f

alpha:alpha];

}

RGBA 傳入?yún)?shù)不一致而已

- (uint32_t)rgbValue {

CGFloat r = 0, g = 0, b = 0, a = 0;

[self getRed:&r green:&g blue:&b alpha:&a];

int8_t red = r * 255;

uint8_t green = g * 255;

uint8_t blue = b * 255;

return (red << 16) + (green << 8) + blue;

}

獲取rgb值吭露,不帶a通道

- (uint32_t)rgbaValue {

CGFloat r = 0, g = 0, b = 0, a = 0;

[self getRed:&r green:&g blue:&b alpha:&a];

int8_t red = r * 255;

uint8_t green = g * 255;

uint8_t blue = b * 255;

uint8_t alpha = a * 255;

return (red << 24) + (green << 16) + (blue << 8) + alpha;

}

獲取rgba?

static inline NSUInteger hexStrToInt(NSString *str) {

uint32_t result = 0;

sscanf([str UTF8String], "%X", &result);

return result;

}

內斂函數(shù)吠撮, ?這個將str 轉換成 int值

static BOOL hexStrToRGBA(NSString *str,

CGFloat *r, CGFloat *g, CGFloat *b, CGFloat *a)

str = [[str stringByTrim] uppercaseString];

if ([str hasPrefix:@"#"]) {

str = [str substringFromIndex:1];

} else if ([str hasPrefix:@"0X"]) {

str = [str substringFromIndex:2];

}

NSUInteger length = [str length];

//? ? ? ? RGB? ? ? ? ? ? RGBA? ? ? ? ? RRGGBB? ? ? ? RRGGBBAA

if (length != 3 && length != 4 && length != 6 && length != 8) {

return NO;

}

//RGB,RGBA,RRGGBB,RRGGBBAA

if (length < 5) {

*r = hexStrToInt([str substringWithRange:NSMakeRange(0, 1)]) / 255.0f;

*g = hexStrToInt([str substringWithRange:NSMakeRange(1, 1)]) / 255.0f;

*b = hexStrToInt([str substringWithRange:NSMakeRange(2, 1)]) / 255.0f;

if (length == 4)? *a = hexStrToInt([str substringWithRange:NSMakeRange(3, 1)]) / 255.0f;

else *a = 1;

} else {

*r = hexStrToInt([str substringWithRange:NSMakeRange(0, 2)]) / 255.0f;

*g = hexStrToInt([str substringWithRange:NSMakeRange(2, 2)]) / 255.0f;

*b = hexStrToInt([str substringWithRange:NSMakeRange(4, 2)]) / 255.0f;

if (length == 8) *a = hexStrToInt([str substringWithRange:NSMakeRange(6, 2)]) / 255.0f;

else *a = 1;

}

return YES;

}

適配了各種書寫形式RGB,RGBA,RRGGBB,RRGGBBAA 帶# 或者0X 或者不帶都可以

+ (instancetype)colorWithHexString:(NSString *)hexStr

- (NSString *)hexString

- (NSString *)hexStringWithAlpha

基礎不做介紹

- (NSString *)hexStringWithAlpha:(BOOL)withAlpha {

CGColorRef color = self.CGColor;

size_t count = CGColorGetNumberOfComponents(color);

const CGFloat *components = CGColorGetComponents(color);

static NSString *stringFormat = @"%02x%02x%02x";

NSString *hex = nil;

if (count == 2) {

NSUInteger white = (NSUInteger)(components[0] * 255.0f);

hex = [NSString stringWithFormat:stringFormat, white, white, white];

} else if (count == 4) {

hex = [NSString stringWithFormat:stringFormat,

(NSUInteger)(components[0] * 255.0f),

(NSUInteger)(components[1] * 255.0f),

(NSUInteger)(components[2] * 255.0f)];

}

if (hex && withAlpha) {

hex = [hex stringByAppendingFormat:@"%02lx",

(unsigned long)(self.alpha * 255.0 + 0.5)];

}

return hex;

}

這里分為 count=2 和count = 4 黑白形式count=2(CGColorCreateGenericGray) 普通形式count=4

- (UIColor *)colorByAddColor:(UIColor *)add blendMode:(CGBlendMode)blendMode {

CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big;

uint8_t pixel[4] = { 0 };

CGContextRef context = CGBitmapContextCreate(&pixel, 1, 1, 8, 4, colorSpace, bitmapInfo);

CGContextSetFillColorWithColor(context, self.CGColor);

CGContextFillRect(context, CGRectMake(0, 0, 1, 1));

CGContextSetBlendMode(context, blendMode);

CGContextSetFillColorWithColor(context, add.CGColor);

CGContextFillRect(context, CGRectMake(0, 0, 1, 1));

CGContextRelease(context);

CGColorSpaceRelease(colorSpace);

return [UIColor colorWithRed:pixel[0] / 255.0f green:pixel[1] / 255.0f blue:pixel[2] / 255.0f alpha:pixel[3] / 255.0f];

}


kCGImageAlphaPremultipliedLast 是顏色編排采用RGBA模式

kCGBitmapByteOrder32Big ?才有32 大字節(jié)序

大端字節(jié)(Big-endian):

----------------->>>>>>>>內存地址增大方向

short變量地址

0x1000????????????????? 0x1001

_____________________________

|?????????????????????????? |

|???????? 0x31???????????? |?????? 0x32

|________________ | ________________

高位字節(jié)在低位字節(jié)的前面,也就是高位在內存地址低的一端.可以這樣記住(大端->高位->在前->正常的邏輯順序)

小端字節(jié)(little-endian):

----------------->>>>>>>>內存地址增大方向

short變量地址

0x1000????????????????? 0x1001

_____________________________

|?????????????????????????? |

|???????? 0x32???????????? |?????? 0x31

|________________ | ________________

低位字節(jié)在高位字節(jié)的前面,也就是低位在內存地址低的一端.可以這樣記住(小端->低位->在前->與正常邏輯順序相反)

? ?就是規(guī)定bitmap 的采用RGBA 32位 在內存中

這里函數(shù)就是顏色之間的融合,根據(jù)CGBlendMode模式

什么是CGBlendMode模式呢

Overview

These blend mode constants represent the Porter-Duff blend modes. The symbols in the equations for these blend modes are:

R is the premultiplied result

S is the source color, and includes alpha

D is the destination color, and includes alpha

Ra, Sa, and Da are the alpha components of R, S, and D

You can find more information on blend modes, including examples of images produced using them, and many mathematical descriptions of the modes, inPDF Reference, Fourth Edition, Version 1.5, Adobe Systems, Inc. If you are a former QuickDraw developer, it may be helpful for you to think of blend modes as an alternative to transfer modes

那我們就看看什么是Porter-Duff讲竿。這里有篇博客做介紹

R 是結果

S是source 帶有alpha

D 是目標顏色 帶有alpha

Ra Sa泥兰,Da 是代表R S D 的透明度

說白了就是兩種顏色融合的模式。


- (UIColor *)colorByChangeHue:(CGFloat)h saturation:(CGFloat)s brightness:(CGFloat)b alpha:(CGFloat)a

增加HSL 的顏色

- (BOOL)getHue:(CGFloat *)hue saturation:(CGFloat *)saturation lightness:(CGFloat *)lightness alpha:(CGFloat *)alpha

- (BOOL)getCyan:(CGFloat *)cyan magenta:(CGFloat *)magenta yellow:(CGFloat *)yellow

black:(CGFloat *)black alpha:(CGFloat *)alpha

- (CGFloat)red

- (CGFloat)green

- (CGFloat)blue

- (CGFloat)alpha

- (CGFloat)hue

- (CGFloat)saturation

- (CGFloat)brightness

- (CGColorSpaceModel)colorSpaceModel

- (NSString *)colorSpaceString

簡單不做介紹

2.UIImage+YYAdd

這個類好長啊题禀。慢慢看吧

+ (UIImage *)imageWithSmallGIFData:(NSData *)data scale:(CGFloat)scale

獲取gif 圖片?

這個函數(shù)分段看

CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFTypeRef)(data), NULL);

if (!source) return nil;

size_t count = CGImageSourceGetCount(source);

if (count <= 1) {

CFRelease(source);

return [self.class imageWithData:data scale:scale];

}

1將gif NSData 轉換成source 鞋诗,這個source 包含了gif圖的一些基本信息。

2 檢查gif 動圖的圖片數(shù)量迈嘹。要是小于或者等于一張削彬,就直接生成圖片就行了。

NSUInteger frames[count];

double oneFrameTime = 1 / 50.0; // 50 fps

NSTimeInterval totalTime = 0;

NSUInteger totalFrame = 0;

NSUInteger gcdFrame = 0;

for (size_t i = 0; i < count; i++) {

NSTimeInterval delay = _yy_CGImageSourceGetGIFFrameDelayAtIndex(source, i);

totalTime += delay;

NSInteger frame = lrint(delay / oneFrameTime);

if (frame < 1) frame = 1;

frames[i] = frame;

totalFrame += frames[i];

if (i == 0) gcdFrame = frames[i];

else {

NSUInteger frame = frames[i], tmp;

if (frame < gcdFrame) {

tmp = frame; frame = gcdFrame; gcdFrame = tmp;

}

while (true) {

tmp = frame % gcdFrame;

if (tmp == 0) break;

frame = gcdFrame;

gcdFrame = tmp;

}

}

}

1定義變量秀仲,從命名可以看出是干啥用的融痛。

2.這里主要看for循環(huán),

NSTimeInterval delay = _yy_CGImageSourceGetGIFFrameDelayAtIndex(source, i);

static NSTimeInterval _yy_CGImageSourceGetGIFFrameDelayAtIndex(CGImageSourceRef source, size_t index) {

NSTimeInterval delay = 0;

CFDictionaryRef dic = CGImageSourceCopyPropertiesAtIndex(source, index, NULL);

if (dic) {

CFDictionaryRef dicGIF = CFDictionaryGetValue(dic, kCGImagePropertyGIFDictionary);

if (dicGIF) {

NSNumber *num = CFDictionaryGetValue(dicGIF, kCGImagePropertyGIFUnclampedDelayTime);

if (num.doubleValue <= __FLT_EPSILON__) {

num = CFDictionaryGetValue(dicGIF, kCGImagePropertyGIFDelayTime);

}

delay = num.doubleValue;

}

CFRelease(dic);

}

// http://nullsleep.tumblr.com/post/16524517190/animated-gif-minimum-frame-delay-browser-compatibility

if (delay < 0.02) delay = 0.1;

return delay;

}

這個c函數(shù)干啥了呢

1.獲取gif 沒一張圖片的屬性保存在dic中

2.如果有屬性dic 神僵,那么獲取kCGImagePropertyGIFDictionary 字典的值

3.如果獲取到了gif 字典雁刷,獲取delay時間。

4.要是delay 時間小于0.02 那么設置為0.1?

關于這個0.1秒挑豌“踩看這里?掘金也可以

不過所有人的設置大小是0.011s 墩崩。yykit這里設置的是0.02 秒。沒查到相關技術指標侯勉。不做評論


返回for循環(huán)接著看

3.將圖片間隔時間累加到totaltime變量上

rint, rintf, rintl, lrint, lrintf, lrintl, llrint, llrintf, llrintl

定義于頭文件

floatrintf(floatarg);(1)(C99 起)

doublerint(doublearg);(2)(C99 起)

longdoublerintl(longdoublearg);(3)(C99 起)

定義于頭文件

#define rint( arg )(4)(C99 起)

定義于頭文件

longlrintf(floatarg);(5)(C99 起)

longlrint(doublearg);(6)(C99 起)

longlrintl(longdoublearg);(7)(C99 起)

定義于頭文件

#define lrint( arg )(8)(C99 起)

定義于頭文件

longlongllrintf(floatarg);(9)(C99 起)

longlongllrint(doublearg);(10)(C99 起)

longlongllrintl(longdoublearg);(11)(C99 起)

定義于頭文件

#define llrint( arg )(12)(C99 起)

1-3)用當前舍入模式鹦筹,舍入浮點參數(shù)arg為整數(shù)值(以浮點格式)。

5-7, 9-11)用當前舍入模式址貌,舍入浮點參數(shù)arg為整數(shù)值铐拐。

4,8,12)泛型宏:若arg擁有l(wèi)ongdouble類型,练对,則調用rintl遍蟋、lrintl、llrintl螟凭。否則若arg擁有整數(shù)或double類型虚青,則調用rint、lrint螺男、llrint棒厘。否則分別調用rintf、lrintf下隧、llrintf奢人。

lrint 函數(shù)用法

4 保存frame 。累加totalFrame

5.gcdFrame 保存第一次的frame

6.檢查后面的frame 淆院,要是比gcdFrame 小何乎,就gcdFrame 保存最小的frame

7.獲取最小公約數(shù)?

NSMutableArray *array = [NSMutableArray new];

8.生成一個數(shù)組

for (size_t i = 0; i < count; i++) {

CGImageRef imageRef = CGImageSourceCreateImageAtIndex(source, i, NULL);

if (!imageRef) {

CFRelease(source);

return nil;

}

size_t width = CGImageGetWidth(imageRef);

size_t height = CGImageGetHeight(imageRef);

if (width == 0 || height == 0) {

CFRelease(source);

CFRelease(imageRef);

return nil;

}

CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(imageRef) & kCGBitmapAlphaInfoMask;

BOOL hasAlpha = NO;

if (alphaInfo == kCGImageAlphaPremultipliedLast ||

alphaInfo == kCGImageAlphaPremultipliedFirst ||

alphaInfo == kCGImageAlphaLast ||

alphaInfo == kCGImageAlphaFirst) {

hasAlpha = YES;

}

// BGRA8888 (premultiplied) or BGRX8888

// same as UIGraphicsBeginImageContext() and -[UIView drawRect:]

CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host;

bitmapInfo |= hasAlpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst;

CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();

CGContextRef context = CGBitmapContextCreate(NULL, width, height, 8, 0, space, bitmapInfo);

CGColorSpaceRelease(space);

if (!context) {

CFRelease(source);

CFRelease(imageRef);

return nil;

}

CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef); // decode

CGImageRef decoded = CGBitmapContextCreateImage(context);

CFRelease(context);

if (!decoded) {

CFRelease(source);

CFRelease(imageRef);

return nil;

}

UIImage *image = [UIImage imageWithCGImage:decoded scale:scale orientation:UIImageOrientationUp];

CGImageRelease(imageRef);

CGImageRelease(decoded);

if (!image) {

CFRelease(source);

return nil;

}

for (size_t j = 0, max = frames[i] / gcdFrame; j < max; j++) {

[array addObject:image];

}

}

9 進入for循環(huán)

10 通過source 獲取image 土辩,要是沒有image 那么就返回了nil

11.獲取沒張image的長度寬度 還有alpha

kCGBitmapAlphaInfoMask 這里出現(xiàn)這個東西支救,干啥的,看了半天沒懂啥意思脯燃。

不經意間看見了這個東西

typedef CF_ENUM(uint32_t, CGImageByteOrderInfo) {

kCGImageByteOrderMask? ? = 0x7000,

kCGImageByteOrder16Little = (1 << 12),

kCGImageByteOrder32Little = (2 << 12),

kCGImageByteOrder16Big? ? = (3 << 12),

kCGImageByteOrder32Big? ? = (4 << 12)

}

這里也出現(xiàn)了mask 搂妻。kCGImageByteOrderMask? ? = 0x7000,?

二進制是00000111000000000000 ?

kCGImageByteOrder16Little 是00000001000000000000

寫到這里應該很明顯了蒙保。kCGImageByteOrderMask 就是規(guī)定CGImageByteOrderInfo 用的哪些位置的值辕棚。將其他位置的值給過濾掉

這里出現(xiàn)了好多alpha通道的枚舉

alpha的兩種類型,直通和預乘:

帶alpha的圖片有兩種計算方法邓厕,一種叫做直通alpha(straightalpha)逝嚎,一種叫做預乘alpha(premultipliedalpha)。這兩種類型在AE軟件里是市場可以看到的详恼,當你導入一張帶通道的圖片补君,比如說TGA,AE就會問你昧互,這張圖的alpha是怎么來的挽铁,是直通類型還是預乘類型伟桅。

這兩種類型的唯一區(qū)別在于,直通alpha圖片保留最原本的RGB數(shù)值叽掘;而預乘alpha楣铁,是原本的RGB信息乘以alpha的數(shù)值以后得到的結果(預乘意思就是預先乘以alpha)。

Premultiplied 明白這個意思就夠了更扁。

kCGImageAlphaPremultipliedLast 預乘 alpha 通道在最后面RGBA?

kCGImageAlphaPremultipliedFirst 預乘 alpha 通道在最前面 ARGB?

kCGImageAlphaLast 普通的RGBA 盖腕,沒有預乘

kCGImageAlphaFirst 普通的ARGB,沒有預乘

還有幾種形式

kCGImageAlphaNoneSkipLast, /* For example, RBGX. */沒有a通道

kCGImageAlphaNoneSkipFirst,? ? ? /* For example, XRGB. */

kCGImageAlphaOnly ?/* No color data, alpha data only */

12.CGBitmapInfo 采用的是kCGImageAlphaPremultipliedFirst 預乘 ARGB浓镜,顏色空間是rgb

13.獲取bitmap的context

14 draw image?

15.獲取image

16 保存image 到數(shù)組中溃列。

17 生成gif image

這個函數(shù)講解完畢了,總結下

1.這個函數(shù)主要是將gif 圖片轉換成可以識別的image動圖格式

2.根據(jù)每個動圖的間隔時間計算出最小間隔時間間隔膛薛,兩張圖片的時間間隔用最小間隔時間*次數(shù)標示听隐,動畫數(shù)組中添加次數(shù)個image圖片

3.將gif 圖片轉換成bitmap圖片。

4.這里用的數(shù)學方式找最大公約數(shù)


+ (BOOL)isAnimatedGIFData:(NSData *)data

大神在這個里面提供了一個網址https://www.w3.org/Graphics/GIF/spec-gif89a.txt

這里判斷gif的方式是

UInt32 magic = *(UInt32 *)data.bytes;

// http://www.w3.org/Graphics/GIF/spec-gif89a.txt

if ((magic & 0xFFFFFF) != '\0FIG') return NO;

這里注意哄啄,UInt32 是和data數(shù)據(jù)方向相反的?

gif數(shù)據(jù)的前三位是 474946

而UInt32 magic = *(UInt32 *)data.bytes; magic 的值是0xXX464947 遵绰,這是因為讀取數(shù)據(jù)都是從頭按照字節(jié)讀取的,先讀取47 放入magic的最低位增淹,再讀取49放入第二位椿访,最后46放入第三位

接下來判斷是否能轉換成source 并且gif 是否只有一張圖

沒有souce或者count不大于1都默認為不是gif

+ (BOOL)isAnimatedGIFFile:(NSString *)path

文件讀取是不是gif 不過這里沒有判斷,count和source 是否含有而只是通過FiLE指針獲取特定位置虑润,這樣也是節(jié)省開支效率吧

+ (UIImage *)imageWithPDF:(id)dataOrPath

+ (UIImage *)imageWithPDF:(id)dataOrPath size:(CGSize)size

+ (UIImage *)_yy_imageWithPDF:(id)dataOrPath resize:(BOOL)resize size:(CGSize)size

?{

CGPDFDocumentRef pdf = NULL;

if ([dataOrPath isKindOfClass:[NSData class]]) {

CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)dataOrPath);

pdf = CGPDFDocumentCreateWithProvider(provider);

CGDataProviderRelease(provider);

} else if ([dataOrPath isKindOfClass:[NSString class]]) {

pdf = CGPDFDocumentCreateWithURL((__bridge CFURLRef)[NSURL fileURLWithPath:dataOrPath]);

}

if (!pdf) return nil;

CGPDFPageRef page = CGPDFDocumentGetPage(pdf, 1);

if (!page) {

CGPDFDocumentRelease(pdf);

return nil;

}

CGRect pdfRect = CGPDFPageGetBoxRect(page, kCGPDFCropBox);

CGSize pdfSize = resize ? size : pdfRect.size;

CGFloat scale = [UIScreen mainScreen].scale;

CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

CGContextRef ctx = CGBitmapContextCreate(NULL, pdfSize.width * scale, pdfSize.height * scale, 8, 0, colorSpace, kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedFirst);

if (!ctx) {

CGColorSpaceRelease(colorSpace);

CGPDFDocumentRelease(pdf);

return nil;

}

CGContextScaleCTM(ctx, scale, scale);

CGContextTranslateCTM(ctx, -pdfRect.origin.x, -pdfRect.origin.y);

CGContextDrawPDFPage(ctx, page);

CGPDFDocumentRelease(pdf);

CGImageRef image = CGBitmapContextCreateImage(ctx);

UIImage *pdfImage = [[UIImage alloc] initWithCGImage:image scale:scale orientation:UIImageOrientationUp];

CGImageRelease(image);

CGContextRelease(ctx);

CGColorSpaceRelease(colorSpace);

return pdfImage;

}


放在一起看成玫,最后都是調用最后這個函數(shù)

1.生成CGPDFDocumentRef 對象

2.獲取pdf 頁數(shù)

3.獲取每頁的大小

4.檢查是否需要重新設置大小

5創(chuàng)建bitmap context?

6 下面就是context 的矩陣轉換了

7將 page 花在context上

8從bitmap context 獲取 image

沒什么難點。簡單介紹

就是講pdf 轉換成image

+ (UIImage *)imageWithEmoji:(NSString *)emoji size:(CGFloat)size {

if (emoji.length == 0) return nil;

if (size < 1) return nil;

CGFloat scale = [UIScreen mainScreen].scale;

CTFontRef font = CTFontCreateWithName(CFSTR("AppleColorEmoji"), size * scale, NULL);

if (!font) return nil;

NSAttributedString *str = [[NSAttributedString alloc] initWithString:emoji attributes:@{ (__bridge id)kCTFontAttributeName:(__bridge id)font, (__bridge id)kCTForegroundColorAttributeName:(__bridge id)[UIColor whiteColor].CGColor }];

CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

CGContextRef ctx = CGBitmapContextCreate(NULL, size * scale, size * scale, 8, 0, colorSpace, kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedFirst);

CGContextSetInterpolationQuality(ctx, kCGInterpolationHigh);

CTLineRef line = CTLineCreateWithAttributedString((__bridge CFTypeRef)str);

CGRect bounds = CTLineGetBoundsWithOptions(line, kCTLineBoundsUseGlyphPathBounds);

CGContextSetTextPosition(ctx, 0, -bounds.origin.y);

CTLineDraw(line, ctx);

CGImageRef imageRef = CGBitmapContextCreateImage(ctx);

UIImage *image = [[UIImage alloc] initWithCGImage:imageRef scale:scale orientation:UIImageOrientationUp];

CFRelease(font);

CGColorSpaceRelease(colorSpace);

CGContextRelease(ctx);

if (line)CFRelease(line);

if (imageRef) CFRelease(imageRef);

return image;

}

將emoji 轉換成圖片

蘋果的emoji表情字體 名字是AppleColorEmoji

1.根據(jù)屏幕創(chuàng)建字體

2創(chuàng)建屬性字符串

3.創(chuàng)建bitmap圖片

4通過處理獲取emoji圖片大小?kCTLineBoundsUseGlyphPathBounds ?

1.字符(Character)和字形(Glyphs)

排版系統(tǒng)中文本顯示的一個重要的過程就是字符到字形的轉換拳喻,字符是信息本身的元素哭当,而字形是字符的圖形表征,字符還會有其它表征比如發(fā)音冗澈。 字符在計算機中其實就是一個編碼钦勘,某個字符集中的編碼,比如Unicode字符集亚亲,就囊括了大都數(shù)存在的字符彻采。 而字形則是圖形,一般都存儲在字體文件中捌归,字形也有它的編碼肛响,也就是它在字體中的索引。 一個字符可以對應多個字形

這里獲取的是字形

5.獲取image

+ (UIImage *)imageWithColor:(UIColor *)color

+ (UIImage *)imageWithColor:(UIColor *)color size:(CGSize)size

通過color 獲取image 老生常談的問題了惜索。不做說明

+ (UIImage *)imageWithSize:(CGSize)size drawBlock:(void (^)(CGContextRef context))drawBlock {

if (!drawBlock) return nil;

UIGraphicsBeginImageContextWithOptions(size, NO, 0);

CGContextRef context = UIGraphicsGetCurrentContext();

if (!context) return nil;

drawBlock(context);

UIImage *image = UIGraphicsGetImageFromCurrentImageContext();

UIGraphicsEndImageContext();

return image;

}

這里主要是回調一個context 可以自定義繪制內容

- (BOOL)hasAlphaChannel

是否有alpha通道

- (void)drawInRect:(CGRect)rect withContentMode:(UIViewContentMode)contentMode clipsToBounds:(BOOL)clips

看這個函數(shù)我們先看看

1根據(jù)contentMode ?獲取rect

2根據(jù)是否clip 進行drawInRect

- (UIImage *)imageByResizeToSize:(CGSize)size

重新設置image 大小

- (UIImage *)imageByResizeToSize:(CGSize)size contentMode:(UIViewContentMode)contentMode

重設大小 根據(jù)模式

- (UIImage *)imageByCropToRect:(CGRect)rect

設置修剪圖片的到rect

這里有個函數(shù)是CGImageCreateWithImageInRect 特笋。

If W and H are the width and height of image, respectively, then the

point (0,0) corresponds to the first pixel of the image data; the point

(W-1, 0) is the last pixel of the first row of the image data; (0, H-1)

is the first pixel of the last row of the image data; and (W-1, H-1) is

the last pixel of the last row of the image data.

這個是按照像素一行一行的在rect排列的。把一行超出去的都舍棄掉巾兆。相當于裁剪圖片猎物。

- (UIImage *)imageByInsetEdge:(UIEdgeInsets)insets withColor:(UIColor *)color

這個函數(shù)就是給image增加一個UIEdgeInsets 邊緣虎囚,圖片壓縮,邊框邊緣顏色是傳入的顏色蔫磨。

這里有個CGContextEOFillPath 填充規(guī)則溜宽。網上很多。自己查閱

- (UIImage *)imageByRoundCornerRadius:(CGFloat)radius

- (UIImage *)imageByRoundCornerRadius:(CGFloat)radius borderWidth:(CGFloat)borderWidth borderColor:(UIColor *)borderColor

- (UIImage *)imageByRoundCornerRadius:(CGFloat)radius corners:(UIRectCorner)corners borderWidth:(CGFloat)borderWidth borderColor:(UIColor *)borderColor borderLineJoin:(CGLineJoin)borderLineJoin

這里有個枚舉UIRectCorner 枚舉 质帅。枚舉的是矩形的四個角

這個方法就是采用UIBezierPath 進行rect繪制适揉。將圖片放入其中

UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectInset(rect, borderWidth, borderWidth) byRoundingCorners:corners cornerRadii:CGSizeMake(radius, borderWidth)];

可以自定義繪制圓角的位置。

這里內容不難理解煤惩。只是要自己繪制效果看看即可嫉嘀。

- (UIImage *)imageByRotate:(CGFloat)radians fitSize:(BOOL)fitSize

- (UIImage *)_yy_flipHorizontal:(BOOL)horizontal vertical:(BOOL)vertical

這個函數(shù)vImageVerticalReflect_ARGB8888 這個是垂直翻轉像素鬼悠,相當于倒立

vImageHorizontalReflect_ARGB8888 水平翻轉像素上岗。相當于照鏡子

這個函數(shù)就是是否設置圖像翻轉,上下翻轉或者左右翻轉


- (UIImage *)imageByRotateLeft90?

左旋轉90度

- (UIImage *)imageByRotateRight90

右旋轉90度

- (UIImage *)imageByRotate180?

旋轉180

- (UIImage *)imageByFlipVertical

- (UIImage *)imageByFlipHorizontal

垂直或者水平旋轉

- (UIImage *)imageByTintColor:(UIColor *)color

填充顏色

- (UIImage *)imageByGrayscale

- (UIImage *)imageByBlurSoft

- (UIImage *)imageByBlurLight

- (UIImage *)imageByBlurExtraLigh

- (UIImage *)imageByBlurDark

- (UIImage *)imageByBlurWithTint:(UIColor *)tintColor

這幾個函數(shù)都是調用

- (UIImage *)imageByBlurRadius:(CGFloat)blurRadius tintColor:(UIColor *)tintColor tintMode:(CGBlendMode)tintBlendMode saturation:(CGFloat)saturation maskImage:(UIImage *)maskImage

這個函數(shù)有150行音瓷,有點長洛退,我們分開看

1瓣俯。參數(shù)校驗,self 和maskImage 必須有CGImage兵怯,blueRadius 或者Saturation 必須設置彩匕。

2 判斷是否有vImageBuffer_InitWithCGImage 函數(shù)。 將imageRef 以format形式書寫到effect中媒区。而scratch 以effect的內從初始化(effect 相當于bitmap圖驼仪,effect 相當于畫布,大小和bitmap大小相同)袜漩。這里不想過多介紹這個函數(shù)绪爸。簡單明白就行了

從來沒看過vImage.Framework 框架,看這個函數(shù)比較困難宙攻,暫時放過去奠货。后期研究這個

- (UIImage *)_yy_mergeImageRef:(CGImageRef)effectCGImage

tintColor:(UIColor *)tintColor

tintBlendMode:(CGBlendMode)tintBlendMode

maskImage:(UIImage *)maskImage

opaque:(BOOL)opaque

這個函數(shù)等以后在看。

3.UIControl+YYAdd

- (void)setTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents {

if (!target || !action || !controlEvents) return;

NSSet *targets = [self allTargets];

for (id currentTarget in targets) {

NSArray *actions = [self actionsForTarget:currentTarget forControlEvent:controlEvents];

for (NSString *currentAction in actions) {

[self removeTarget:currentTarget action:NSSelectorFromString(currentAction)

forControlEvents:controlEvents];

}

}

[self addTarget:target action:action forControlEvents:controlEvents];

}


就是講target 關聯(lián)的controlevents 的action 替換掉

- (void)addBlockForControlEvents:(UIControlEvents)controlEvents

block:(void (^)(id sender))block

我認為這個方法還是很關鍵的座掘,給uicontrol 增加block的回調形式

看了很多yykit大神寫的block回調递惋,其實都是中間增加一個中間target 。給self 分類增加一個關聯(lián)引用數(shù)組雹顺,用這個數(shù)組保存這個target

這個方法同樣適用

1生成中間對象target.讓target 保存block對象

2.給UIControl 增加action 目標對象是target?

3.將target 保存在數(shù)組里

這樣UIControl 觸發(fā)時間丹墨,會調用target 的 action 。action 執(zhí)行block事件就ok了

- (void)removeAllBlocksForControlEvents:(UIControlEvents)controlEvents

這個就是add 的逆向寫法 不做介紹了

- (void)setBlockForControlEvents:(UIControlEvents)controlEvents

block:(void (^)(id sender))block

1removeBlock?

2增加block

這里有個枚舉UIControlEventAllEvents 嬉愧。值是0xFFFFFFFF ,相當于mask 喉前。所有事件&UIControlEventAllEvents 都是true没酣。

4.UIBarButtonItem+YYAdd

- (void)setActionBlock:(void (^)(id sender))block

增加UIBarButtonItem 的block形式王财。封裝和UIControl 一樣。不做介紹

5.UIGestureRecognizer+YYAdd

- (void)addActionBlock:(void (^)(id sender))block

這個UIGestureRecognizer 也是單純的增加了block回調的形式裕便。封裝和UIControl一樣的手法绒净。不做介紹

6.UIView+YYAdd

- (UIImage *)snapshotImage

截圖UIView

- (UIImage *)snapshotImageAfterScreenUpdates:(BOOL)afterUpdates

這個方法是對- (BOOL)drawViewHierarchyInRect:(CGRect)rect afterScreenUpdates:(BOOL)afterUpdates 方法的封裝

afterUpdates

A Boolean value that indicates whether the snapshot should be rendered after recent changes have been incorporated. Specify the valueNOif you want to render a snapshot in the view hierarchy’s current state, which might not include recent changes.

這里發(fā)現(xiàn)一篇文章,講述截圖的偿衰。地址挂疆。沒仔細看,后期寫完回去再看看這里的具體實現(xiàn)細節(jié)下翎。

- (NSData *)snapshotPDF

渲染成pdf

- (void)setLayerShadow:(UIColor*)color offset:(CGSize)offset radius:(CGFloat)radius

layer 陰影設置

shadowOpacity ?陰影的透明度缤言,默認是0 ? 范圍 0-1 越大越不透明

shouldRasterize設成true時,layer被渲染成一個bitmap视事,并緩存起來胆萧,等下次使用時不會再重新去渲染了。

shouldRasterize

實現(xiàn)組透明的效果俐东,如果它被設置為YES跌穗,在應用透明度之前,圖層及其子圖層都會被整合成一個整體的圖片虏辫,這樣就沒有透明度混合的問題了;

為了啟用shouldRasterize屬性蚌吸,我們設置了圖層的rasterizationScale屬性。默認情況下砌庄,所有圖層拉伸都是1.0套利, 所以如果你使用了shouldRasterize屬性,你就要確保你設置了rasterizationScale屬性去匹配屏幕鹤耍,以防止出現(xiàn)Retina屏幕像素化的問題肉迫。

這里知識點挺多的,與性能有關系稿黄。沒有仔細看的文章地址?地址2

- (void)removeAllSubviews

刪除subview

- (UIViewController *)viewController {

for (UIView *view = self; view; view = view.superview) {

UIResponder *nextResponder = [view nextResponder];

if ([nextResponder isKindOfClass:[UIViewController class]]) {

return (UIViewController *)nextResponder;

}

}

return nil;

}

查找view 的頂層控制器喊衫。 為啥這么寫,其實我們要了解響應鏈杆怕。

事件響應鏈:當用戶點擊一個UIView時族购,系統(tǒng)會產生一個事件,并將其放入UIApplication的事件隊列中陵珍。然后該事件會順著這條鏈傳遞到用戶點擊的那個UIView:UIApplication->UIWindow->RootView->...->Subview寝杖。然后開始處理這個事件,若Subview不處理互纯,事件將會傳遞給其?視圖控制器瑟幕,若沒有控制器則傳給其superView,最后傳給UIWindow,UIApplication。若UIApplication還是沒處理則將事件傳給nil只盹。


UIResponder具有nextResponder屬性,也就是其SuperView或是UIViewConterller等辣往。UIView是UIResponder的子類,所以UIView及其子類都能使用此屬性殖卑。


- (CGFloat)visibleAlpha

可視透明度站削。UIView 遍歷到最后的根都是UIWindow

這里用了透明度的累積

- (CGPoint)convertPoint:(CGPoint)point toViewOrWindow:(UIView *)view

- (CGPoint)convertPoint:(CGPoint)point fromViewOrWindow:(UIView *)view

- (CGRect)convertRect:(CGRect)rect toViewOrWindow:(UIView *)view

- (CGRect)convertRect:(CGRect)rect fromViewOrWindow:(UIView *)view

坐標轉換 。

- (CGFloat)left

- (void)setLeft:(CGFloat)x

- (CGFloat)top

- (void)setTop:(CGFloat)y

- (CGFloat)right

- (void)setRight:(CGFloat)right

- (CGFloat)bottom

- (void)setBottom:(CGFloat)bottom

- (CGFloat)width

- (void)setWidth:(CGFloat)width

- (CGFloat)height

- (void)setHeight:(CGFloat)height

- (CGFloat)centerX

- (void)setCenterX:(CGFloat)centerX

- (CGFloat)centerY

- (void)setCenterY:(CGFloat)centerY

- (CGPoint)origin

- (void)setOrigin:(CGPoint)origin

- (CGSize)size

- (void)setSize:(CGSize)size

7.UIScrollView+YYAdd

- (void)scrollToTop

- (void)scrollToBottom

- (void)scrollToLeft

- (void)scrollToRight

簡單的封裝孵稽。

8.UITableView+YYAdd

- (void)updateWithBlock:(void (^)(UITableView *tableView))block

更新tableview?

- (void)scrollToRow:(NSUInteger)row inSection:(NSUInteger)section atScrollPosition:(UITableViewScrollPosition)scrollPosition animated:(BOOL)animated

滾動到row

- (void)insertRowAtIndexPath:(NSIndexPath *)indexPath withRowAnimation:(UITableViewRowAnimation)animation

增加row

- (void)insertRow:(NSUInteger)row inSection:(NSUInteger)section withRowAnimation:(UITableViewRowAnimation)animation

同上

- (void)reloadRowAtIndexPath:(NSIndexPath *)indexPath withRowAnimation:(UITableViewRowAnimation)animation

刷新row

- (void)reloadRow:(NSUInteger)row inSection:(NSUInteger)section withRowAnimation:(UITableViewRowAnimation)animation

同上

- (void)deleteRowAtIndexPath:(NSIndexPath *)indexPath withRowAnimation:(UITableViewRowAnimation)animation

刪除row

- (void)deleteRow:(NSUInteger)row inSection:(NSUInteger)section withRowAnimation:(UITableViewRowAnimation)animation

同上

- (void)insertSection:(NSUInteger)section withRowAnimation:(UITableViewRowAnimation)animation

- (void)deleteSection:(NSUInteger)section withRowAnimation:(UITableViewRowAnimation)animation

- (void)reloadSection:(NSUInteger)section withRowAnimation:(UITableViewRowAnimation)animation

對section 的增刪 更新

- (void)clearSelectedRowsAnimated:(BOOL)animated

清除選中的row


9.UITextField+YYAdd

- (void)selectAllText

選中所有文本

- (void)setSelectedRange:(NSRange)range?

選中特定范圍文本


10.UIScreen+YYAdd

+ (CGFloat)screenScale

獲取screen scale

- (CGRect)currentBounds

獲取screen bound 豎屏的bounds

- (CGRect)boundsForOrientation:(UIInterfaceOrientation)orientation

返回豎屏的bounds

- (CGSize)sizeInPixel

獲取屏幕像素點大小

- (CGFloat)pixelsPerInch?

獲取單位長度的像素點

這里了解ppi 公式是

以iphone3gs分辨率為480*320為例

可以看看這個博客许起。這樣的博客很多,可以自行查閱

11.UIDevice+YYAdd

+ (double)systemVersion

獲取系統(tǒng)版本

- (BOOL)isPad

判斷是否是ipad

- (BOOL)isJailbroken

檢查是否越獄菩鲜,由于沒有想過經歷园细,不做深究。

- (BOOL)canMakePhoneCalls

是否能打電話

- (NSString *)ipAddressWithIfaName:(NSString *)name

getifaddrs 獲取本機地址

判斷ifaName 的ip地址字符串

.把ip地址轉化為用于網絡傳輸?shù)亩M制數(shù)值

int inet_aton(const char *cp, struct in_addr *inp);

inet_aton() 轉換網絡主機地址ip(如192.168.1.10)為二進制數(shù)值睦袖,并存儲在struct in_addr結構中珊肃,即第二個參數(shù)*inp,函數(shù)返回非0表示cp主機有地有效,返回0表示主機地址無效馅笙。(這個轉換完后不能用于網絡傳輸伦乔,還需要調用htons或htonl函數(shù)才能將主機字節(jié)順序轉化為網絡字節(jié)順序)

in_addr_t inet_addr(const char *cp);

inet_addr函數(shù)轉換網絡主機地址(如192.168.1.10)為網絡字節(jié)序二進制值,如果參數(shù)char *cp無效董习,函數(shù)返回-1(INADDR_NONE),這個函數(shù)在處理地址為255.255.255.255時也返回-1,255.255.255.255是一個有效的地址烈和,不過inet_addr無法處理;

- (NSString *)ipAddressWIFI

檢查ip地址是否是wifi

- (NSString *)ipAddressCell

檢查ip地址是否是蜂窩

- (uint64_t)getNetworkTrafficBytes:(YYNetworkTrafficType)types

這里先看自定義的YYNetworkTrafficType

typedef NS_OPTIONS(NSUInteger, YYNetworkTrafficType) {

YYNetworkTrafficTypeWWANSent? ? = 1 << 0,

YYNetworkTrafficTypeWWANReceived = 1 << 1,

YYNetworkTrafficTypeWIFISent? ? = 1 << 2,

YYNetworkTrafficTypeWIFIReceived = 1 << 3,

YYNetworkTrafficTypeAWDLSent? ? = 1 << 4,

YYNetworkTrafficTypeAWDLReceived = 1 << 5,

YYNetworkTrafficTypeWWAN = YYNetworkTrafficTypeWWANSent | YYNetworkTrafficTypeWWANReceived,

YYNetworkTrafficTypeWIFI = YYNetworkTrafficTypeWIFISent | YYNetworkTrafficTypeWIFIReceived,

YYNetworkTrafficTypeAWDL = YYNetworkTrafficTypeAWDLSent | YYNetworkTrafficTypeAWDLReceived,

YYNetworkTrafficTypeALL = YYNetworkTrafficTypeWWAN |

YYNetworkTrafficTypeWIFI |

YYNetworkTrafficTypeAWDL,

};

/**

Network traffic type:

WWAN: Wireless Wide Area Network.

For example: 3G/4G.

WIFI: Wi-Fi.

AWDL: Apple Wireless Direct Link (peer-to-peer connection).

For exmaple: AirDrop, AirPlay, GameKit.

*/

這是yykit大神自己的解釋

針對wwan wifi awdl 分別定義了send 和recevice

接下來看

static yy_net_interface_counter yy_get_net_interface_counter() c函數(shù)

static yy_net_interface_counter yy_get_net_interface_counter() {

static dispatch_semaphore_t lock;

static NSMutableDictionary *sharedInCounters;

static NSMutableDictionary *sharedOutCounters;

static dispatch_once_t onceToken;

dispatch_once(&onceToken, ^{

sharedInCounters = [NSMutableDictionary new];

sharedOutCounters = [NSMutableDictionary new];

lock = dispatch_semaphore_create(1);

});

yy_net_interface_counter counter = {0};

struct ifaddrs *addrs;

const struct ifaddrs *cursor;

if (getifaddrs(&addrs) == 0) {

cursor = addrs;

dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);

while (cursor) {

if (cursor->ifa_addr->sa_family == AF_LINK) {

const struct if_data *data = cursor->ifa_data;

NSString *name = cursor->ifa_name ? [NSString stringWithUTF8String:cursor->ifa_name] : nil;

if (name) {

uint64_t counter_in = ((NSNumber *)sharedInCounters[name]).unsignedLongLongValue;

counter_in = yy_net_counter_add(counter_in, data->ifi_ibytes);

sharedInCounters[name] = @(counter_in);

uint64_t counter_out = ((NSNumber *)sharedOutCounters[name]).unsignedLongLongValue;

counter_out = yy_net_counter_add(counter_out, data->ifi_obytes);

sharedOutCounters[name] = @(counter_out);

if ([name hasPrefix:@"en"]) {

counter.en_in += counter_in;

counter.en_out += counter_out;

} else if ([name hasPrefix:@"awdl"]) {

counter.awdl_in += counter_in;

counter.awdl_out += counter_out;

} else if ([name hasPrefix:@"pdp_ip"]) {

counter.pdp_ip_in += counter_in;

counter.pdp_ip_out += counter_out;

}

}

}

cursor = cursor->ifa_next;

}

dispatch_semaphore_signal(lock);

freeifaddrs(addrs);

}

return counter;

}

1.創(chuàng)建一個信號量鎖dispatch_semaphore_t 初始化一些變量

2.初始化yy_net_interface_counter 結構體

typedef struct {

uint64_t en_in;

uint64_t en_out;

uint64_t pdp_ip_in;

uint64_t pdp_ip_out;

uint64_t awdl_in;

uint64_t awdl_out;

} yy_net_interface_counter;

en 代表ip地址

pdp 代表我們使用的cell

awdl代表?Apple Wireless Direct Link

3.循環(huán)讀取ip地址?

這里代表AF_LINK 鏈路層接口

我用模擬器打印了這個函數(shù)的返回的部分信息

NSString *name = cursor->ifa_name ? [NSString stringWithUTF8String:cursor->ifa_name] : @"nil";

NSLog(@"%d name:%@",cursor->ifa_addr->sa_family,name);

2017-12-20 11:12:16.218952+0800 YYKitDemo[25918:11075457] 18 name:lo0

2017-12-20 11:12:16.219145+0800 YYKitDemo[25918:11075457] 2 name:lo0

2017-12-20 11:12:16.219377+0800 YYKitDemo[25918:11075457] 30 name:lo0

2017-12-20 11:12:16.219560+0800 YYKitDemo[25918:11075457] 30 name:lo0

2017-12-20 11:12:16.219693+0800 YYKitDemo[25918:11075457] 18 name:gif0

2017-12-20 11:12:16.219798+0800 YYKitDemo[25918:11075457] 18 name:stf0

2017-12-20 11:12:16.220025+0800 YYKitDemo[25918:11075457] 18 name:XHC20

2017-12-20 11:12:16.220134+0800 YYKitDemo[25918:11075457] 18 name:en0

2017-12-20 11:12:16.220254+0800 YYKitDemo[25918:11075457] 30 name:en0

2017-12-20 11:12:16.220356+0800 YYKitDemo[25918:11075457] 2 name:en0

2017-12-20 11:12:16.220689+0800 YYKitDemo[25918:11075457] 18 name:p2p0

2017-12-20 11:12:16.220869+0800 YYKitDemo[25918:11075457] 18 name:awdl0

2017-12-20 11:12:16.221108+0800 YYKitDemo[25918:11075457] 30 name:awdl0

2017-12-20 11:12:16.221408+0800 YYKitDemo[25918:11075457] 18 name:en1

2017-12-20 11:12:16.221628+0800 YYKitDemo[25918:11075457] 18 name:en2

2017-12-20 11:12:16.221955+0800 YYKitDemo[25918:11075457] 18 name:bridge0

2017-12-20 11:12:16.222193+0800 YYKitDemo[25918:11075457] 18 name:utun0

2017-12-20 11:12:16.222497+0800 YYKitDemo[25918:11075457] 30 name:utun0

#define AF_LINK 18?#define AF_INET 2?#define AF_INET6 30 ?

可以看出來,AF_lINK 包含了?AF_INET ?AF_INET6 是所有連接的都會返回來

這里調用c函數(shù)

static uint64_t yy_net_counter_add(uint64_t counter, uint64_t bytes) {

if (bytes < (counter % 0xFFFFFFFF)) {

counter += 0xFFFFFFFF - (counter % 0xFFFFFFFF);

counter += bytes;

} else {

counter = bytes;

}

return counter;

}

如果bytes 比counter 取模小 皿淋,那么我就將counter 的前面32 位置0招刹,而高位加1,再加上bytes窝趣。(沒看懂)

要是比counter取模大疯暑,直接賦值。

4用counter 記錄結果

5 獲取網絡字節(jié)數(shù)

- (NSString *)machineModel

獲取設備model

還有一種方法

struct utsname systemInfo;

uname(&systemInfo);

NSString *deviceString = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding];

不知道這兩種獲取方式有啥不同


- (NSString *)machineModelName

獲取設備model 字符串

- (NSDate *)systemUptime?

系統(tǒng)開機時間

- (int64_t)diskSpace

磁盤空間

- (int64_t)diskSpaceFree

磁盤剩余空間

- (int64_t)diskSpaceUsed

用戶使用空間

- (int64_t)memoryTotal

內存大小

- (int64_t)memoryUsed

使用的內存大小

- (int64_t)memoryFree

剩余內存大小

- (int64_t)memoryActive?

激活內存大小

- (int64_t)memoryInactive

未激活內存大小

- (int64_t)memoryWired


- (int64_t)memoryPurgable


- (NSUInteger)cpuCount

cpu數(shù)量

- (float)cpuUsage

cpu 使用的比例

- (NSArray *)cpuUsagePerProcessor

每個processor中cpu的使用比例

這部分內存獲取查閱資料很少哑舒,暫時不做深究妇拯。

12.UIApplication+YYAdd

- (NSURL *)documentsURL

- (NSString *)documentsPath

獲取document 文件路徑或者url

- (NSURL *)cachesURL

- (NSString *)cachesPath

獲取caches 文件路徑或者url

- (NSURL *)libraryURL

- (NSString *)libraryPath

獲取library文件路徑或者url

- (BOOL)isPirated

檢查是否是盜版的?

- (BOOL)_yy_fileExistInMainBundle:(NSString *)name

檢查文件是否存在

- (NSString *)appBundleName

獲取bundleName

- (NSString *)appBundleID

獲取bundleId

- (NSString *)appVersion

獲取app版本

- (NSString *)appBuildVersion

build版本

- (BOOL)isBeingDebugged

是否是debug模式

- (int64_t)memoryUsage

- (float)cpuUsage

- (void)incrementNetworkActivityCount

- (void)decrementNetworkActivityCount


+ (BOOL)isAppExtension

是否是app的extension

+ (UIApplication *)sharedExtensionApplication


13.UIFont+YYAdd

- (BOOL)isBold?

粗體

- (BOOL)isItalic

斜體

- (BOOL)isMonoSpace

MonoSpace?

- (BOOL)isColorGlyphs

- (CGFloat)fontWeight

字體大小

- (UIFont *)fontWithBold

轉換成粗體

- (UIFont *)fontWithItalic

轉換成斜體

- (UIFont *)fontWithBoldItalic

轉換成粗斜體

- (UIFont *)fontWithNormal

正常字體

+ (UIFont *)fontWithCTFont:(CTFontRef)CTFont

將CT轉換成UIFont

+ (UIFont *)fontWithCGFont:(CGFontRef)CGFont size:(CGFloat)size

將cgFont 轉換成UIFont

- (CTFontRef)CTFontRef CF_RETURNS_RETAINED

轉換成CTFont

CF_RETURNS_NOT_RETAINED ? 讓編譯器幫助我們管理內存

- (CGFontRef)CGFontRef CF_RETURNS_RETAINED

轉換成CGFont

+ (BOOL)loadFontFromPath:(NSString *)path

加載字體路徑

+ (void)unloadFontFromPath:(NSString *)path

自定義字體卸載

這里只介紹了自己的加載和卸載。具體自定義字體詳查資料

+ (UIFont *)loadFontFromData:(NSData *)data

獲取自定義字體

+ (BOOL)unloadFontFromData:(UIFont *)font

卸載字體

+ (NSData *)dataFromFont:(UIFont *)font

將字體轉換成data


14.UIBezierPath+YYAdd


+ (UIBezierPath *)bezierPathWithText:(NSString *)text font:(UIFont *)font?

獲取字體的bezierPath

1就是將text 換著NSAttributedString?

2獲取CTLine?

3 再獲取CTRun

4 再從CTRun中獲取每個字的path


這個文件夾的東西都是功能類洗鸵。大多數(shù)不難越锈,過于簡單的不做介紹了。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末膘滨,一起剝皮案震驚了整個濱河市甘凭,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌火邓,老刑警劉巖丹弱,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件德撬,死亡現(xiàn)場離奇詭異,居然都是意外死亡蹈矮,警方通過查閱死者的電腦和手機砰逻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進店門鸣驱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來泛鸟,“玉大人,你說我怎么就攤上這事踊东”崩模” “怎么了?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵闸翅,是天一觀的道長再芋。 經常有香客問我,道長坚冀,這世上最難降的妖魔是什么济赎? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮记某,結果婚禮上司训,老公的妹妹穿的比我還像新娘。我一直安慰自己液南,他們只是感情好壳猜,可當我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著滑凉,像睡著了一般统扳。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上畅姊,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天咒钟,我揣著相機與錄音,去河邊找鬼若未。 笑死朱嘴,一個胖子當著我的面吹牛,可吹牛的內容都是我干的陨瘩。 我是一名探鬼主播腕够,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼舌劳!你這毒婦竟也來了帚湘?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤甚淡,失蹤者是張志新(化名)和其女友劉穎大诸,沒想到半個月后捅厂,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡资柔,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年焙贷,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片贿堰。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡辙芍,死狀恐怖,靈堂內的尸體忽然破棺而出羹与,到底是詐尸還是另有隱情故硅,我是刑警寧澤,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布纵搁,位于F島的核電站吃衅,受9級特大地震影響,放射性物質發(fā)生泄漏腾誉。R本人自食惡果不足惜徘层,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望利职。 院中可真熱鬧趣效,春花似錦、人聲如沸眼耀。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽哮伟。三九已至干花,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間楞黄,已是汗流浹背池凄。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留鬼廓,地道東北人肿仑。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像碎税,于是被迫代替她去往敵國和親尤慰。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,722評論 2 345

推薦閱讀更多精彩內容

  • 1雷蹂、禁止手機睡眠[UIApplication sharedApplication].idleTimerDisabl...
    DingGa閱讀 1,115評論 1 6
  • iOS開發(fā)系列--網絡開發(fā) 概覽 大部分應用程序都或多或少會牽扯到網絡開發(fā)伟端,例如說新浪微博、微信等匪煌,這些應用本身可...
    lichengjin閱讀 3,639評論 2 7
  • VLC的集成和使用 VLC介紹 VLC Media Player (VideoLAN) 為 Windows责蝠、Lin...
    Pocket閱讀 19,480評論 75 66
  • 在日常生活中霜医,我們常常向別人提出請求齿拂,但并非都能獲得他人的積極回應。在學習了觀察與感受之后肴敛,我們應該如何向他人提出...
    陳蕾FZ閱讀 842評論 0 50
  • 大年初四署海,溫度降下來了,街上行人很少值朋,坐在新華書店門口的毛澤東像下叹侄,困意一陣陣地來巩搏。街心廣場十字路口的廣播在重復播...
    九九鷗閱讀 114評論 0 1