增加换肤功能
This commit is contained in:
22
Pods/YYCategories/LICENSE
generated
Normal file
22
Pods/YYCategories/LICENSE
generated
Normal file
@@ -0,0 +1,22 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 ibireme <ibireme@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
145
Pods/YYCategories/README.md
generated
Executable file
145
Pods/YYCategories/README.md
generated
Executable file
@@ -0,0 +1,145 @@
|
||||
YYCategories
|
||||
==============
|
||||
|
||||
[](https://raw.githubusercontent.com/ibireme/YYCategories/master/LICENSE)
|
||||
[](https://github.com/Carthage/Carthage)
|
||||
[](http://cocoapods.org/?q=YYCategories)
|
||||
[](http://cocoapods.org/?q=YYCategories)
|
||||
[](https://www.apple.com/nl/ios/)
|
||||
[](https://travis-ci.org/ibireme/YYCategories)
|
||||
|
||||
A set of useful categories for Foundation and UIKit.<br/>
|
||||
(It's a component of [YYKit](https://github.com/ibireme/YYKit))
|
||||
|
||||
Documentation
|
||||
==============
|
||||
|
||||
You can build and install docset use `Docset` scheme in Xcode, `appledoc` need to be pre-installed.
|
||||
Or your can read the [Documentation](http://github.ibireme.com/doc/YYCategories/index.html) online.
|
||||
|
||||
|
||||
Installation
|
||||
==============
|
||||
|
||||
### CocoaPods
|
||||
|
||||
1. Add `pod 'YYCategories'` to your Podfile.
|
||||
2. Run `pod install` or `pod update`.
|
||||
3. Import \<YYCategories/YYCategories.h\>.
|
||||
|
||||
|
||||
### Carthage
|
||||
|
||||
1. Add `github "ibireme/YYCategories"` to your Cartfile.
|
||||
2. Run `carthage update --platform ios` and add the framework to your project.
|
||||
3. Import \<YYCategories/YYCategories.h\>.
|
||||
|
||||
|
||||
### Manually
|
||||
|
||||
1. Download all the files in the YYCategories subdirectory.
|
||||
2. Add the source files to your Xcode project.
|
||||
3. Add `-fno-objc-arc` compiler flag to `NSObject+YYAddForARC.m` and `NSThread+YYAdd.m`.
|
||||
4. Link with required frameworks:
|
||||
* UIKit
|
||||
* CoreGraphics
|
||||
* QuartzCore
|
||||
* Accelerate
|
||||
* ImageIO
|
||||
* CoreText
|
||||
* CoreFoundation
|
||||
* libz
|
||||
5. Import `YYCategories.h`.
|
||||
|
||||
|
||||
Documentation
|
||||
==============
|
||||
Full API documentation is available on [CocoaDocs](http://cocoadocs.org/docsets/YYCategories/).<br/>
|
||||
You can also install documentation locally using [appledoc](https://github.com/tomaz/appledoc).
|
||||
|
||||
|
||||
Requirements
|
||||
==============
|
||||
This library requires `iOS 6.0+` and `Xcode 7.0+`.
|
||||
|
||||
|
||||
Notice
|
||||
==============
|
||||
I want to use the APIs as if it was provided by system, so I don't add prefix in
|
||||
these categories. This may cause some potential problems(such as conflict with other libraries), so if you just need some pieces of code
|
||||
in this project, pick them out and don't import the whole library.
|
||||
|
||||
|
||||
License
|
||||
==============
|
||||
YYCategories is provided under the MIT license. See LICENSE file for details.
|
||||
|
||||
|
||||
|
||||
|
||||
<br/><br/>
|
||||
---
|
||||
中文介绍
|
||||
==============
|
||||
功能丰富的 Category 类型工具库。<br/>
|
||||
(该项目是 [YYKit](https://github.com/ibireme/YYKit) 组件之一)
|
||||
|
||||
文档
|
||||
==============
|
||||
|
||||
你可以用 `Docset` scheme 来生成文档 (需要预先安装 appledoc),或者[在线查看](http://github.ibireme.com/doc/YYCategories/index.html)。
|
||||
|
||||
|
||||
安装
|
||||
==============
|
||||
|
||||
### CocoaPods
|
||||
|
||||
1. 在 Podfile 中添加 `pod 'YYCategories'`。
|
||||
2. 执行 `pod install` 或 `pod update`。
|
||||
3. 导入 \<YYCategories/YYCategories.h\>。
|
||||
|
||||
|
||||
### Carthage
|
||||
|
||||
1. 在 Cartfile 中添加 `github "ibireme/YYCategories"`。
|
||||
2. 执行 `carthage update --platform ios` 并将生成的 framework 添加到你的工程。
|
||||
3. 导入 \<YYCategories/YYCategories.h\>。
|
||||
|
||||
|
||||
### 手动安装
|
||||
|
||||
1. 下载 YYCategories 文件夹内的所有内容。
|
||||
2. 将 YYCategories 内的源文件添加(拖放)到你的工程。
|
||||
3. 为 `NSObject+YYAddForARC.m` 和 `NSThread+YYAdd.m` 添加编译参数 `-fno-objc-arc`。
|
||||
4. 链接以下 frameworks:
|
||||
* UIKit
|
||||
* CoreGraphics
|
||||
* QuartzCore
|
||||
* Accelerate
|
||||
* ImageIO
|
||||
* CoreText
|
||||
* CoreFoundation
|
||||
* libz
|
||||
5. 导入 `YYCategories.h`。
|
||||
|
||||
|
||||
文档
|
||||
==============
|
||||
你可以在 [CocoaDocs](http://cocoadocs.org/docsets/YYCategories/) 查看在线 API 文档,也可以用 [appledoc](https://github.com/tomaz/appledoc) 本地生成文档。
|
||||
|
||||
系统要求
|
||||
==============
|
||||
该项目最低支持 `iOS 6.0` 和 `Xcode 7.0`。
|
||||
|
||||
|
||||
注意
|
||||
==============
|
||||
我希望调用 API 时,有着和调用系统自带 API 一样的体验,所以我并没有为 Category 方法添加前缀。我已经用工具扫描过这个项目中的 API,确保没有对系统 API 产生影响。我知道没有前缀的 Category 可能会带来麻烦(比如可能和其他某些类库产生冲突),所以如果你只需要其中少量代码,那最好将那段代码取出来,而不是导入整个库。
|
||||
|
||||
|
||||
许可证
|
||||
==============
|
||||
YYCategories 使用 MIT 许可证,详情见 LICENSE 文件。
|
||||
|
||||
|
||||
196
Pods/YYCategories/YYCategories/Foundation/NSArray+YYAdd.h
generated
Normal file
196
Pods/YYCategories/YYCategories/Foundation/NSArray+YYAdd.h
generated
Normal file
@@ -0,0 +1,196 @@
|
||||
//
|
||||
// NSArray+YYAdd.h
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 13/4/4.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
Provide some some common method for `NSArray`.
|
||||
*/
|
||||
@interface NSArray (YYAdd)
|
||||
|
||||
/**
|
||||
Creates and returns an array from a specified property list data.
|
||||
|
||||
@param plist A property list data whose root object is an array.
|
||||
@return A new array created from the plist data, or nil if an error occurs.
|
||||
*/
|
||||
+ (nullable NSArray *)arrayWithPlistData:(NSData *)plist;
|
||||
|
||||
/**
|
||||
Creates and returns an array from a specified property list xml string.
|
||||
|
||||
@param plist A property list xml string whose root object is an array.
|
||||
@return A new array created from the plist string, or nil if an error occurs.
|
||||
*/
|
||||
+ (nullable NSArray *)arrayWithPlistString:(NSString *)plist;
|
||||
|
||||
/**
|
||||
Serialize the array to a binary property list data.
|
||||
|
||||
@return A bplist data, or nil if an error occurs.
|
||||
*/
|
||||
- (nullable NSData *)plistData;
|
||||
|
||||
/**
|
||||
Serialize the array to a xml property list string.
|
||||
|
||||
@return A plist xml string, or nil if an error occurs.
|
||||
*/
|
||||
- (nullable NSString *)plistString;
|
||||
|
||||
/**
|
||||
Returns the object located at a random index.
|
||||
|
||||
@return The object in the array with a random index value.
|
||||
If the array is empty, returns nil.
|
||||
*/
|
||||
- (nullable id)randomObject;
|
||||
|
||||
/**
|
||||
Returns the object located at index, or return nil when out of bounds.
|
||||
It's similar to `objectAtIndex:`, but it never throw exception.
|
||||
|
||||
@param index The object located at index.
|
||||
*/
|
||||
- (nullable id)objectOrNilAtIndex:(NSUInteger)index;
|
||||
|
||||
/**
|
||||
Convert object to json string. return nil if an error occurs.
|
||||
NSString/NSNumber/NSDictionary/NSArray
|
||||
*/
|
||||
- (nullable NSString *)jsonStringEncoded;
|
||||
|
||||
/**
|
||||
Convert object to json string formatted. return nil if an error occurs.
|
||||
*/
|
||||
- (nullable NSString *)jsonPrettyStringEncoded;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
/**
|
||||
Provide some some common method for `NSMutableArray`.
|
||||
*/
|
||||
@interface NSMutableArray (YYAdd)
|
||||
|
||||
/**
|
||||
Creates and returns an array from a specified property list data.
|
||||
|
||||
@param plist A property list data whose root object is an array.
|
||||
@return A new array created from the plist data, or nil if an error occurs.
|
||||
*/
|
||||
+ (nullable NSMutableArray *)arrayWithPlistData:(NSData *)plist;
|
||||
|
||||
/**
|
||||
Creates and returns an array from a specified property list xml string.
|
||||
|
||||
@param plist A property list xml string whose root object is an array.
|
||||
@return A new array created from the plist string, or nil if an error occurs.
|
||||
*/
|
||||
+ (nullable NSMutableArray *)arrayWithPlistString:(NSString *)plist;
|
||||
|
||||
/**
|
||||
Removes the object with the lowest-valued index in the array.
|
||||
If the array is empty, this method has no effect.
|
||||
|
||||
@discussion Apple has implemented this method, but did not make it public.
|
||||
Override for safe.
|
||||
*/
|
||||
- (void)removeFirstObject;
|
||||
|
||||
/**
|
||||
Removes the object with the highest-valued index in the array.
|
||||
If the array is empty, this method has no effect.
|
||||
|
||||
@discussion Apple's implementation said it raises an NSRangeException if the
|
||||
array is empty, but in fact nothing will happen. Override for safe.
|
||||
*/
|
||||
- (void)removeLastObject;
|
||||
|
||||
/**
|
||||
Removes and returns the object with the lowest-valued index in the array.
|
||||
If the array is empty, it just returns nil.
|
||||
|
||||
@return The first object, or nil.
|
||||
*/
|
||||
- (nullable id)popFirstObject;
|
||||
|
||||
/**
|
||||
Removes and returns the object with the highest-valued index in the array.
|
||||
If the array is empty, it just returns nil.
|
||||
|
||||
@return The first object, or nil.
|
||||
*/
|
||||
- (nullable id)popLastObject;
|
||||
|
||||
/**
|
||||
Inserts a given object at the end of the array.
|
||||
|
||||
@param anObject The object to add to the end of the array's content.
|
||||
This value must not be nil. Raises an NSInvalidArgumentException if anObject is nil.
|
||||
*/
|
||||
- (void)appendObject:(id)anObject;
|
||||
|
||||
/**
|
||||
Inserts a given object at the beginning of the array.
|
||||
|
||||
@param anObject The object to add to the end of the array's content.
|
||||
This value must not be nil. Raises an NSInvalidArgumentException if anObject is nil.
|
||||
*/
|
||||
- (void)prependObject:(id)anObject;
|
||||
|
||||
/**
|
||||
Adds the objects contained in another given array to the end of the receiving
|
||||
array's content.
|
||||
|
||||
@param objects An array of objects to add to the end of the receiving array's
|
||||
content. If the objects is empty or nil, this method has no effect.
|
||||
*/
|
||||
- (void)appendObjects:(NSArray *)objects;
|
||||
|
||||
/**
|
||||
Adds the objects contained in another given array to the beginnin of the receiving
|
||||
array's content.
|
||||
|
||||
@param objects An array of objects to add to the beginning of the receiving array's
|
||||
content. If the objects is empty or nil, this method has no effect.
|
||||
*/
|
||||
- (void)prependObjects:(NSArray *)objects;
|
||||
|
||||
/**
|
||||
Adds the objects contained in another given array at the index of the receiving
|
||||
array's content.
|
||||
|
||||
@param objects An array of objects to add to the receiving array's
|
||||
content. If the objects is empty or nil, this method has no effect.
|
||||
|
||||
@param index The index in the array at which to insert objects. This value must
|
||||
not be greater than the count of elements in the array. Raises an
|
||||
NSRangeException if index is greater than the number of elements in the array.
|
||||
*/
|
||||
- (void)insertObjects:(NSArray *)objects atIndex:(NSUInteger)index;
|
||||
|
||||
/**
|
||||
Reverse the index of object in this array.
|
||||
Example: Before @[ @1, @2, @3 ], After @[ @3, @2, @1 ].
|
||||
*/
|
||||
- (void)reverse;
|
||||
|
||||
/**
|
||||
Sort the object in this array randomly.
|
||||
*/
|
||||
- (void)shuffle;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
172
Pods/YYCategories/YYCategories/Foundation/NSArray+YYAdd.m
generated
Normal file
172
Pods/YYCategories/YYCategories/Foundation/NSArray+YYAdd.m
generated
Normal file
@@ -0,0 +1,172 @@
|
||||
//
|
||||
// NSArray+YYAdd.m
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 13/4/4.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import "NSArray+YYAdd.h"
|
||||
#import "YYCategoriesMacro.h"
|
||||
#import "NSData+YYAdd.h"
|
||||
|
||||
YYSYNTH_DUMMY_CLASS(NSArray_YYAdd)
|
||||
|
||||
|
||||
@implementation NSArray (YYAdd)
|
||||
|
||||
+ (NSArray *)arrayWithPlistData:(NSData *)plist {
|
||||
if (!plist) return nil;
|
||||
NSArray *array = [NSPropertyListSerialization propertyListWithData:plist options:NSPropertyListImmutable format:NULL error:NULL];
|
||||
if ([array isKindOfClass:[NSArray class]]) return array;
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (NSArray *)arrayWithPlistString:(NSString *)plist {
|
||||
if (!plist) return nil;
|
||||
NSData* data = [plist dataUsingEncoding:NSUTF8StringEncoding];
|
||||
return [self arrayWithPlistData:data];
|
||||
}
|
||||
|
||||
- (NSData *)plistData {
|
||||
return [NSPropertyListSerialization dataWithPropertyList:self format:NSPropertyListBinaryFormat_v1_0 options:kNilOptions error:NULL];
|
||||
}
|
||||
|
||||
- (NSString *)plistString {
|
||||
NSData *xmlData = [NSPropertyListSerialization dataWithPropertyList:self format:NSPropertyListXMLFormat_v1_0 options:kNilOptions error:NULL];
|
||||
if (xmlData) return xmlData.utf8String;
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (id)randomObject {
|
||||
if (self.count) {
|
||||
return self[arc4random_uniform((u_int32_t)self.count)];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (id)objectOrNilAtIndex:(NSUInteger)index {
|
||||
return index < self.count ? self[index] : nil;
|
||||
}
|
||||
|
||||
- (NSString *)jsonStringEncoded {
|
||||
if ([NSJSONSerialization isValidJSONObject:self]) {
|
||||
NSError *error;
|
||||
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:self options:0 error:&error];
|
||||
NSString *json = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
|
||||
return json;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSString *)jsonPrettyStringEncoded {
|
||||
if ([NSJSONSerialization isValidJSONObject:self]) {
|
||||
NSError *error;
|
||||
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:self options:NSJSONWritingPrettyPrinted error:&error];
|
||||
NSString *json = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
|
||||
return json;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
@implementation NSMutableArray (YYAdd)
|
||||
|
||||
+ (NSMutableArray *)arrayWithPlistData:(NSData *)plist {
|
||||
if (!plist) return nil;
|
||||
NSMutableArray *array = [NSPropertyListSerialization propertyListWithData:plist options:NSPropertyListMutableContainersAndLeaves format:NULL error:NULL];
|
||||
if ([array isKindOfClass:[NSMutableArray class]]) return array;
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (NSMutableArray *)arrayWithPlistString:(NSString *)plist {
|
||||
if (!plist) return nil;
|
||||
NSData* data = [plist dataUsingEncoding:NSUTF8StringEncoding];
|
||||
return [self arrayWithPlistData:data];
|
||||
}
|
||||
|
||||
- (void)removeFirstObject {
|
||||
if (self.count) {
|
||||
[self removeObjectAtIndex:0];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation"
|
||||
- (void)removeLastObject {
|
||||
if (self.count) {
|
||||
[self removeObjectAtIndex:self.count - 1];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
|
||||
- (id)popFirstObject {
|
||||
id obj = nil;
|
||||
if (self.count) {
|
||||
obj = self.firstObject;
|
||||
[self removeFirstObject];
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
- (id)popLastObject {
|
||||
id obj = nil;
|
||||
if (self.count) {
|
||||
obj = self.lastObject;
|
||||
[self removeLastObject];
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
- (void)appendObject:(id)anObject {
|
||||
[self addObject:anObject];
|
||||
}
|
||||
|
||||
- (void)prependObject:(id)anObject {
|
||||
[self insertObject:anObject atIndex:0];
|
||||
}
|
||||
|
||||
- (void)appendObjects:(NSArray *)objects {
|
||||
if (!objects) return;
|
||||
[self addObjectsFromArray:objects];
|
||||
}
|
||||
|
||||
- (void)prependObjects:(NSArray *)objects {
|
||||
if (!objects) return;
|
||||
NSUInteger i = 0;
|
||||
for (id obj in objects) {
|
||||
[self insertObject:obj atIndex:i++];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)insertObjects:(NSArray *)objects atIndex:(NSUInteger)index {
|
||||
NSUInteger i = index;
|
||||
for (id obj in objects) {
|
||||
[self insertObject:obj atIndex:i++];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)reverse {
|
||||
NSUInteger count = self.count;
|
||||
int mid = floor(count / 2.0);
|
||||
for (NSUInteger i = 0; i < mid; i++) {
|
||||
[self exchangeObjectAtIndex:i withObjectAtIndex:(count - (i + 1))];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)shuffle {
|
||||
for (NSUInteger i = self.count; i > 1; i--) {
|
||||
[self exchangeObjectAtIndex:(i - 1)
|
||||
withObjectAtIndex:arc4random_uniform((u_int32_t)i)];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
92
Pods/YYCategories/YYCategories/Foundation/NSBundle+YYAdd.h
generated
Normal file
92
Pods/YYCategories/YYCategories/Foundation/NSBundle+YYAdd.h
generated
Normal file
@@ -0,0 +1,92 @@
|
||||
//
|
||||
// NSBundle+YYAdd.h
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 14/10/20.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
Provides extensions for `NSBundle` to get resource by @2x or @3x...
|
||||
|
||||
Example: ico.png, ico@2x.png, ico@3x.png. Call scaledResource:@"ico" ofType:@"png"
|
||||
on iPhone6 will return "ico@2x.png"'s path.
|
||||
*/
|
||||
@interface NSBundle (YYAdd)
|
||||
|
||||
/**
|
||||
An array of NSNumber objects, shows the best order for path scale search.
|
||||
e.g. iPhone3GS:@[@1,@2,@3] iPhone5:@[@2,@3,@1] iPhone6 Plus:@[@3,@2,@1]
|
||||
*/
|
||||
+ (NSArray<NSNumber *> *)preferredScales;
|
||||
|
||||
/**
|
||||
Returns the full pathname for the resource file identified by the specified
|
||||
name and extension and residing in a given bundle directory. It first search
|
||||
the file with current screen's scale (such as @2x), then search from higher
|
||||
scale to lower scale.
|
||||
|
||||
@param name The name of a resource file contained in the directory
|
||||
specified by bundlePath.
|
||||
|
||||
@param ext If extension is an empty string or nil, the extension is
|
||||
assumed not to exist and the file is the first file encountered that exactly matches name.
|
||||
|
||||
@param bundlePath The path of a top-level bundle directory. This must be a
|
||||
valid path. For example, to specify the bundle directory for a Mac app, you
|
||||
might specify the path /Applications/MyApp.app.
|
||||
|
||||
@return The full pathname for the resource file or nil if the file could not be
|
||||
located. This method also returns nil if the bundle specified by the bundlePath
|
||||
parameter does not exist or is not a readable directory.
|
||||
*/
|
||||
+ (nullable NSString *)pathForScaledResource:(NSString *)name
|
||||
ofType:(nullable nullable NSString *)ext
|
||||
inDirectory:(NSString *)bundlePath;
|
||||
|
||||
/**
|
||||
Returns the full pathname for the resource identified by the specified name and
|
||||
file extension. It first search the file with current screen's scale (such as @2x),
|
||||
then search from higher scale to lower scale.
|
||||
|
||||
@param name The name of the resource file. If name is an empty string or
|
||||
nil, returns the first file encountered of the supplied type.
|
||||
|
||||
@param ext If extension is an empty string or nil, the extension is
|
||||
assumed not to exist and the file is the first file encountered that exactly matches name.
|
||||
|
||||
|
||||
@return The full pathname for the resource file or nil if the file could not be located.
|
||||
*/
|
||||
- (nullable NSString *)pathForScaledResource:(NSString *)name ofType:(nullable NSString *)ext;
|
||||
|
||||
/**
|
||||
Returns the full pathname for the resource identified by the specified name and
|
||||
file extension and located in the specified bundle subdirectory. It first search
|
||||
the file with current screen's scale (such as @2x), then search from higher
|
||||
scale to lower scale.
|
||||
|
||||
@param name The name of the resource file.
|
||||
|
||||
@param ext If extension is an empty string or nil, all the files in
|
||||
subpath and its subdirectories are returned. If an extension is provided the
|
||||
subdirectories are not searched.
|
||||
|
||||
@param subpath The name of the bundle subdirectory. Can be nil.
|
||||
|
||||
@return The full pathname for the resource file or nil if the file could not be located.
|
||||
*/
|
||||
- (nullable NSString *)pathForScaledResource:(NSString *)name
|
||||
ofType:(nullable NSString *)ext
|
||||
inDirectory:(nullable NSString *)subpath;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
87
Pods/YYCategories/YYCategories/Foundation/NSBundle+YYAdd.m
generated
Normal file
87
Pods/YYCategories/YYCategories/Foundation/NSBundle+YYAdd.m
generated
Normal file
@@ -0,0 +1,87 @@
|
||||
//
|
||||
// NSBundle+YYAdd.m
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 14/10/20.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import "NSBundle+YYAdd.h"
|
||||
#import "NSString+YYAdd.h"
|
||||
#import "YYCategoriesMacro.h"
|
||||
|
||||
YYSYNTH_DUMMY_CLASS(NSBundle_YYAdd)
|
||||
|
||||
@implementation NSBundle (YYAdd)
|
||||
|
||||
+ (NSArray *)preferredScales {
|
||||
static NSArray *scales;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
CGFloat screenScale = [UIScreen mainScreen].scale;
|
||||
if (screenScale <= 1) {
|
||||
scales = @[@1,@2,@3];
|
||||
} else if (screenScale <= 2) {
|
||||
scales = @[@2,@3,@1];
|
||||
} else {
|
||||
scales = @[@3,@2,@1];
|
||||
}
|
||||
});
|
||||
return scales;
|
||||
}
|
||||
|
||||
+ (NSString *)pathForScaledResource:(NSString *)name ofType:(NSString *)ext inDirectory:(NSString *)bundlePath {
|
||||
if (name.length == 0) return nil;
|
||||
if ([name hasSuffix:@"/"]) return [self pathForResource:name ofType:ext inDirectory:bundlePath];
|
||||
|
||||
NSString *path = nil;
|
||||
NSArray *scales = [self preferredScales];
|
||||
for (int s = 0; s < scales.count; s++) {
|
||||
CGFloat scale = ((NSNumber *)scales[s]).floatValue;
|
||||
NSString *scaledName = ext.length ? [name stringByAppendingNameScale:scale]
|
||||
: [name stringByAppendingPathScale:scale];
|
||||
path = [self pathForResource:scaledName ofType:ext inDirectory:bundlePath];
|
||||
if (path) break;
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
- (NSString *)pathForScaledResource:(NSString *)name ofType:(NSString *)ext {
|
||||
if (name.length == 0) return nil;
|
||||
if ([name hasSuffix:@"/"]) return [self pathForResource:name ofType:ext];
|
||||
|
||||
NSString *path = nil;
|
||||
NSArray *scales = [NSBundle preferredScales];
|
||||
for (int s = 0; s < scales.count; s++) {
|
||||
CGFloat scale = ((NSNumber *)scales[s]).floatValue;
|
||||
NSString *scaledName = ext.length ? [name stringByAppendingNameScale:scale]
|
||||
: [name stringByAppendingPathScale:scale];
|
||||
path = [self pathForResource:scaledName ofType:ext];
|
||||
if (path) break;
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
- (NSString *)pathForScaledResource:(NSString *)name ofType:(NSString *)ext inDirectory:(NSString *)subpath {
|
||||
if (name.length == 0) return nil;
|
||||
if ([name hasSuffix:@"/"]) return [self pathForResource:name ofType:ext];
|
||||
|
||||
NSString *path = nil;
|
||||
NSArray *scales = [NSBundle preferredScales];
|
||||
for (int s = 0; s < scales.count; s++) {
|
||||
CGFloat scale = ((NSNumber *)scales[s]).floatValue;
|
||||
NSString *scaledName = ext.length ? [name stringByAppendingNameScale:scale]
|
||||
: [name stringByAppendingPathScale:scale];
|
||||
path = [self pathForResource:scaledName ofType:ext inDirectory:subpath];
|
||||
if (path) break;
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
@end
|
||||
310
Pods/YYCategories/YYCategories/Foundation/NSData+YYAdd.h
generated
Normal file
310
Pods/YYCategories/YYCategories/Foundation/NSData+YYAdd.h
generated
Normal file
@@ -0,0 +1,310 @@
|
||||
//
|
||||
// NSData+YYAdd.h
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 13/4/4.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
Provide hash, encrypt, encode and some common method for `NSData`.
|
||||
*/
|
||||
@interface NSData (YYAdd)
|
||||
|
||||
#pragma mark - Hash
|
||||
///=============================================================================
|
||||
/// @name Hash
|
||||
///=============================================================================
|
||||
|
||||
/**
|
||||
Returns a lowercase NSString for md2 hash.
|
||||
*/
|
||||
- (NSString *)md2String;
|
||||
|
||||
/**
|
||||
Returns an NSData for md2 hash.
|
||||
*/
|
||||
- (NSData *)md2Data;
|
||||
|
||||
/**
|
||||
Returns a lowercase NSString for md4 hash.
|
||||
*/
|
||||
- (NSString *)md4String;
|
||||
|
||||
/**
|
||||
Returns an NSData for md4 hash.
|
||||
*/
|
||||
- (NSData *)md4Data;
|
||||
|
||||
/**
|
||||
Returns a lowercase NSString for md5 hash.
|
||||
*/
|
||||
- (NSString *)md5String;
|
||||
|
||||
/**
|
||||
Returns an NSData for md5 hash.
|
||||
*/
|
||||
- (NSData *)md5Data;
|
||||
|
||||
/**
|
||||
Returns a lowercase NSString for sha1 hash.
|
||||
*/
|
||||
- (NSString *)sha1String;
|
||||
|
||||
/**
|
||||
Returns an NSData for sha1 hash.
|
||||
*/
|
||||
- (NSData *)sha1Data;
|
||||
|
||||
/**
|
||||
Returns a lowercase NSString for sha224 hash.
|
||||
*/
|
||||
- (NSString *)sha224String;
|
||||
|
||||
/**
|
||||
Returns an NSData for sha224 hash.
|
||||
*/
|
||||
- (NSData *)sha224Data;
|
||||
|
||||
/**
|
||||
Returns a lowercase NSString for sha256 hash.
|
||||
*/
|
||||
- (NSString *)sha256String;
|
||||
|
||||
/**
|
||||
Returns an NSData for sha256 hash.
|
||||
*/
|
||||
- (NSData *)sha256Data;
|
||||
|
||||
/**
|
||||
Returns a lowercase NSString for sha384 hash.
|
||||
*/
|
||||
- (NSString *)sha384String;
|
||||
|
||||
/**
|
||||
Returns an NSData for sha384 hash.
|
||||
*/
|
||||
- (NSData *)sha384Data;
|
||||
|
||||
/**
|
||||
Returns a lowercase NSString for sha512 hash.
|
||||
*/
|
||||
- (NSString *)sha512String;
|
||||
|
||||
/**
|
||||
Returns an NSData for sha512 hash.
|
||||
*/
|
||||
- (NSData *)sha512Data;
|
||||
|
||||
/**
|
||||
Returns a lowercase NSString for hmac using algorithm md5 with key.
|
||||
@param key The hmac key.
|
||||
*/
|
||||
- (NSString *)hmacMD5StringWithKey:(NSString *)key;
|
||||
|
||||
/**
|
||||
Returns an NSData for hmac using algorithm md5 with key.
|
||||
@param key The hmac key.
|
||||
*/
|
||||
- (NSData *)hmacMD5DataWithKey:(NSData *)key;
|
||||
|
||||
/**
|
||||
Returns a lowercase NSString for hmac using algorithm sha1 with key.
|
||||
@param key The hmac key.
|
||||
*/
|
||||
- (NSString *)hmacSHA1StringWithKey:(NSString *)key;
|
||||
|
||||
/**
|
||||
Returns an NSData for hmac using algorithm sha1 with key.
|
||||
@param key The hmac key.
|
||||
*/
|
||||
- (NSData *)hmacSHA1DataWithKey:(NSData *)key;
|
||||
|
||||
/**
|
||||
Returns a lowercase NSString for hmac using algorithm sha224 with key.
|
||||
@param key The hmac key.
|
||||
*/
|
||||
- (NSString *)hmacSHA224StringWithKey:(NSString *)key;
|
||||
|
||||
/**
|
||||
Returns an NSData for hmac using algorithm sha224 with key.
|
||||
@param key The hmac key.
|
||||
*/
|
||||
- (NSData *)hmacSHA224DataWithKey:(NSData *)key;
|
||||
|
||||
/**
|
||||
Returns a lowercase NSString for hmac using algorithm sha256 with key.
|
||||
@param key The hmac key.
|
||||
*/
|
||||
- (NSString *)hmacSHA256StringWithKey:(NSString *)key;
|
||||
|
||||
/**
|
||||
Returns an NSData for hmac using algorithm sha256 with key.
|
||||
@param key The hmac key.
|
||||
*/
|
||||
- (NSData *)hmacSHA256DataWithKey:(NSData *)key;
|
||||
|
||||
/**
|
||||
Returns a lowercase NSString for hmac using algorithm sha384 with key.
|
||||
@param key The hmac key.
|
||||
*/
|
||||
- (NSString *)hmacSHA384StringWithKey:(NSString *)key;
|
||||
|
||||
/**
|
||||
Returns an NSData for hmac using algorithm sha384 with key.
|
||||
@param key The hmac key.
|
||||
*/
|
||||
- (NSData *)hmacSHA384DataWithKey:(NSData *)key;
|
||||
|
||||
/**
|
||||
Returns a lowercase NSString for hmac using algorithm sha512 with key.
|
||||
@param key The hmac key.
|
||||
*/
|
||||
- (NSString *)hmacSHA512StringWithKey:(NSString *)key;
|
||||
|
||||
/**
|
||||
Returns an NSData for hmac using algorithm sha512 with key.
|
||||
@param key The hmac key.
|
||||
*/
|
||||
- (NSData *)hmacSHA512DataWithKey:(NSData *)key;
|
||||
|
||||
/**
|
||||
Returns a lowercase NSString for crc32 hash.
|
||||
*/
|
||||
- (NSString *)crc32String;
|
||||
|
||||
/**
|
||||
Returns crc32 hash.
|
||||
*/
|
||||
- (uint32_t)crc32;
|
||||
|
||||
|
||||
#pragma mark - Encrypt and Decrypt
|
||||
///=============================================================================
|
||||
/// @name Encrypt and Decrypt
|
||||
///=============================================================================
|
||||
|
||||
/**
|
||||
Returns an encrypted NSData using AES.
|
||||
|
||||
@param key A key length of 16, 24 or 32 (128, 192 or 256bits).
|
||||
|
||||
@param iv An initialization vector length of 16(128bits).
|
||||
Pass nil when you don't want to use iv.
|
||||
|
||||
@return An NSData encrypted, or nil if an error occurs.
|
||||
*/
|
||||
- (nullable NSData *)aes256EncryptWithKey:(NSData *)key iv:(nullable NSData *)iv;
|
||||
|
||||
/**
|
||||
Returns an decrypted NSData using AES.
|
||||
|
||||
@param key A key length of 16, 24 or 32 (128, 192 or 256bits).
|
||||
|
||||
@param iv An initialization vector length of 16(128bits).
|
||||
Pass nil when you don't want to use iv.
|
||||
|
||||
@return An NSData decrypted, or nil if an error occurs.
|
||||
*/
|
||||
- (nullable NSData *)aes256DecryptWithkey:(NSData *)key iv:(nullable NSData *)iv;
|
||||
|
||||
|
||||
#pragma mark - Encode and decode
|
||||
///=============================================================================
|
||||
/// @name Encode and decode
|
||||
///=============================================================================
|
||||
|
||||
/**
|
||||
Returns string decoded in UTF8.
|
||||
*/
|
||||
- (nullable NSString *)utf8String;
|
||||
|
||||
/**
|
||||
Returns a uppercase NSString in HEX.
|
||||
*/
|
||||
- (nullable NSString *)hexString;
|
||||
|
||||
/**
|
||||
Returns an NSData from hex string.
|
||||
|
||||
@param hexString The hex string which is case insensitive.
|
||||
|
||||
@return a new NSData, or nil if an error occurs.
|
||||
*/
|
||||
+ (nullable NSData *)dataWithHexString:(NSString *)hexString;
|
||||
|
||||
/**
|
||||
Returns an NSString for base64 encoded.
|
||||
*/
|
||||
- (nullable NSString *)base64EncodedString;
|
||||
|
||||
/**
|
||||
Returns an NSData from base64 encoded string.
|
||||
|
||||
@warning This method has been implemented in iOS7.
|
||||
|
||||
@param base64EncodedString The encoded string.
|
||||
*/
|
||||
+ (nullable NSData *)dataWithBase64EncodedString:(NSString *)base64EncodedString;
|
||||
|
||||
/**
|
||||
Returns an NSDictionary or NSArray for decoded self.
|
||||
Returns nil if an error occurs.
|
||||
*/
|
||||
- (nullable id)jsonValueDecoded;
|
||||
|
||||
|
||||
#pragma mark - Inflate and deflate
|
||||
///=============================================================================
|
||||
/// @name Inflate and deflate
|
||||
///=============================================================================
|
||||
|
||||
/**
|
||||
Decompress data from gzip data.
|
||||
@return Inflated data.
|
||||
*/
|
||||
- (nullable NSData *)gzipInflate;
|
||||
|
||||
/**
|
||||
Comperss data to gzip in default compresssion level.
|
||||
@return Deflated data.
|
||||
*/
|
||||
- (nullable NSData *)gzipDeflate;
|
||||
|
||||
/**
|
||||
Decompress data from zlib-compressed data.
|
||||
@return Inflated data.
|
||||
*/
|
||||
- (nullable NSData *)zlibInflate;
|
||||
|
||||
/**
|
||||
Comperss data to zlib-compressed in default compresssion level.
|
||||
@return Deflated data.
|
||||
*/
|
||||
- (nullable NSData *)zlibDeflate;
|
||||
|
||||
|
||||
#pragma mark - Others
|
||||
///=============================================================================
|
||||
/// @name Others
|
||||
///=============================================================================
|
||||
|
||||
/**
|
||||
Create data from the file in main bundle (similar to [UIImage imageNamed:]).
|
||||
|
||||
@param name The file name (in main bundle).
|
||||
|
||||
@return A new data create from the file.
|
||||
*/
|
||||
+ (nullable NSData *)dataNamed:(NSString *)name;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
642
Pods/YYCategories/YYCategories/Foundation/NSData+YYAdd.m
generated
Normal file
642
Pods/YYCategories/YYCategories/Foundation/NSData+YYAdd.m
generated
Normal file
@@ -0,0 +1,642 @@
|
||||
//
|
||||
// NSData+YYAdd.m
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 13/4/4.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import "NSData+YYAdd.h"
|
||||
#import "YYCategoriesMacro.h"
|
||||
#include <CommonCrypto/CommonCrypto.h>
|
||||
#include <zlib.h>
|
||||
|
||||
YYSYNTH_DUMMY_CLASS(NSData_YYAdd)
|
||||
|
||||
|
||||
@implementation NSData (YYAdd)
|
||||
|
||||
- (NSString *)md2String {
|
||||
unsigned char result[CC_MD2_DIGEST_LENGTH];
|
||||
CC_MD2(self.bytes, (CC_LONG)self.length, result);
|
||||
return [NSString stringWithFormat:
|
||||
@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
|
||||
result[0], result[1], result[2], result[3],
|
||||
result[4], result[5], result[6], result[7],
|
||||
result[8], result[9], result[10], result[11],
|
||||
result[12], result[13], result[14], result[15]
|
||||
];
|
||||
}
|
||||
|
||||
- (NSData *)md2Data {
|
||||
unsigned char result[CC_MD2_DIGEST_LENGTH];
|
||||
CC_MD2(self.bytes, (CC_LONG)self.length, result);
|
||||
return [NSData dataWithBytes:result length:CC_MD2_DIGEST_LENGTH];
|
||||
}
|
||||
|
||||
- (NSString *)md4String {
|
||||
unsigned char result[CC_MD4_DIGEST_LENGTH];
|
||||
CC_MD4(self.bytes, (CC_LONG)self.length, result);
|
||||
return [NSString stringWithFormat:
|
||||
@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
|
||||
result[0], result[1], result[2], result[3],
|
||||
result[4], result[5], result[6], result[7],
|
||||
result[8], result[9], result[10], result[11],
|
||||
result[12], result[13], result[14], result[15]
|
||||
];
|
||||
}
|
||||
|
||||
- (NSData *)md4Data {
|
||||
unsigned char result[CC_MD4_DIGEST_LENGTH];
|
||||
CC_MD4(self.bytes, (CC_LONG)self.length, result);
|
||||
return [NSData dataWithBytes:result length:CC_MD4_DIGEST_LENGTH];
|
||||
}
|
||||
|
||||
- (NSString *)md5String {
|
||||
unsigned char result[CC_MD5_DIGEST_LENGTH];
|
||||
CC_MD5(self.bytes, (CC_LONG)self.length, result);
|
||||
return [NSString stringWithFormat:
|
||||
@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
|
||||
result[0], result[1], result[2], result[3],
|
||||
result[4], result[5], result[6], result[7],
|
||||
result[8], result[9], result[10], result[11],
|
||||
result[12], result[13], result[14], result[15]
|
||||
];
|
||||
}
|
||||
|
||||
- (NSData *)md5Data {
|
||||
unsigned char result[CC_MD5_DIGEST_LENGTH];
|
||||
CC_MD5(self.bytes, (CC_LONG)self.length, result);
|
||||
return [NSData dataWithBytes:result length:CC_MD5_DIGEST_LENGTH];
|
||||
}
|
||||
|
||||
- (NSString *)sha1String {
|
||||
unsigned char result[CC_SHA1_DIGEST_LENGTH];
|
||||
CC_SHA1(self.bytes, (CC_LONG)self.length, result);
|
||||
NSMutableString *hash = [NSMutableString
|
||||
stringWithCapacity:CC_SHA1_DIGEST_LENGTH * 2];
|
||||
for (int i = 0; i < CC_SHA1_DIGEST_LENGTH; i++) {
|
||||
[hash appendFormat:@"%02x", result[i]];
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
- (NSData *)sha1Data {
|
||||
unsigned char result[CC_SHA1_DIGEST_LENGTH];
|
||||
CC_SHA1(self.bytes, (CC_LONG)self.length, result);
|
||||
return [NSData dataWithBytes:result length:CC_SHA1_DIGEST_LENGTH];
|
||||
}
|
||||
|
||||
- (NSString *)sha224String {
|
||||
unsigned char result[CC_SHA224_DIGEST_LENGTH];
|
||||
CC_SHA224(self.bytes, (CC_LONG)self.length, result);
|
||||
NSMutableString *hash = [NSMutableString
|
||||
stringWithCapacity:CC_SHA224_DIGEST_LENGTH * 2];
|
||||
for (int i = 0; i < CC_SHA224_DIGEST_LENGTH; i++) {
|
||||
[hash appendFormat:@"%02x", result[i]];
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
- (NSData *)sha224Data {
|
||||
unsigned char result[CC_SHA224_DIGEST_LENGTH];
|
||||
CC_SHA224(self.bytes, (CC_LONG)self.length, result);
|
||||
return [NSData dataWithBytes:result length:CC_SHA224_DIGEST_LENGTH];
|
||||
}
|
||||
|
||||
- (NSString *)sha256String {
|
||||
unsigned char result[CC_SHA256_DIGEST_LENGTH];
|
||||
CC_SHA256(self.bytes, (CC_LONG)self.length, result);
|
||||
NSMutableString *hash = [NSMutableString
|
||||
stringWithCapacity:CC_SHA256_DIGEST_LENGTH * 2];
|
||||
for (int i = 0; i < CC_SHA256_DIGEST_LENGTH; i++) {
|
||||
[hash appendFormat:@"%02x", result[i]];
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
- (NSData *)sha256Data {
|
||||
unsigned char result[CC_SHA256_DIGEST_LENGTH];
|
||||
CC_SHA256(self.bytes, (CC_LONG)self.length, result);
|
||||
return [NSData dataWithBytes:result length:CC_SHA256_DIGEST_LENGTH];
|
||||
}
|
||||
|
||||
- (NSString *)sha384String {
|
||||
unsigned char result[CC_SHA384_DIGEST_LENGTH];
|
||||
CC_SHA384(self.bytes, (CC_LONG)self.length, result);
|
||||
NSMutableString *hash = [NSMutableString
|
||||
stringWithCapacity:CC_SHA384_DIGEST_LENGTH * 2];
|
||||
for (int i = 0; i < CC_SHA384_DIGEST_LENGTH; i++) {
|
||||
[hash appendFormat:@"%02x", result[i]];
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
- (NSData *)sha384Data {
|
||||
unsigned char result[CC_SHA384_DIGEST_LENGTH];
|
||||
CC_SHA384(self.bytes, (CC_LONG)self.length, result);
|
||||
return [NSData dataWithBytes:result length:CC_SHA384_DIGEST_LENGTH];
|
||||
}
|
||||
|
||||
- (NSString *)sha512String {
|
||||
unsigned char result[CC_SHA512_DIGEST_LENGTH];
|
||||
CC_SHA512(self.bytes, (CC_LONG)self.length, result);
|
||||
NSMutableString *hash = [NSMutableString
|
||||
stringWithCapacity:CC_SHA512_DIGEST_LENGTH * 2];
|
||||
for (int i = 0; i < CC_SHA512_DIGEST_LENGTH; i++) {
|
||||
[hash appendFormat:@"%02x", result[i]];
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
- (NSData *)sha512Data {
|
||||
unsigned char result[CC_SHA512_DIGEST_LENGTH];
|
||||
CC_SHA512(self.bytes, (CC_LONG)self.length, result);
|
||||
return [NSData dataWithBytes:result length:CC_SHA512_DIGEST_LENGTH];
|
||||
}
|
||||
|
||||
- (NSString *)hmacStringUsingAlg:(CCHmacAlgorithm)alg withKey:(NSString *)key {
|
||||
size_t size;
|
||||
switch (alg) {
|
||||
case kCCHmacAlgMD5: size = CC_MD5_DIGEST_LENGTH; break;
|
||||
case kCCHmacAlgSHA1: size = CC_SHA1_DIGEST_LENGTH; break;
|
||||
case kCCHmacAlgSHA224: size = CC_SHA224_DIGEST_LENGTH; break;
|
||||
case kCCHmacAlgSHA256: size = CC_SHA256_DIGEST_LENGTH; break;
|
||||
case kCCHmacAlgSHA384: size = CC_SHA384_DIGEST_LENGTH; break;
|
||||
case kCCHmacAlgSHA512: size = CC_SHA512_DIGEST_LENGTH; break;
|
||||
default: return nil;
|
||||
}
|
||||
unsigned char result[size];
|
||||
const char *cKey = [key cStringUsingEncoding:NSUTF8StringEncoding];
|
||||
CCHmac(alg, cKey, strlen(cKey), self.bytes, self.length, result);
|
||||
NSMutableString *hash = [NSMutableString stringWithCapacity:size * 2];
|
||||
for (int i = 0; i < size; i++) {
|
||||
[hash appendFormat:@"%02x", result[i]];
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
- (NSData *)hmacDataUsingAlg:(CCHmacAlgorithm)alg withKey:(NSData *)key {
|
||||
size_t size;
|
||||
switch (alg) {
|
||||
case kCCHmacAlgMD5: size = CC_MD5_DIGEST_LENGTH; break;
|
||||
case kCCHmacAlgSHA1: size = CC_SHA1_DIGEST_LENGTH; break;
|
||||
case kCCHmacAlgSHA224: size = CC_SHA224_DIGEST_LENGTH; break;
|
||||
case kCCHmacAlgSHA256: size = CC_SHA256_DIGEST_LENGTH; break;
|
||||
case kCCHmacAlgSHA384: size = CC_SHA384_DIGEST_LENGTH; break;
|
||||
case kCCHmacAlgSHA512: size = CC_SHA512_DIGEST_LENGTH; break;
|
||||
default: return nil;
|
||||
}
|
||||
unsigned char result[size];
|
||||
CCHmac(alg, [key bytes], key.length, self.bytes, self.length, result);
|
||||
return [NSData dataWithBytes:result length:size];
|
||||
}
|
||||
|
||||
- (NSString *)hmacMD5StringWithKey:(NSString *)key {
|
||||
return [self hmacStringUsingAlg:kCCHmacAlgMD5 withKey:key];
|
||||
}
|
||||
|
||||
- (NSData *)hmacMD5DataWithKey:(NSData *)key {
|
||||
return [self hmacDataUsingAlg:kCCHmacAlgMD5 withKey:key];
|
||||
}
|
||||
|
||||
- (NSString *)hmacSHA1StringWithKey:(NSString *)key {
|
||||
return [self hmacStringUsingAlg:kCCHmacAlgSHA1 withKey:key];
|
||||
}
|
||||
|
||||
- (NSData *)hmacSHA1DataWithKey:(NSData *)key {
|
||||
return [self hmacDataUsingAlg:kCCHmacAlgSHA1 withKey:key];
|
||||
}
|
||||
|
||||
- (NSString *)hmacSHA224StringWithKey:(NSString *)key {
|
||||
return [self hmacStringUsingAlg:kCCHmacAlgSHA224 withKey:key];
|
||||
}
|
||||
|
||||
- (NSData *)hmacSHA224DataWithKey:(NSData *)key {
|
||||
return [self hmacDataUsingAlg:kCCHmacAlgSHA224 withKey:key];
|
||||
}
|
||||
|
||||
- (NSString *)hmacSHA256StringWithKey:(NSString *)key {
|
||||
return [self hmacStringUsingAlg:kCCHmacAlgSHA256 withKey:key];
|
||||
}
|
||||
|
||||
- (NSData *)hmacSHA256DataWithKey:(NSData *)key {
|
||||
return [self hmacDataUsingAlg:kCCHmacAlgSHA256 withKey:key];
|
||||
}
|
||||
|
||||
- (NSString *)hmacSHA384StringWithKey:(NSString *)key {
|
||||
return [self hmacStringUsingAlg:kCCHmacAlgSHA384 withKey:key];
|
||||
}
|
||||
|
||||
- (NSData *)hmacSHA384DataWithKey:(NSData *)key {
|
||||
return [self hmacDataUsingAlg:kCCHmacAlgSHA384 withKey:key];
|
||||
}
|
||||
|
||||
- (NSString *)hmacSHA512StringWithKey:(NSString *)key {
|
||||
return [self hmacStringUsingAlg:kCCHmacAlgSHA512 withKey:key];
|
||||
}
|
||||
|
||||
- (NSData *)hmacSHA512DataWithKey:(NSData *)key {
|
||||
return [self hmacDataUsingAlg:kCCHmacAlgSHA512 withKey:key];
|
||||
}
|
||||
|
||||
- (NSString *)crc32String {
|
||||
uLong result = crc32(0, self.bytes, (uInt)self.length);
|
||||
return [NSString stringWithFormat:@"%08x", (uint32_t)result];
|
||||
}
|
||||
|
||||
- (uint32_t)crc32 {
|
||||
uLong result = crc32(0, self.bytes, (uInt)self.length);
|
||||
return (uint32_t)result;
|
||||
}
|
||||
|
||||
- (NSData *)aes256EncryptWithKey:(NSData *)key iv:(NSData *)iv {
|
||||
if (key.length != 16 && key.length != 24 && key.length != 32) {
|
||||
return nil;
|
||||
}
|
||||
if (iv.length != 16 && iv.length != 0) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSData *result = nil;
|
||||
size_t bufferSize = self.length + kCCBlockSizeAES128;
|
||||
void *buffer = malloc(bufferSize);
|
||||
if (!buffer) return nil;
|
||||
size_t encryptedSize = 0;
|
||||
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
|
||||
kCCAlgorithmAES128,
|
||||
kCCOptionPKCS7Padding,
|
||||
key.bytes,
|
||||
key.length,
|
||||
iv.bytes,
|
||||
self.bytes,
|
||||
self.length,
|
||||
buffer,
|
||||
bufferSize,
|
||||
&encryptedSize);
|
||||
if (cryptStatus == kCCSuccess) {
|
||||
result = [[NSData alloc]initWithBytes:buffer length:encryptedSize];
|
||||
free(buffer);
|
||||
return result;
|
||||
} else {
|
||||
free(buffer);
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSData *)aes256DecryptWithkey:(NSData *)key iv:(NSData *)iv {
|
||||
if (key.length != 16 && key.length != 24 && key.length != 32) {
|
||||
return nil;
|
||||
}
|
||||
if (iv.length != 16 && iv.length != 0) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSData *result = nil;
|
||||
size_t bufferSize = self.length + kCCBlockSizeAES128;
|
||||
void *buffer = malloc(bufferSize);
|
||||
if (!buffer) return nil;
|
||||
size_t encryptedSize = 0;
|
||||
CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,
|
||||
kCCAlgorithmAES128,
|
||||
kCCOptionPKCS7Padding,
|
||||
key.bytes,
|
||||
key.length,
|
||||
iv.bytes,
|
||||
self.bytes,
|
||||
self.length,
|
||||
buffer,
|
||||
bufferSize,
|
||||
&encryptedSize);
|
||||
if (cryptStatus == kCCSuccess) {
|
||||
result = [[NSData alloc]initWithBytes:buffer length:encryptedSize];
|
||||
free(buffer);
|
||||
return result;
|
||||
} else {
|
||||
free(buffer);
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString *)utf8String {
|
||||
if (self.length > 0) {
|
||||
return [[NSString alloc] initWithData:self encoding:NSUTF8StringEncoding];
|
||||
}
|
||||
return @"";
|
||||
}
|
||||
|
||||
- (NSString *)hexString {
|
||||
NSUInteger length = self.length;
|
||||
NSMutableString *result = [NSMutableString stringWithCapacity:length * 2];
|
||||
const unsigned char *byte = self.bytes;
|
||||
for (int i = 0; i < length; i++, byte++) {
|
||||
[result appendFormat:@"%02X", *byte];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
+ (NSData *)dataWithHexString:(NSString *)hexStr {
|
||||
hexStr = [hexStr stringByReplacingOccurrencesOfString:@" " withString:@""];
|
||||
hexStr = [hexStr lowercaseString];
|
||||
NSUInteger len = hexStr.length;
|
||||
if (!len) return nil;
|
||||
unichar *buf = malloc(sizeof(unichar) * len);
|
||||
if (!buf) return nil;
|
||||
[hexStr getCharacters:buf range:NSMakeRange(0, len)];
|
||||
|
||||
NSMutableData *result = [NSMutableData data];
|
||||
unsigned char bytes;
|
||||
char str[3] = { '\0', '\0', '\0' };
|
||||
int i;
|
||||
for (i = 0; i < len / 2; i++) {
|
||||
str[0] = buf[i * 2];
|
||||
str[1] = buf[i * 2 + 1];
|
||||
bytes = strtol(str, NULL, 16);
|
||||
[result appendBytes:&bytes length:1];
|
||||
}
|
||||
free(buf);
|
||||
return result;
|
||||
}
|
||||
|
||||
static const char base64EncodingTable[64]
|
||||
= "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
static const short base64DecodingTable[256] = {
|
||||
-2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -1, -2, -1, -1, -2, -2,
|
||||
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
|
||||
-1, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, 62, -2, -2, -2, 63,
|
||||
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -2, -2, -2, -2, -2, -2,
|
||||
-2, 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, -2, -2, -2, -2, -2,
|
||||
-2, 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, -2, -2, -2, -2, -2,
|
||||
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
|
||||
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
|
||||
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
|
||||
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
|
||||
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
|
||||
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
|
||||
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
|
||||
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2
|
||||
};
|
||||
|
||||
- (NSString *)base64EncodedString {
|
||||
NSUInteger length = self.length;
|
||||
if (length == 0)
|
||||
return @"";
|
||||
|
||||
NSUInteger out_length = ((length + 2) / 3) * 4;
|
||||
uint8_t *output = malloc(((out_length + 2) / 3) * 4);
|
||||
if (output == NULL)
|
||||
return nil;
|
||||
|
||||
const char *input = self.bytes;
|
||||
NSInteger i, value;
|
||||
for (i = 0; i < length; i += 3) {
|
||||
value = 0;
|
||||
for (NSInteger j = i; j < i + 3; j++) {
|
||||
value <<= 8;
|
||||
if (j < length) {
|
||||
value |= (0xFF & input[j]);
|
||||
}
|
||||
}
|
||||
NSInteger index = (i / 3) * 4;
|
||||
output[index + 0] = base64EncodingTable[(value >> 18) & 0x3F];
|
||||
output[index + 1] = base64EncodingTable[(value >> 12) & 0x3F];
|
||||
output[index + 2] = ((i + 1) < length)
|
||||
? base64EncodingTable[(value >> 6) & 0x3F]
|
||||
: '=';
|
||||
output[index + 3] = ((i + 2) < length)
|
||||
? base64EncodingTable[(value >> 0) & 0x3F]
|
||||
: '=';
|
||||
}
|
||||
|
||||
NSString *base64 = [[NSString alloc] initWithBytes:output
|
||||
length:out_length
|
||||
encoding:NSASCIIStringEncoding];
|
||||
free(output);
|
||||
return base64;
|
||||
}
|
||||
|
||||
+ (NSData *)dataWithBase64EncodedString:(NSString *)base64EncodedString {
|
||||
NSInteger length = base64EncodedString.length;
|
||||
const char *string = [base64EncodedString cStringUsingEncoding:NSASCIIStringEncoding];
|
||||
if (string == NULL)
|
||||
return nil;
|
||||
|
||||
while (length > 0 && string[length - 1] == '=')
|
||||
length--;
|
||||
|
||||
NSInteger outputLength = length * 3 / 4;
|
||||
NSMutableData *data = [NSMutableData dataWithLength:outputLength];
|
||||
if (data == nil)
|
||||
return nil;
|
||||
if (length == 0)
|
||||
return data;
|
||||
|
||||
uint8_t *output = data.mutableBytes;
|
||||
NSInteger inputPoint = 0;
|
||||
NSInteger outputPoint = 0;
|
||||
while (inputPoint < length) {
|
||||
char i0 = string[inputPoint++];
|
||||
char i1 = string[inputPoint++];
|
||||
char i2 = inputPoint < length ? string[inputPoint++] : 'A';
|
||||
char i3 = inputPoint < length ? string[inputPoint++] : 'A';
|
||||
|
||||
output[outputPoint++] = (base64DecodingTable[i0] << 2)
|
||||
| (base64DecodingTable[i1] >> 4);
|
||||
if (outputPoint < outputLength) {
|
||||
output[outputPoint++] = ((base64DecodingTable[i1] & 0xf) << 4)
|
||||
| (base64DecodingTable[i2] >> 2);
|
||||
}
|
||||
if (outputPoint < outputLength) {
|
||||
output[outputPoint++] = ((base64DecodingTable[i2] & 0x3) << 6)
|
||||
| base64DecodingTable[i3];
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
- (id)jsonValueDecoded {
|
||||
NSError *error = nil;
|
||||
id value = [NSJSONSerialization JSONObjectWithData:self options:kNilOptions error:&error];
|
||||
if (error) {
|
||||
NSLog(@"jsonValueDecoded error:%@", error);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
- (NSData *)gzipInflate {
|
||||
if ([self length] == 0) return self;
|
||||
|
||||
unsigned full_length = (unsigned)[self length];
|
||||
unsigned half_length = (unsigned)[self length] / 2;
|
||||
|
||||
NSMutableData *decompressed = [NSMutableData
|
||||
dataWithLength:full_length + half_length];
|
||||
BOOL done = NO;
|
||||
int status;
|
||||
|
||||
z_stream strm;
|
||||
strm.next_in = (Bytef *)[self bytes];
|
||||
strm.avail_in = (unsigned)[self length];
|
||||
strm.total_out = 0;
|
||||
strm.zalloc = Z_NULL;
|
||||
strm.zfree = Z_NULL;
|
||||
|
||||
if (inflateInit2(&strm, (15 + 32)) != Z_OK) return nil;
|
||||
while (!done) {
|
||||
// Make sure we have enough room and reset the lengths.
|
||||
if (strm.total_out >= [decompressed length])
|
||||
[decompressed increaseLengthBy:half_length];
|
||||
strm.next_out = [decompressed mutableBytes] + strm.total_out;
|
||||
strm.avail_out = (uInt)([decompressed length] - strm.total_out);
|
||||
|
||||
// Inflate another chunk.
|
||||
status = inflate(&strm, Z_SYNC_FLUSH);
|
||||
if (status == Z_STREAM_END) done = YES;
|
||||
else if (status != Z_OK) break;
|
||||
}
|
||||
if (inflateEnd(&strm) != Z_OK) return nil;
|
||||
|
||||
// Set real length.
|
||||
if (done) {
|
||||
[decompressed setLength:strm.total_out];
|
||||
return [NSData dataWithData:decompressed];
|
||||
} else return nil;
|
||||
}
|
||||
|
||||
- (NSData *)gzipDeflate {
|
||||
if ([self length] == 0) return self;
|
||||
|
||||
z_stream strm;
|
||||
|
||||
strm.zalloc = Z_NULL;
|
||||
strm.zfree = Z_NULL;
|
||||
strm.opaque = Z_NULL;
|
||||
strm.total_out = 0;
|
||||
strm.next_in = (Bytef *)[self bytes];
|
||||
strm.avail_in = (uInt)[self length];
|
||||
|
||||
// Compresssion Levels:
|
||||
// Z_NO_COMPRESSION
|
||||
// Z_BEST_SPEED
|
||||
// Z_BEST_COMPRESSION
|
||||
// Z_DEFAULT_COMPRESSION
|
||||
|
||||
if (deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, (15 + 16),
|
||||
8, Z_DEFAULT_STRATEGY) != Z_OK)
|
||||
return nil;
|
||||
|
||||
// 16K chunks for expansion
|
||||
NSMutableData *compressed = [NSMutableData dataWithLength:16384];
|
||||
|
||||
do {
|
||||
if (strm.total_out >= [compressed length])
|
||||
[compressed increaseLengthBy:16384];
|
||||
|
||||
strm.next_out = [compressed mutableBytes] + strm.total_out;
|
||||
strm.avail_out = (uInt)([compressed length] - strm.total_out);
|
||||
|
||||
deflate(&strm, Z_FINISH);
|
||||
}
|
||||
while (strm.avail_out == 0);
|
||||
|
||||
deflateEnd(&strm);
|
||||
|
||||
[compressed setLength:strm.total_out];
|
||||
return [NSData dataWithData:compressed];
|
||||
}
|
||||
|
||||
- (NSData *)zlibInflate {
|
||||
if ([self length] == 0) return self;
|
||||
|
||||
NSUInteger full_length = [self length];
|
||||
NSUInteger half_length = [self length] / 2;
|
||||
|
||||
NSMutableData *decompressed = [NSMutableData
|
||||
dataWithLength:full_length + half_length];
|
||||
BOOL done = NO;
|
||||
int status;
|
||||
|
||||
z_stream strm;
|
||||
strm.next_in = (Bytef *)[self bytes];
|
||||
strm.avail_in = (uInt)full_length;
|
||||
strm.total_out = 0;
|
||||
strm.zalloc = Z_NULL;
|
||||
strm.zfree = Z_NULL;
|
||||
|
||||
if (inflateInit(&strm) != Z_OK) return nil;
|
||||
|
||||
while (!done) {
|
||||
// Make sure we have enough room and reset the lengths.
|
||||
if (strm.total_out >= [decompressed length])
|
||||
[decompressed increaseLengthBy:half_length];
|
||||
strm.next_out = [decompressed mutableBytes] + strm.total_out;
|
||||
strm.avail_out = (uInt)([decompressed length] - strm.total_out);
|
||||
|
||||
// Inflate another chunk.
|
||||
status = inflate(&strm, Z_SYNC_FLUSH);
|
||||
if (status == Z_STREAM_END) done = YES;
|
||||
else if (status != Z_OK) break;
|
||||
}
|
||||
if (inflateEnd(&strm) != Z_OK) return nil;
|
||||
|
||||
// Set real length.
|
||||
if (done) {
|
||||
[decompressed setLength:strm.total_out];
|
||||
return [NSData dataWithData:decompressed];
|
||||
} else return nil;
|
||||
}
|
||||
|
||||
- (NSData *)zlibDeflate {
|
||||
if ([self length] == 0) return self;
|
||||
|
||||
z_stream strm;
|
||||
|
||||
strm.zalloc = Z_NULL;
|
||||
strm.zfree = Z_NULL;
|
||||
strm.opaque = Z_NULL;
|
||||
strm.total_out = 0;
|
||||
strm.next_in = (Bytef *)[self bytes];
|
||||
strm.avail_in = (uInt)[self length];
|
||||
|
||||
// Compresssion Levels:
|
||||
// Z_NO_COMPRESSION
|
||||
// Z_BEST_SPEED
|
||||
// Z_BEST_COMPRESSION
|
||||
// Z_DEFAULT_COMPRESSION
|
||||
|
||||
if (deflateInit(&strm, Z_DEFAULT_COMPRESSION) != Z_OK) return nil;
|
||||
|
||||
// 16K chuncks for expansion
|
||||
NSMutableData *compressed = [NSMutableData dataWithLength:16384];
|
||||
|
||||
do {
|
||||
if (strm.total_out >= [compressed length])
|
||||
[compressed increaseLengthBy:16384];
|
||||
|
||||
strm.next_out = [compressed mutableBytes] + strm.total_out;
|
||||
strm.avail_out = (uInt)([compressed length] - strm.total_out);
|
||||
|
||||
deflate(&strm, Z_FINISH);
|
||||
}
|
||||
while (strm.avail_out == 0);
|
||||
|
||||
deflateEnd(&strm);
|
||||
|
||||
[compressed setLength:strm.total_out];
|
||||
return [NSData dataWithData:compressed];
|
||||
}
|
||||
|
||||
+ (NSData *)dataNamed:(NSString *)name {
|
||||
NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:@""];
|
||||
if (!path) return nil;
|
||||
NSData *data = [NSData dataWithContentsOfFile:path];
|
||||
return data;
|
||||
}
|
||||
|
||||
@end
|
||||
188
Pods/YYCategories/YYCategories/Foundation/NSDate+YYAdd.h
generated
Normal file
188
Pods/YYCategories/YYCategories/Foundation/NSDate+YYAdd.h
generated
Normal file
@@ -0,0 +1,188 @@
|
||||
//
|
||||
// NSDate+YYAdd.h
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 13/4/11.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
Provides extensions for `NSDate`.
|
||||
*/
|
||||
@interface NSDate (YYAdd)
|
||||
|
||||
#pragma mark - Component Properties
|
||||
///=============================================================================
|
||||
/// @name Component Properties
|
||||
///=============================================================================
|
||||
|
||||
@property (nonatomic, readonly) NSInteger year; ///< Year component
|
||||
@property (nonatomic, readonly) NSInteger month; ///< Month component (1~12)
|
||||
@property (nonatomic, readonly) NSInteger day; ///< Day component (1~31)
|
||||
@property (nonatomic, readonly) NSInteger hour; ///< Hour component (0~23)
|
||||
@property (nonatomic, readonly) NSInteger minute; ///< Minute component (0~59)
|
||||
@property (nonatomic, readonly) NSInteger second; ///< Second component (0~59)
|
||||
@property (nonatomic, readonly) NSInteger nanosecond; ///< Nanosecond component
|
||||
@property (nonatomic, readonly) NSInteger weekday; ///< Weekday component (1~7, first day is based on user setting)
|
||||
@property (nonatomic, readonly) NSInteger weekdayOrdinal; ///< WeekdayOrdinal component
|
||||
@property (nonatomic, readonly) NSInteger weekOfMonth; ///< WeekOfMonth component (1~5)
|
||||
@property (nonatomic, readonly) NSInteger weekOfYear; ///< WeekOfYear component (1~53)
|
||||
@property (nonatomic, readonly) NSInteger yearForWeekOfYear; ///< YearForWeekOfYear component
|
||||
@property (nonatomic, readonly) NSInteger quarter; ///< Quarter component
|
||||
@property (nonatomic, readonly) BOOL isLeapMonth; ///< Weather the month is leap month
|
||||
@property (nonatomic, readonly) BOOL isLeapYear; ///< Weather the year is leap year
|
||||
@property (nonatomic, readonly) BOOL isToday; ///< Weather date is today (based on current locale)
|
||||
@property (nonatomic, readonly) BOOL isYesterday; ///< Weather date is yesterday (based on current locale)
|
||||
|
||||
#pragma mark - Date modify
|
||||
///=============================================================================
|
||||
/// @name Date modify
|
||||
///=============================================================================
|
||||
|
||||
/**
|
||||
Returns a date representing the receiver date shifted later by the provided number of years.
|
||||
|
||||
@param years Number of years to add.
|
||||
@return Date modified by the number of desired years.
|
||||
*/
|
||||
- (nullable NSDate *)dateByAddingYears:(NSInteger)years;
|
||||
|
||||
/**
|
||||
Returns a date representing the receiver date shifted later by the provided number of months.
|
||||
|
||||
@param months Number of months to add.
|
||||
@return Date modified by the number of desired months.
|
||||
*/
|
||||
- (nullable NSDate *)dateByAddingMonths:(NSInteger)months;
|
||||
|
||||
/**
|
||||
Returns a date representing the receiver date shifted later by the provided number of weeks.
|
||||
|
||||
@param weeks Number of weeks to add.
|
||||
@return Date modified by the number of desired weeks.
|
||||
*/
|
||||
- (nullable NSDate *)dateByAddingWeeks:(NSInteger)weeks;
|
||||
|
||||
/**
|
||||
Returns a date representing the receiver date shifted later by the provided number of days.
|
||||
|
||||
@param days Number of days to add.
|
||||
@return Date modified by the number of desired days.
|
||||
*/
|
||||
- (nullable NSDate *)dateByAddingDays:(NSInteger)days;
|
||||
|
||||
/**
|
||||
Returns a date representing the receiver date shifted later by the provided number of hours.
|
||||
|
||||
@param hours Number of hours to add.
|
||||
@return Date modified by the number of desired hours.
|
||||
*/
|
||||
- (nullable NSDate *)dateByAddingHours:(NSInteger)hours;
|
||||
|
||||
/**
|
||||
Returns a date representing the receiver date shifted later by the provided number of minutes.
|
||||
|
||||
@param minutes Number of minutes to add.
|
||||
@return Date modified by the number of desired minutes.
|
||||
*/
|
||||
- (nullable NSDate *)dateByAddingMinutes:(NSInteger)minutes;
|
||||
|
||||
/**
|
||||
Returns a date representing the receiver date shifted later by the provided number of seconds.
|
||||
|
||||
@param seconds Number of seconds to add.
|
||||
@return Date modified by the number of desired seconds.
|
||||
*/
|
||||
- (nullable NSDate *)dateByAddingSeconds:(NSInteger)seconds;
|
||||
|
||||
|
||||
#pragma mark - Date Format
|
||||
///=============================================================================
|
||||
/// @name Date Format
|
||||
///=============================================================================
|
||||
|
||||
/**
|
||||
Returns a formatted string representing this date.
|
||||
see http://www.unicode.org/reports/tr35/tr35-31/tr35-dates.html#Date_Format_Patterns
|
||||
for format description.
|
||||
|
||||
@param format String representing the desired date format.
|
||||
e.g. @"yyyy-MM-dd HH:mm:ss"
|
||||
|
||||
@return NSString representing the formatted date string.
|
||||
*/
|
||||
- (nullable NSString *)stringWithFormat:(NSString *)format;
|
||||
|
||||
/**
|
||||
Returns a formatted string representing this date.
|
||||
see http://www.unicode.org/reports/tr35/tr35-31/tr35-dates.html#Date_Format_Patterns
|
||||
for format description.
|
||||
|
||||
@param format String representing the desired date format.
|
||||
e.g. @"yyyy-MM-dd HH:mm:ss"
|
||||
|
||||
@param timeZone Desired time zone.
|
||||
|
||||
@param locale Desired locale.
|
||||
|
||||
@return NSString representing the formatted date string.
|
||||
*/
|
||||
- (nullable NSString *)stringWithFormat:(NSString *)format
|
||||
timeZone:(nullable NSTimeZone *)timeZone
|
||||
locale:(nullable NSLocale *)locale;
|
||||
|
||||
/**
|
||||
Returns a string representing this date in ISO8601 format.
|
||||
e.g. "2010-07-09T16:13:30+12:00"
|
||||
|
||||
@return NSString representing the formatted date string in ISO8601.
|
||||
*/
|
||||
- (nullable NSString *)stringWithISOFormat;
|
||||
|
||||
/**
|
||||
Returns a date parsed from given string interpreted using the format.
|
||||
|
||||
@param dateString The string to parse.
|
||||
@param format The string's date format.
|
||||
|
||||
@return A date representation of string interpreted using the format.
|
||||
If can not parse the string, returns nil.
|
||||
*/
|
||||
+ (nullable NSDate *)dateWithString:(NSString *)dateString format:(NSString *)format;
|
||||
|
||||
/**
|
||||
Returns a date parsed from given string interpreted using the format.
|
||||
|
||||
@param dateString The string to parse.
|
||||
@param format The string's date format.
|
||||
@param timeZone The time zone, can be nil.
|
||||
@param locale The locale, can be nil.
|
||||
|
||||
@return A date representation of string interpreted using the format.
|
||||
If can not parse the string, returns nil.
|
||||
*/
|
||||
+ (nullable NSDate *)dateWithString:(NSString *)dateString
|
||||
format:(NSString *)format
|
||||
timeZone:(nullable NSTimeZone *)timeZone
|
||||
locale:(nullable NSLocale *)locale;
|
||||
|
||||
/**
|
||||
Returns a date parsed from given string interpreted using the ISO8601 format.
|
||||
|
||||
@param dateString The date string in ISO8601 format. e.g. "2010-07-09T16:13:30+12:00"
|
||||
|
||||
@return A date representation of string interpreted using the format.
|
||||
If can not parse the string, returns nil.
|
||||
*/
|
||||
+ (nullable NSDate *)dateWithISOFormatString:(NSString *)dateString;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
188
Pods/YYCategories/YYCategories/Foundation/NSDate+YYAdd.m
generated
Normal file
188
Pods/YYCategories/YYCategories/Foundation/NSDate+YYAdd.m
generated
Normal file
@@ -0,0 +1,188 @@
|
||||
//
|
||||
// NSDate+YYAdd.m
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 13/4/11.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import "NSDate+YYAdd.h"
|
||||
#import "YYCategoriesMacro.h"
|
||||
#import <time.h>
|
||||
|
||||
YYSYNTH_DUMMY_CLASS(NSDate_YYAdd)
|
||||
|
||||
|
||||
@implementation NSDate (YYAdd)
|
||||
|
||||
- (NSInteger)year {
|
||||
return [[[NSCalendar currentCalendar] components:NSCalendarUnitYear fromDate:self] year];
|
||||
}
|
||||
|
||||
- (NSInteger)month {
|
||||
return [[[NSCalendar currentCalendar] components:NSCalendarUnitMonth fromDate:self] month];
|
||||
}
|
||||
|
||||
- (NSInteger)day {
|
||||
return [[[NSCalendar currentCalendar] components:NSCalendarUnitDay fromDate:self] day];
|
||||
}
|
||||
|
||||
- (NSInteger)hour {
|
||||
return [[[NSCalendar currentCalendar] components:NSCalendarUnitHour fromDate:self] hour];
|
||||
}
|
||||
|
||||
- (NSInteger)minute {
|
||||
return [[[NSCalendar currentCalendar] components:NSCalendarUnitMinute fromDate:self] minute];
|
||||
}
|
||||
|
||||
- (NSInteger)second {
|
||||
return [[[NSCalendar currentCalendar] components:NSCalendarUnitSecond fromDate:self] second];
|
||||
}
|
||||
|
||||
- (NSInteger)nanosecond {
|
||||
return [[[NSCalendar currentCalendar] components:NSCalendarUnitSecond fromDate:self] nanosecond];
|
||||
}
|
||||
|
||||
- (NSInteger)weekday {
|
||||
return [[[NSCalendar currentCalendar] components:NSCalendarUnitWeekday fromDate:self] weekday];
|
||||
}
|
||||
|
||||
- (NSInteger)weekdayOrdinal {
|
||||
return [[[NSCalendar currentCalendar] components:NSCalendarUnitWeekdayOrdinal fromDate:self] weekdayOrdinal];
|
||||
}
|
||||
|
||||
- (NSInteger)weekOfMonth {
|
||||
return [[[NSCalendar currentCalendar] components:NSCalendarUnitWeekOfMonth fromDate:self] weekOfMonth];
|
||||
}
|
||||
|
||||
- (NSInteger)weekOfYear {
|
||||
return [[[NSCalendar currentCalendar] components:NSCalendarUnitWeekOfYear fromDate:self] weekOfYear];
|
||||
}
|
||||
|
||||
- (NSInteger)yearForWeekOfYear {
|
||||
return [[[NSCalendar currentCalendar] components:NSCalendarUnitYearForWeekOfYear fromDate:self] yearForWeekOfYear];
|
||||
}
|
||||
|
||||
- (NSInteger)quarter {
|
||||
return [[[NSCalendar currentCalendar] components:NSCalendarUnitQuarter fromDate:self] quarter];
|
||||
}
|
||||
|
||||
- (BOOL)isLeapMonth {
|
||||
return [[[NSCalendar currentCalendar] components:NSCalendarUnitQuarter fromDate:self] isLeapMonth];
|
||||
}
|
||||
|
||||
- (BOOL)isLeapYear {
|
||||
NSUInteger year = self.year;
|
||||
return ((year % 400 == 0) || ((year % 100 != 0) && (year % 4 == 0)));
|
||||
}
|
||||
|
||||
- (BOOL)isToday {
|
||||
if (fabs(self.timeIntervalSinceNow) >= 60 * 60 * 24) return NO;
|
||||
return [NSDate new].day == self.day;
|
||||
}
|
||||
|
||||
- (BOOL)isYesterday {
|
||||
NSDate *added = [self dateByAddingDays:1];
|
||||
return [added isToday];
|
||||
}
|
||||
|
||||
- (NSDate *)dateByAddingYears:(NSInteger)years {
|
||||
NSCalendar *calendar = [NSCalendar currentCalendar];
|
||||
NSDateComponents *components = [[NSDateComponents alloc] init];
|
||||
[components setYear:years];
|
||||
return [calendar dateByAddingComponents:components toDate:self options:0];
|
||||
}
|
||||
|
||||
- (NSDate *)dateByAddingMonths:(NSInteger)months {
|
||||
NSCalendar *calendar = [NSCalendar currentCalendar];
|
||||
NSDateComponents *components = [[NSDateComponents alloc] init];
|
||||
[components setMonth:months];
|
||||
return [calendar dateByAddingComponents:components toDate:self options:0];
|
||||
}
|
||||
|
||||
- (NSDate *)dateByAddingWeeks:(NSInteger)weeks {
|
||||
NSCalendar *calendar = [NSCalendar currentCalendar];
|
||||
NSDateComponents *components = [[NSDateComponents alloc] init];
|
||||
[components setWeekOfYear:weeks];
|
||||
return [calendar dateByAddingComponents:components toDate:self options:0];
|
||||
}
|
||||
|
||||
- (NSDate *)dateByAddingDays:(NSInteger)days {
|
||||
NSTimeInterval aTimeInterval = [self timeIntervalSinceReferenceDate] + 86400 * days;
|
||||
NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval];
|
||||
return newDate;
|
||||
}
|
||||
|
||||
- (NSDate *)dateByAddingHours:(NSInteger)hours {
|
||||
NSTimeInterval aTimeInterval = [self timeIntervalSinceReferenceDate] + 3600 * hours;
|
||||
NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval];
|
||||
return newDate;
|
||||
}
|
||||
|
||||
- (NSDate *)dateByAddingMinutes:(NSInteger)minutes {
|
||||
NSTimeInterval aTimeInterval = [self timeIntervalSinceReferenceDate] + 60 * minutes;
|
||||
NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval];
|
||||
return newDate;
|
||||
}
|
||||
|
||||
- (NSDate *)dateByAddingSeconds:(NSInteger)seconds {
|
||||
NSTimeInterval aTimeInterval = [self timeIntervalSinceReferenceDate] + seconds;
|
||||
NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval];
|
||||
return newDate;
|
||||
}
|
||||
|
||||
- (NSString *)stringWithFormat:(NSString *)format {
|
||||
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
|
||||
[formatter setDateFormat:format];
|
||||
[formatter setLocale:[NSLocale currentLocale]];
|
||||
return [formatter stringFromDate:self];
|
||||
}
|
||||
|
||||
- (NSString *)stringWithFormat:(NSString *)format timeZone:(NSTimeZone *)timeZone locale:(NSLocale *)locale {
|
||||
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
|
||||
[formatter setDateFormat:format];
|
||||
if (timeZone) [formatter setTimeZone:timeZone];
|
||||
if (locale) [formatter setLocale:locale];
|
||||
return [formatter stringFromDate:self];
|
||||
}
|
||||
|
||||
- (NSString *)stringWithISOFormat {
|
||||
static NSDateFormatter *formatter = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
formatter = [[NSDateFormatter alloc] init];
|
||||
formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
|
||||
formatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ssZ";
|
||||
});
|
||||
return [formatter stringFromDate:self];
|
||||
}
|
||||
|
||||
+ (NSDate *)dateWithString:(NSString *)dateString format:(NSString *)format {
|
||||
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
|
||||
[formatter setDateFormat:format];
|
||||
return [formatter dateFromString:dateString];
|
||||
}
|
||||
|
||||
+ (NSDate *)dateWithString:(NSString *)dateString format:(NSString *)format timeZone:(NSTimeZone *)timeZone locale:(NSLocale *)locale {
|
||||
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
|
||||
[formatter setDateFormat:format];
|
||||
if (timeZone) [formatter setTimeZone:timeZone];
|
||||
if (locale) [formatter setLocale:locale];
|
||||
return [formatter dateFromString:dateString];
|
||||
}
|
||||
|
||||
+ (NSDate *)dateWithISOFormatString:(NSString *)dateString {
|
||||
static NSDateFormatter *formatter = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
formatter = [[NSDateFormatter alloc] init];
|
||||
formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
|
||||
formatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ssZ";
|
||||
});
|
||||
return [formatter dateFromString:dateString];
|
||||
}
|
||||
|
||||
@end
|
||||
197
Pods/YYCategories/YYCategories/Foundation/NSDictionary+YYAdd.h
generated
Normal file
197
Pods/YYCategories/YYCategories/Foundation/NSDictionary+YYAdd.h
generated
Normal file
@@ -0,0 +1,197 @@
|
||||
//
|
||||
// NSDictionary+YYAdd.h
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 13/4/4.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
Provide some some common method for `NSDictionary`.
|
||||
*/
|
||||
@interface NSDictionary (YYAdd)
|
||||
|
||||
#pragma mark - Dictionary Convertor
|
||||
///=============================================================================
|
||||
/// @name Dictionary Convertor
|
||||
///=============================================================================
|
||||
|
||||
/**
|
||||
Creates and returns a dictionary from a specified property list data.
|
||||
|
||||
@param plist A property list data whose root object is a dictionary.
|
||||
@return A new dictionary created from the plist data, or nil if an error occurs.
|
||||
*/
|
||||
+ (nullable NSDictionary *)dictionaryWithPlistData:(NSData *)plist;
|
||||
|
||||
/**
|
||||
Creates and returns a dictionary from a specified property list xml string.
|
||||
|
||||
@param plist A property list xml string whose root object is a dictionary.
|
||||
@return A new dictionary created from the plist string, or nil if an error occurs.
|
||||
|
||||
@discussion Apple has implemented this method, but did not make it public.
|
||||
*/
|
||||
+ (nullable NSDictionary *)dictionaryWithPlistString:(NSString *)plist;
|
||||
|
||||
/**
|
||||
Serialize the dictionary to a binary property list data.
|
||||
|
||||
@return A bplist data, or nil if an error occurs.
|
||||
|
||||
@discussion Apple has implemented this method, but did not make it public.
|
||||
*/
|
||||
- (nullable NSData *)plistData;
|
||||
|
||||
/**
|
||||
Serialize the dictionary to a xml property list string.
|
||||
|
||||
@return A plist xml string, or nil if an error occurs.
|
||||
*/
|
||||
- (nullable NSString *)plistString;
|
||||
|
||||
/**
|
||||
Returns a new array containing the dictionary's keys sorted.
|
||||
The keys should be NSString, and they will be sorted ascending.
|
||||
|
||||
@return A new array containing the dictionary's keys,
|
||||
or an empty array if the dictionary has no entries.
|
||||
*/
|
||||
- (NSArray *)allKeysSorted;
|
||||
|
||||
/**
|
||||
Returns a new array containing the dictionary's values sorted by keys.
|
||||
|
||||
The order of the values in the array is defined by keys.
|
||||
The keys should be NSString, and they will be sorted ascending.
|
||||
|
||||
@return A new array containing the dictionary's values sorted by keys,
|
||||
or an empty array if the dictionary has no entries.
|
||||
*/
|
||||
- (NSArray *)allValuesSortedByKeys;
|
||||
|
||||
/**
|
||||
Returns a BOOL value tells if the dictionary has an object for key.
|
||||
|
||||
@param key The key.
|
||||
*/
|
||||
- (BOOL)containsObjectForKey:(id)key;
|
||||
|
||||
/**
|
||||
Returns a new dictionary containing the entries for keys.
|
||||
If the keys is empty or nil, it just returns an empty dictionary.
|
||||
|
||||
@param keys The keys.
|
||||
@return The entries for the keys.
|
||||
*/
|
||||
- (NSDictionary *)entriesForKeys:(NSArray *)keys;
|
||||
|
||||
/**
|
||||
Convert dictionary to json string. return nil if an error occurs.
|
||||
*/
|
||||
- (nullable NSString *)jsonStringEncoded;
|
||||
|
||||
/**
|
||||
Convert dictionary to json string formatted. return nil if an error occurs.
|
||||
*/
|
||||
- (nullable NSString *)jsonPrettyStringEncoded;
|
||||
|
||||
/**
|
||||
Try to parse an XML and wrap it into a dictionary.
|
||||
If you just want to get some value from a small xml, try this.
|
||||
|
||||
example XML: "<config><a href="test.com">link</a></config>"
|
||||
example Return: @{@"_name":@"config", @"a":{@"_text":@"link",@"href":@"test.com"}}
|
||||
|
||||
@param xmlDataOrString XML in NSData or NSString format.
|
||||
@return Return a new dictionary, or nil if an error occurs.
|
||||
*/
|
||||
+ (nullable NSDictionary *)dictionaryWithXML:(id)xmlDataOrString;
|
||||
|
||||
#pragma mark - Dictionary Value Getter
|
||||
///=============================================================================
|
||||
/// @name Dictionary Value Getter
|
||||
///=============================================================================
|
||||
|
||||
- (BOOL)boolValueForKey:(NSString *)key default:(BOOL)def;
|
||||
|
||||
- (char)charValueForKey:(NSString *)key default:(char)def;
|
||||
- (unsigned char)unsignedCharValueForKey:(NSString *)key default:(unsigned char)def;
|
||||
|
||||
- (short)shortValueForKey:(NSString *)key default:(short)def;
|
||||
- (unsigned short)unsignedShortValueForKey:(NSString *)key default:(unsigned short)def;
|
||||
|
||||
- (int)intValueForKey:(NSString *)key default:(int)def;
|
||||
- (unsigned int)unsignedIntValueForKey:(NSString *)key default:(unsigned int)def;
|
||||
|
||||
- (long)longValueForKey:(NSString *)key default:(long)def;
|
||||
- (unsigned long)unsignedLongValueForKey:(NSString *)key default:(unsigned long)def;
|
||||
|
||||
- (long long)longLongValueForKey:(NSString *)key default:(long long)def;
|
||||
- (unsigned long long)unsignedLongLongValueForKey:(NSString *)key default:(unsigned long long)def;
|
||||
|
||||
- (float)floatValueForKey:(NSString *)key default:(float)def;
|
||||
- (double)doubleValueForKey:(NSString *)key default:(double)def;
|
||||
|
||||
- (NSInteger)integerValueForKey:(NSString *)key default:(NSInteger)def;
|
||||
- (NSUInteger)unsignedIntegerValueForKey:(NSString *)key default:(NSUInteger)def;
|
||||
|
||||
- (nullable NSNumber *)numberValueForKey:(NSString *)key default:(nullable NSNumber *)def;
|
||||
- (nullable NSString *)stringValueForKey:(NSString *)key default:(nullable NSString *)def;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Provide some some common method for `NSMutableDictionary`.
|
||||
*/
|
||||
@interface NSMutableDictionary (YYAdd)
|
||||
|
||||
/**
|
||||
Creates and returns a dictionary from a specified property list data.
|
||||
|
||||
@param plist A property list data whose root object is a dictionary.
|
||||
@return A new dictionary created from the plist data, or nil if an error occurs.
|
||||
|
||||
@discussion Apple has implemented this method, but did not make it public.
|
||||
*/
|
||||
+ (nullable NSMutableDictionary *)dictionaryWithPlistData:(NSData *)plist;
|
||||
|
||||
/**
|
||||
Creates and returns a dictionary from a specified property list xml string.
|
||||
|
||||
@param plist A property list xml string whose root object is a dictionary.
|
||||
@return A new dictionary created from the plist string, or nil if an error occurs.
|
||||
*/
|
||||
+ (nullable NSMutableDictionary *)dictionaryWithPlistString:(NSString *)plist;
|
||||
|
||||
|
||||
/**
|
||||
Removes and returns the value associated with a given key.
|
||||
|
||||
@param aKey The key for which to return and remove the corresponding value.
|
||||
@return The value associated with aKey, or nil if no value is associated with aKey.
|
||||
*/
|
||||
- (nullable id)popObjectForKey:(id)aKey;
|
||||
|
||||
/**
|
||||
Returns a new dictionary containing the entries for keys, and remove these
|
||||
entries from reciever. If the keys is empty or nil, it just returns an
|
||||
empty dictionary.
|
||||
|
||||
@param keys The keys.
|
||||
@return The entries for the keys.
|
||||
*/
|
||||
- (NSDictionary *)popEntriesForKeys:(NSArray *)keys;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
391
Pods/YYCategories/YYCategories/Foundation/NSDictionary+YYAdd.m
generated
Normal file
391
Pods/YYCategories/YYCategories/Foundation/NSDictionary+YYAdd.m
generated
Normal file
@@ -0,0 +1,391 @@
|
||||
//
|
||||
// NSDictionary+YYAdd.m
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 13/4/4.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import "NSDictionary+YYAdd.h"
|
||||
#import "NSString+YYAdd.h"
|
||||
#import "NSData+YYAdd.h"
|
||||
#import "YYCategoriesMacro.h"
|
||||
|
||||
YYSYNTH_DUMMY_CLASS(NSDictionary_YYAdd)
|
||||
|
||||
|
||||
@interface _YYXMLDictionaryParser : NSObject <NSXMLParserDelegate>
|
||||
@end
|
||||
|
||||
@implementation _YYXMLDictionaryParser {
|
||||
NSMutableDictionary *_root;
|
||||
NSMutableArray *_stack;
|
||||
NSMutableString *_text;
|
||||
}
|
||||
|
||||
- (instancetype)initWithData:(NSData *)data {
|
||||
self = super.init;
|
||||
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
|
||||
[parser setDelegate:self];
|
||||
[parser parse];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithString:(NSString *)xml {
|
||||
NSData *data = [xml dataUsingEncoding:NSUTF8StringEncoding];
|
||||
return [self initWithData:data];
|
||||
}
|
||||
|
||||
- (NSDictionary *)result {
|
||||
return _root;
|
||||
}
|
||||
|
||||
#pragma mark NSXMLParserDelegate
|
||||
|
||||
#define XMLText @"_text"
|
||||
#define XMLName @"_name"
|
||||
#define XMLPref @"_"
|
||||
|
||||
- (void)textEnd {
|
||||
_text = _text.stringByTrim.mutableCopy;
|
||||
if (_text.length) {
|
||||
NSMutableDictionary *top = _stack.lastObject;
|
||||
id existing = top[XMLText];
|
||||
if ([existing isKindOfClass:[NSArray class]]) {
|
||||
[existing addObject:_text];
|
||||
} else if (existing) {
|
||||
top[XMLText] = [@[existing, _text] mutableCopy];
|
||||
} else {
|
||||
top[XMLText] = _text;
|
||||
}
|
||||
}
|
||||
_text = nil;
|
||||
}
|
||||
|
||||
- (void)parser:(__unused NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(__unused NSString *)namespaceURI qualifiedName:(__unused NSString *)qName attributes:(NSDictionary *)attributeDict {
|
||||
[self textEnd];
|
||||
|
||||
NSMutableDictionary *node = [NSMutableDictionary new];
|
||||
if (!_root) node[XMLName] = elementName;
|
||||
if (attributeDict.count) [node addEntriesFromDictionary:attributeDict];
|
||||
|
||||
if (_root) {
|
||||
NSMutableDictionary *top = _stack.lastObject;
|
||||
id existing = top[elementName];
|
||||
if ([existing isKindOfClass:[NSArray class]]) {
|
||||
[existing addObject:node];
|
||||
} else if (existing) {
|
||||
top[elementName] = [@[existing, node] mutableCopy];
|
||||
} else {
|
||||
top[elementName] = node;
|
||||
}
|
||||
[_stack addObject:node];
|
||||
} else {
|
||||
_root = node;
|
||||
_stack = [NSMutableArray arrayWithObject:node];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)parser:(__unused NSXMLParser *)parser didEndElement:(__unused NSString *)elementName namespaceURI:(__unused NSString *)namespaceURI qualifiedName:(__unused NSString *)qName {
|
||||
[self textEnd];
|
||||
|
||||
NSMutableDictionary *top = _stack.lastObject;
|
||||
[_stack removeLastObject];
|
||||
|
||||
NSMutableDictionary *left = top.mutableCopy;
|
||||
[left removeObjectsForKeys:@[XMLText, XMLName]];
|
||||
for (NSString *key in left.allKeys) {
|
||||
[left removeObjectForKey:key];
|
||||
if ([key hasPrefix:XMLPref]) {
|
||||
left[[key substringFromIndex:XMLPref.length]] = top[key];
|
||||
}
|
||||
}
|
||||
if (left.count) return;
|
||||
|
||||
NSMutableDictionary *children = top.mutableCopy;
|
||||
[children removeObjectsForKeys:@[XMLText, XMLName]];
|
||||
for (NSString *key in children.allKeys) {
|
||||
if ([key hasPrefix:XMLPref]) {
|
||||
[children removeObjectForKey:key];
|
||||
}
|
||||
}
|
||||
if (children.count) return;
|
||||
|
||||
NSMutableDictionary *topNew = _stack.lastObject;
|
||||
NSString *nodeName = top[XMLName];
|
||||
if (!nodeName) {
|
||||
for (NSString *name in topNew) {
|
||||
id object = topNew[name];
|
||||
if (object == top) {
|
||||
nodeName = name; break;
|
||||
} else if ([object isKindOfClass:[NSArray class]] && [object containsObject:top]) {
|
||||
nodeName = name; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!nodeName) return;
|
||||
|
||||
id inner = top[XMLText];
|
||||
if ([inner isKindOfClass:[NSArray class]]) {
|
||||
inner = [inner componentsJoinedByString:@"\n"];
|
||||
}
|
||||
if (!inner) return;
|
||||
|
||||
id parent = topNew[nodeName];
|
||||
if ([parent isKindOfClass:[NSArray class]]) {
|
||||
parent[[parent count] - 1] = inner;
|
||||
} else {
|
||||
topNew[nodeName] = inner;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)parser:(__unused NSXMLParser *)parser foundCharacters:(NSString *)string {
|
||||
if (_text) [_text appendString:string];
|
||||
else _text = [NSMutableString stringWithString:string];
|
||||
}
|
||||
|
||||
- (void)parser:(__unused NSXMLParser *)parser foundCDATA:(NSData *)CDATABlock {
|
||||
NSString *string = [[NSString alloc] initWithData:CDATABlock encoding:NSUTF8StringEncoding];
|
||||
if (_text) [_text appendString:string];
|
||||
else _text = [NSMutableString stringWithString:string];
|
||||
}
|
||||
|
||||
#undef XMLText
|
||||
#undef XMLName
|
||||
#undef XMLPref
|
||||
@end
|
||||
|
||||
|
||||
@implementation NSDictionary (YYAdd)
|
||||
|
||||
+ (NSDictionary *)dictionaryWithPlistData:(NSData *)plist {
|
||||
if (!plist) return nil;
|
||||
NSDictionary *dictionary = [NSPropertyListSerialization propertyListWithData:plist options:NSPropertyListImmutable format:NULL error:NULL];
|
||||
if ([dictionary isKindOfClass:[NSDictionary class]]) return dictionary;
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (NSDictionary *)dictionaryWithPlistString:(NSString *)plist {
|
||||
if (!plist) return nil;
|
||||
NSData* data = [plist dataUsingEncoding:NSUTF8StringEncoding];
|
||||
return [self dictionaryWithPlistData:data];
|
||||
}
|
||||
|
||||
- (NSData *)plistData {
|
||||
return [NSPropertyListSerialization dataWithPropertyList:self format:NSPropertyListBinaryFormat_v1_0 options:kNilOptions error:NULL];
|
||||
}
|
||||
|
||||
- (NSString *)plistString {
|
||||
NSData *xmlData = [NSPropertyListSerialization dataWithPropertyList:self format:NSPropertyListXMLFormat_v1_0 options:kNilOptions error:NULL];
|
||||
if (xmlData) return xmlData.utf8String;
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSArray *)allKeysSorted {
|
||||
return [[self allKeys] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
|
||||
}
|
||||
|
||||
- (NSArray *)allValuesSortedByKeys {
|
||||
NSArray *sortedKeys = [self allKeysSorted];
|
||||
NSMutableArray *arr = [[NSMutableArray alloc] init];
|
||||
for (id key in sortedKeys) {
|
||||
[arr addObject:self[key]];
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
- (BOOL)containsObjectForKey:(id)key {
|
||||
if (!key) return NO;
|
||||
return self[key] != nil;
|
||||
}
|
||||
|
||||
- (NSDictionary *)entriesForKeys:(NSArray *)keys {
|
||||
NSMutableDictionary *dic = [NSMutableDictionary new];
|
||||
for (id key in keys) {
|
||||
id value = self[key];
|
||||
if (value) dic[key] = value;
|
||||
}
|
||||
return dic;
|
||||
}
|
||||
|
||||
- (NSString *)jsonStringEncoded {
|
||||
if ([NSJSONSerialization isValidJSONObject:self]) {
|
||||
NSError *error;
|
||||
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:self options:0 error:&error];
|
||||
NSString *json = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
|
||||
return json;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSString *)jsonPrettyStringEncoded {
|
||||
if ([NSJSONSerialization isValidJSONObject:self]) {
|
||||
NSError *error;
|
||||
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:self options:NSJSONWritingPrettyPrinted error:&error];
|
||||
NSString *json = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
|
||||
return json;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (NSDictionary *)dictionaryWithXML:(id)xml {
|
||||
_YYXMLDictionaryParser *parser = nil;
|
||||
if ([xml isKindOfClass:[NSString class]]) {
|
||||
parser = [[_YYXMLDictionaryParser alloc] initWithString:xml];
|
||||
} else if ([xml isKindOfClass:[NSData class]]) {
|
||||
parser = [[_YYXMLDictionaryParser alloc] initWithData:xml];
|
||||
}
|
||||
return [parser result];
|
||||
}
|
||||
|
||||
|
||||
/// Get a number value from 'id'.
|
||||
static NSNumber *NSNumberFromID(id value) {
|
||||
static NSCharacterSet *dot;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
dot = [NSCharacterSet characterSetWithRange:NSMakeRange('.', 1)];
|
||||
});
|
||||
if (!value || value == [NSNull null]) return nil;
|
||||
if ([value isKindOfClass:[NSNumber class]]) return value;
|
||||
if ([value isKindOfClass:[NSString class]]) {
|
||||
NSString *lower = ((NSString *)value).lowercaseString;
|
||||
if ([lower isEqualToString:@"true"] || [lower isEqualToString:@"yes"]) return @(YES);
|
||||
if ([lower isEqualToString:@"false"] || [lower isEqualToString:@"no"]) return @(NO);
|
||||
if ([lower isEqualToString:@"nil"] || [lower isEqualToString:@"null"]) return nil;
|
||||
if ([(NSString *)value rangeOfCharacterFromSet:dot].location != NSNotFound) {
|
||||
return @(((NSString *)value).doubleValue);
|
||||
} else {
|
||||
return @(((NSString *)value).longLongValue);
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
#define RETURN_VALUE(_type_) \
|
||||
if (!key) return def; \
|
||||
id value = self[key]; \
|
||||
if (!value || value == [NSNull null]) return def; \
|
||||
if ([value isKindOfClass:[NSNumber class]]) return ((NSNumber *)value)._type_; \
|
||||
if ([value isKindOfClass:[NSString class]]) return NSNumberFromID(value)._type_; \
|
||||
return def;
|
||||
|
||||
- (BOOL)boolValueForKey:(NSString *)key default:(BOOL)def {
|
||||
RETURN_VALUE(boolValue);
|
||||
}
|
||||
|
||||
- (char)charValueForKey:(NSString *)key default:(char)def {
|
||||
RETURN_VALUE(charValue);
|
||||
}
|
||||
|
||||
- (unsigned char)unsignedCharValueForKey:(NSString *)key default:(unsigned char)def {
|
||||
RETURN_VALUE(unsignedCharValue);
|
||||
}
|
||||
|
||||
- (short)shortValueForKey:(NSString *)key default:(short)def {
|
||||
RETURN_VALUE(shortValue);
|
||||
}
|
||||
|
||||
- (unsigned short)unsignedShortValueForKey:(NSString *)key default:(unsigned short)def {
|
||||
RETURN_VALUE(unsignedShortValue);
|
||||
}
|
||||
|
||||
- (int)intValueForKey:(NSString *)key default:(int)def {
|
||||
RETURN_VALUE(intValue);
|
||||
}
|
||||
|
||||
- (unsigned int)unsignedIntValueForKey:(NSString *)key default:(unsigned int)def {
|
||||
RETURN_VALUE(unsignedIntValue);
|
||||
}
|
||||
|
||||
- (long)longValueForKey:(NSString *)key default:(long)def {
|
||||
RETURN_VALUE(longValue);
|
||||
}
|
||||
|
||||
- (unsigned long)unsignedLongValueForKey:(NSString *)key default:(unsigned long)def {
|
||||
RETURN_VALUE(unsignedLongValue);
|
||||
}
|
||||
|
||||
- (long long)longLongValueForKey:(NSString *)key default:(long long)def {
|
||||
RETURN_VALUE(longLongValue);
|
||||
}
|
||||
|
||||
- (unsigned long long)unsignedLongLongValueForKey:(NSString *)key default:(unsigned long long)def {
|
||||
RETURN_VALUE(unsignedLongLongValue);
|
||||
}
|
||||
|
||||
- (float)floatValueForKey:(NSString *)key default:(float)def {
|
||||
RETURN_VALUE(floatValue);
|
||||
}
|
||||
|
||||
- (double)doubleValueForKey:(NSString *)key default:(double)def {
|
||||
RETURN_VALUE(doubleValue);
|
||||
}
|
||||
|
||||
- (NSInteger)integerValueForKey:(NSString *)key default:(NSInteger)def {
|
||||
RETURN_VALUE(integerValue);
|
||||
}
|
||||
|
||||
- (NSUInteger)unsignedIntegerValueForKey:(NSString *)key default:(NSUInteger)def {
|
||||
RETURN_VALUE(unsignedIntegerValue);
|
||||
}
|
||||
|
||||
- (NSNumber *)numberValueForKey:(NSString *)key default:(NSNumber *)def {
|
||||
if (!key) return def;
|
||||
id value = self[key];
|
||||
if (!value || value == [NSNull null]) return def;
|
||||
if ([value isKindOfClass:[NSNumber class]]) return value;
|
||||
if ([value isKindOfClass:[NSString class]]) return NSNumberFromID(value);
|
||||
return def;
|
||||
}
|
||||
|
||||
- (NSString *)stringValueForKey:(NSString *)key default:(NSString *)def {
|
||||
if (!key) return def;
|
||||
id value = self[key];
|
||||
if (!value || value == [NSNull null]) return def;
|
||||
if ([value isKindOfClass:[NSString class]]) return value;
|
||||
if ([value isKindOfClass:[NSNumber class]]) return ((NSNumber *)value).description;
|
||||
return def;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation NSMutableDictionary (YYAdd)
|
||||
|
||||
+ (NSMutableDictionary *)dictionaryWithPlistData:(NSData *)plist {
|
||||
if (!plist) return nil;
|
||||
NSMutableDictionary *dictionary = [NSPropertyListSerialization propertyListWithData:plist options:NSPropertyListMutableContainersAndLeaves format:NULL error:NULL];
|
||||
if ([dictionary isKindOfClass:[NSMutableDictionary class]]) return dictionary;
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (NSMutableDictionary *)dictionaryWithPlistString:(NSString *)plist {
|
||||
if (!plist) return nil;
|
||||
NSData* data = [plist dataUsingEncoding:NSUTF8StringEncoding];
|
||||
return [self dictionaryWithPlistData:data];
|
||||
}
|
||||
|
||||
- (id)popObjectForKey:(id)aKey {
|
||||
if (!aKey) return nil;
|
||||
id value = self[aKey];
|
||||
[self removeObjectForKey:aKey];
|
||||
return value;
|
||||
}
|
||||
|
||||
- (NSDictionary *)popEntriesForKeys:(NSArray *)keys {
|
||||
NSMutableDictionary *dic = [NSMutableDictionary new];
|
||||
for (id key in keys) {
|
||||
id value = self[key];
|
||||
if (value) {
|
||||
[self removeObjectForKey:key];
|
||||
dic[key] = value;
|
||||
}
|
||||
}
|
||||
return dic;
|
||||
}
|
||||
|
||||
@end
|
||||
45
Pods/YYCategories/YYCategories/Foundation/NSKeyedUnarchiver+YYAdd.h
generated
Normal file
45
Pods/YYCategories/YYCategories/Foundation/NSKeyedUnarchiver+YYAdd.h
generated
Normal file
@@ -0,0 +1,45 @@
|
||||
//
|
||||
// NSKeyedUnarchiver+YYAdd.h
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 13/8/4.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
Provides extensions for `NSKeyedUnarchiver`.
|
||||
*/
|
||||
@interface NSKeyedUnarchiver (YYAdd)
|
||||
|
||||
/**
|
||||
Same as unarchiveObjectWithData:, except it returns the exception by reference.
|
||||
|
||||
@param data The data need unarchived.
|
||||
|
||||
@param exception Pointer which will, upon return, if an exception occurred and
|
||||
said pointer is not NULL, point to said NSException.
|
||||
*/
|
||||
+ (nullable id)unarchiveObjectWithData:(NSData *)data
|
||||
exception:(NSException *_Nullable *_Nullable)exception;
|
||||
|
||||
/**
|
||||
Same as unarchiveObjectWithFile:, except it returns the exception by reference.
|
||||
|
||||
@param path The path of archived object file.
|
||||
|
||||
@param exception Pointer which will, upon return, if an exception occurred and
|
||||
said pointer is not NULL, point to said NSException.
|
||||
*/
|
||||
+ (nullable id)unarchiveObjectWithFile:(NSString *)path
|
||||
exception:(NSException *_Nullable *_Nullable)exception;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
51
Pods/YYCategories/YYCategories/Foundation/NSKeyedUnarchiver+YYAdd.m
generated
Normal file
51
Pods/YYCategories/YYCategories/Foundation/NSKeyedUnarchiver+YYAdd.m
generated
Normal file
@@ -0,0 +1,51 @@
|
||||
//
|
||||
// NSKeyedUnarchiver+YYAdd.m
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 13/8/4.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import "NSKeyedUnarchiver+YYAdd.h"
|
||||
#import "YYCategoriesMacro.h"
|
||||
|
||||
YYSYNTH_DUMMY_CLASS(NSKeyedUnarchiver_YYAdd)
|
||||
|
||||
|
||||
@implementation NSKeyedUnarchiver (YYAdd)
|
||||
|
||||
+ (id)unarchiveObjectWithData:(NSData *)data exception:(__autoreleasing NSException **)exception {
|
||||
id object = nil;
|
||||
@try {
|
||||
object = [NSKeyedUnarchiver unarchiveObjectWithData:data];
|
||||
}
|
||||
@catch (NSException *e)
|
||||
{
|
||||
if (exception) *exception = e;
|
||||
}
|
||||
@finally
|
||||
{
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
+ (id)unarchiveObjectWithFile:(NSString *)path exception:(__autoreleasing NSException **)exception {
|
||||
id object = nil;
|
||||
|
||||
@try {
|
||||
object = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
|
||||
}
|
||||
@catch (NSException *e)
|
||||
{
|
||||
if (exception) *exception = e;
|
||||
}
|
||||
@finally
|
||||
{
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
@end
|
||||
97
Pods/YYCategories/YYCategories/Foundation/NSNotificationCenter+YYAdd.h
generated
Normal file
97
Pods/YYCategories/YYCategories/Foundation/NSNotificationCenter+YYAdd.h
generated
Normal file
@@ -0,0 +1,97 @@
|
||||
//
|
||||
// NSNotificationCenter+YYAdd.h
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 13/8/24.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
Provide some method for `NSNotificationCenter`
|
||||
to post notification in different thread.
|
||||
*/
|
||||
@interface NSNotificationCenter (YYAdd)
|
||||
|
||||
/**
|
||||
Posts a given notification to the receiver on main thread.
|
||||
If current thread is main thread, the notification is posted synchronized;
|
||||
otherwise, is posted asynchronized.
|
||||
|
||||
@param notification The notification to post.
|
||||
An exception is raised if notification is nil.
|
||||
*/
|
||||
- (void)postNotificationOnMainThread:(NSNotification *)notification;
|
||||
|
||||
/**
|
||||
Posts a given notification to the receiver on main thread.
|
||||
|
||||
@param notification The notification to post.
|
||||
An exception is raised if notification is nil.
|
||||
|
||||
@param wait A Boolean that specifies whether the current thread blocks
|
||||
until after the specified notification is posted on the
|
||||
receiver on the main thread. Specify YES to block this
|
||||
thread; otherwise, specify NO to have this method return
|
||||
immediately.
|
||||
*/
|
||||
- (void)postNotificationOnMainThread:(NSNotification *)notification
|
||||
waitUntilDone:(BOOL)wait;
|
||||
|
||||
/**
|
||||
Creates a notification with a given name and sender and posts it to the
|
||||
receiver on main thread. If current thread is main thread, the notification
|
||||
is posted synchronized; otherwise, is posted asynchronized.
|
||||
|
||||
@param name The name of the notification.
|
||||
|
||||
@param object The object posting the notification.
|
||||
*/
|
||||
- (void)postNotificationOnMainThreadWithName:(NSString *)name
|
||||
object:(nullable id)object;
|
||||
|
||||
/**
|
||||
Creates a notification with a given name and sender and posts it to the
|
||||
receiver on main thread. If current thread is main thread, the notification
|
||||
is posted synchronized; otherwise, is posted asynchronized.
|
||||
|
||||
@param name The name of the notification.
|
||||
|
||||
@param object The object posting the notification.
|
||||
|
||||
@param userInfo Information about the the notification. May be nil.
|
||||
*/
|
||||
- (void)postNotificationOnMainThreadWithName:(NSString *)name
|
||||
object:(nullable id)object
|
||||
userInfo:(nullable NSDictionary *)userInfo;
|
||||
|
||||
/**
|
||||
Creates a notification with a given name and sender and posts it to the
|
||||
receiver on main thread.
|
||||
|
||||
@param name The name of the notification.
|
||||
|
||||
@param object The object posting the notification.
|
||||
|
||||
@param userInfo Information about the the notification. May be nil.
|
||||
|
||||
@param wait A Boolean that specifies whether the current thread blocks
|
||||
until after the specified notification is posted on the
|
||||
receiver on the main thread. Specify YES to block this
|
||||
thread; otherwise, specify NO to have this method return
|
||||
immediately.
|
||||
*/
|
||||
- (void)postNotificationOnMainThreadWithName:(NSString *)name
|
||||
object:(nullable id)object
|
||||
userInfo:(nullable NSDictionary *)userInfo
|
||||
waitUntilDone:(BOOL)wait;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
62
Pods/YYCategories/YYCategories/Foundation/NSNotificationCenter+YYAdd.m
generated
Normal file
62
Pods/YYCategories/YYCategories/Foundation/NSNotificationCenter+YYAdd.m
generated
Normal file
@@ -0,0 +1,62 @@
|
||||
//
|
||||
// NSNotificationCenter+YYAdd.m
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 13/8/24.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import "NSNotificationCenter+YYAdd.h"
|
||||
#include <pthread.h>
|
||||
#import "YYCategoriesMacro.h"
|
||||
|
||||
YYSYNTH_DUMMY_CLASS(NSNotificationCenter_YYAdd)
|
||||
|
||||
|
||||
@implementation NSNotificationCenter (YYAdd)
|
||||
|
||||
- (void)postNotificationOnMainThread:(NSNotification *)notification {
|
||||
if (pthread_main_np()) return [self postNotification:notification];
|
||||
[self postNotificationOnMainThread:notification waitUntilDone:NO];
|
||||
}
|
||||
|
||||
- (void)postNotificationOnMainThread:(NSNotification *)notification waitUntilDone:(BOOL)wait {
|
||||
if (pthread_main_np()) return [self postNotification:notification];
|
||||
[[self class] performSelectorOnMainThread:@selector(_yy_postNotification:) withObject:notification waitUntilDone:wait];
|
||||
}
|
||||
|
||||
- (void)postNotificationOnMainThreadWithName:(NSString *)name object:(id)object {
|
||||
if (pthread_main_np()) return [self postNotificationName:name object:object userInfo:nil];
|
||||
[self postNotificationOnMainThreadWithName:name object:object userInfo:nil waitUntilDone:NO];
|
||||
}
|
||||
|
||||
- (void)postNotificationOnMainThreadWithName:(NSString *)name object:(id)object userInfo:(NSDictionary *)userInfo {
|
||||
if (pthread_main_np()) return [self postNotificationName:name object:object userInfo:userInfo];
|
||||
[self postNotificationOnMainThreadWithName:name object:object userInfo:userInfo waitUntilDone:NO];
|
||||
}
|
||||
|
||||
- (void)postNotificationOnMainThreadWithName:(NSString *)name object:(id)object userInfo:(NSDictionary *)userInfo waitUntilDone:(BOOL)wait {
|
||||
if (pthread_main_np()) return [self postNotificationName:name object:object userInfo:userInfo];
|
||||
NSMutableDictionary *info = [[NSMutableDictionary allocWithZone:nil] initWithCapacity:3];
|
||||
if (name) [info setObject:name forKey:@"name"];
|
||||
if (object) [info setObject:object forKey:@"object"];
|
||||
if (userInfo) [info setObject:userInfo forKey:@"userInfo"];
|
||||
[[self class] performSelectorOnMainThread:@selector(_yy_postNotificationName:) withObject:info waitUntilDone:wait];
|
||||
}
|
||||
|
||||
+ (void)_yy_postNotification:(NSNotification *)notification {
|
||||
[[self defaultCenter] postNotification:notification];
|
||||
}
|
||||
|
||||
+ (void)_yy_postNotificationName:(NSDictionary *)info {
|
||||
NSString *name = [info objectForKey:@"name"];
|
||||
id object = [info objectForKey:@"object"];
|
||||
NSDictionary *userInfo = [info objectForKey:@"userInfo"];
|
||||
|
||||
[[self defaultCenter] postNotificationName:name object:object userInfo:userInfo];
|
||||
}
|
||||
|
||||
@end
|
||||
33
Pods/YYCategories/YYCategories/Foundation/NSNumber+YYAdd.h
generated
Normal file
33
Pods/YYCategories/YYCategories/Foundation/NSNumber+YYAdd.h
generated
Normal file
@@ -0,0 +1,33 @@
|
||||
//
|
||||
// NSNumber+YYAdd.h
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 13/8/24.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
Provide a method to parse `NSString` for `NSNumber`.
|
||||
*/
|
||||
@interface NSNumber (YYAdd)
|
||||
|
||||
/**
|
||||
Creates and returns an NSNumber object from a string.
|
||||
Valid format: @"12", @"12.345", @" -0xFF", @" .23e99 "...
|
||||
|
||||
@param string The string described an number.
|
||||
|
||||
@return an NSNumber when parse succeed, or nil if an error occurs.
|
||||
*/
|
||||
+ (nullable NSNumber *)numberWithString:(NSString *)string;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
63
Pods/YYCategories/YYCategories/Foundation/NSNumber+YYAdd.m
generated
Normal file
63
Pods/YYCategories/YYCategories/Foundation/NSNumber+YYAdd.m
generated
Normal file
@@ -0,0 +1,63 @@
|
||||
//
|
||||
// NSNumber+YYAdd.m
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 13/8/24.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import "NSNumber+YYAdd.h"
|
||||
#import "NSString+YYAdd.h"
|
||||
#import "YYCategoriesMacro.h"
|
||||
|
||||
YYSYNTH_DUMMY_CLASS(NSNumber_YYAdd)
|
||||
|
||||
|
||||
@implementation NSNumber (YYAdd)
|
||||
|
||||
+ (NSNumber *)numberWithString:(NSString *)string {
|
||||
NSString *str = [[string stringByTrim] lowercaseString];
|
||||
if (!str || !str.length) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
static NSDictionary *dic;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
dic = @{@"true" : @(YES),
|
||||
@"yes" : @(YES),
|
||||
@"false" : @(NO),
|
||||
@"no" : @(NO),
|
||||
@"nil" : [NSNull null],
|
||||
@"null" : [NSNull null],
|
||||
@"<null>" : [NSNull null]};
|
||||
});
|
||||
NSNumber *num = dic[str];
|
||||
if (num) {
|
||||
if (num == (id)[NSNull null]) return nil;
|
||||
return num;
|
||||
}
|
||||
|
||||
// hex number
|
||||
int sign = 0;
|
||||
if ([str hasPrefix:@"0x"]) sign = 1;
|
||||
else if ([str hasPrefix:@"-0x"]) sign = -1;
|
||||
if (sign != 0) {
|
||||
NSScanner *scan = [NSScanner scannerWithString:str];
|
||||
unsigned num = -1;
|
||||
BOOL suc = [scan scanHexInt:&num];
|
||||
if (suc)
|
||||
return [NSNumber numberWithLong:((long)num * sign)];
|
||||
else
|
||||
return nil;
|
||||
}
|
||||
// normal number
|
||||
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
|
||||
[formatter setNumberStyle:NSNumberFormatterDecimalStyle];
|
||||
return [formatter numberFromString:string];
|
||||
}
|
||||
|
||||
@end
|
||||
302
Pods/YYCategories/YYCategories/Foundation/NSObject+YYAdd.h
generated
Normal file
302
Pods/YYCategories/YYCategories/Foundation/NSObject+YYAdd.h
generated
Normal file
@@ -0,0 +1,302 @@
|
||||
//
|
||||
// NSObject+YYAdd.h
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 14/10/8.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
Common tasks for NSObject.
|
||||
*/
|
||||
@interface NSObject (YYAdd)
|
||||
|
||||
|
||||
#pragma mark - Sending messages with variable parameters
|
||||
///=============================================================================
|
||||
/// @name Sending messages with variable parameters
|
||||
///=============================================================================
|
||||
|
||||
/**
|
||||
Sends a specified message to the receiver and returns the result of the message.
|
||||
|
||||
@param sel A selector identifying the message to send. If the selector is
|
||||
NULL or unrecognized, an NSInvalidArgumentException is raised.
|
||||
|
||||
@param ... Variable parameter list. Parameters type must correspond to the
|
||||
selector's method declaration, or unexpected results may occur.
|
||||
It doesn't support union or struct which is larger than 256 bytes.
|
||||
|
||||
@return An object that is the result of the message.
|
||||
|
||||
@discussion The selector's return value will be wrap as NSNumber or NSValue
|
||||
if the selector's `return type` is not object. It always returns nil
|
||||
if the selector's `return type` is void.
|
||||
|
||||
Sample Code:
|
||||
|
||||
// no variable args
|
||||
[view performSelectorWithArgs:@selector(removeFromSuperView)];
|
||||
|
||||
// variable arg is not object
|
||||
[view performSelectorWithArgs:@selector(setCenter:), CGPointMake(0, 0)];
|
||||
|
||||
// perform and return object
|
||||
UIImage *image = [UIImage.class performSelectorWithArgs:@selector(imageWithData:scale:), data, 2.0];
|
||||
|
||||
// perform and return wrapped number
|
||||
NSNumber *lengthValue = [@"hello" performSelectorWithArgs:@selector(length)];
|
||||
NSUInteger length = lengthValue.unsignedIntegerValue;
|
||||
|
||||
// perform and return wrapped struct
|
||||
NSValue *frameValue = [view performSelectorWithArgs:@selector(frame)];
|
||||
CGRect frame = frameValue.CGRectValue;
|
||||
*/
|
||||
- (nullable id)performSelectorWithArgs:(SEL)sel, ...;
|
||||
|
||||
/**
|
||||
Invokes a method of the receiver on the current thread using the default mode after a delay.
|
||||
|
||||
@warning It can't cancelled by previous request.
|
||||
|
||||
@param sel A selector identifying the message to send. If the selector is
|
||||
NULL or unrecognized, an NSInvalidArgumentException is raised immediately.
|
||||
|
||||
@param delay The minimum time before which the message is sent. Specifying
|
||||
a delay of 0 does not necessarily cause the selector to be
|
||||
performed immediately. The selector is still queued on the
|
||||
thread's run loop and performed as soon as possible.
|
||||
|
||||
@param ... Variable parameter list. Parameters type must correspond to the
|
||||
selector's method declaration, or unexpected results may occur.
|
||||
It doesn't support union or struct which is larger than 256 bytes.
|
||||
|
||||
Sample Code:
|
||||
|
||||
// no variable args
|
||||
[view performSelectorWithArgs:@selector(removeFromSuperView) afterDelay:2.0];
|
||||
|
||||
// variable arg is not object
|
||||
[view performSelectorWithArgs:@selector(setCenter:), afterDelay:0, CGPointMake(0, 0)];
|
||||
*/
|
||||
- (void)performSelectorWithArgs:(SEL)sel afterDelay:(NSTimeInterval)delay, ...;
|
||||
|
||||
/**
|
||||
Invokes a method of the receiver on the main thread using the default mode.
|
||||
|
||||
@param sel A selector identifying the message to send. If the selector is
|
||||
NULL or unrecognized, an NSInvalidArgumentException is raised.
|
||||
|
||||
@param wait A Boolean that specifies whether the current thread blocks until
|
||||
after the specified selector is performed on the receiver on the
|
||||
specified thread. Specify YES to block this thread; otherwise,
|
||||
specify NO to have this method return immediately.
|
||||
|
||||
@param ... Variable parameter list. Parameters type must correspond to the
|
||||
selector's method declaration, or unexpected results may occur.
|
||||
It doesn't support union or struct which is larger than 256 bytes.
|
||||
|
||||
@return While @a wait is YES, it returns object that is the result of
|
||||
the message. Otherwise return nil;
|
||||
|
||||
@discussion The selector's return value will be wrap as NSNumber or NSValue
|
||||
if the selector's `return type` is not object. It always returns nil
|
||||
if the selector's `return type` is void, or @a wait is YES.
|
||||
|
||||
Sample Code:
|
||||
|
||||
// no variable args
|
||||
[view performSelectorWithArgsOnMainThread:@selector(removeFromSuperView), waitUntilDone:NO];
|
||||
|
||||
// variable arg is not object
|
||||
[view performSelectorWithArgsOnMainThread:@selector(setCenter:), waitUntilDone:NO, CGPointMake(0, 0)];
|
||||
*/
|
||||
- (nullable id)performSelectorWithArgsOnMainThread:(SEL)sel waitUntilDone:(BOOL)wait, ...;
|
||||
|
||||
/**
|
||||
Invokes a method of the receiver on the specified thread using the default mode.
|
||||
|
||||
@param sel A selector identifying the message to send. If the selector is
|
||||
NULL or unrecognized, an NSInvalidArgumentException is raised.
|
||||
|
||||
@param thread The thread on which to execute aSelector.
|
||||
|
||||
@param wait A Boolean that specifies whether the current thread blocks until
|
||||
after the specified selector is performed on the receiver on the
|
||||
specified thread. Specify YES to block this thread; otherwise,
|
||||
specify NO to have this method return immediately.
|
||||
|
||||
@param ... Variable parameter list. Parameters type must correspond to the
|
||||
selector's method declaration, or unexpected results may occur.
|
||||
It doesn't support union or struct which is larger than 256 bytes.
|
||||
|
||||
@return While @a wait is YES, it returns object that is the result of
|
||||
the message. Otherwise return nil;
|
||||
|
||||
@discussion The selector's return value will be wrap as NSNumber or NSValue
|
||||
if the selector's `return type` is not object. It always returns nil
|
||||
if the selector's `return type` is void, or @a wait is YES.
|
||||
|
||||
Sample Code:
|
||||
|
||||
[view performSelectorWithArgs:@selector(removeFromSuperView) onThread:mainThread waitUntilDone:NO];
|
||||
|
||||
[array performSelectorWithArgs:@selector(sortUsingComparator:)
|
||||
onThread:backgroundThread
|
||||
waitUntilDone:NO, ^NSComparisonResult(NSNumber *num1, NSNumber *num2) {
|
||||
return [num2 compare:num2];
|
||||
}];
|
||||
*/
|
||||
- (nullable id)performSelectorWithArgs:(SEL)sel onThread:(NSThread *)thread waitUntilDone:(BOOL)wait, ...;
|
||||
|
||||
/**
|
||||
Invokes a method of the receiver on a new background thread.
|
||||
|
||||
@param sel A selector identifying the message to send. If the selector is
|
||||
NULL or unrecognized, an NSInvalidArgumentException is raised.
|
||||
|
||||
@param ... Variable parameter list. Parameters type must correspond to the
|
||||
selector's method declaration, or unexpected results may occur.
|
||||
It doesn't support union or struct which is larger than 256 bytes.
|
||||
|
||||
@discussion This method creates a new thread in your application, putting
|
||||
your application into multithreaded mode if it was not already.
|
||||
The method represented by sel must set up the thread environment
|
||||
just as you would for any other new thread in your program.
|
||||
|
||||
Sample Code:
|
||||
|
||||
[array performSelectorWithArgsInBackground:@selector(sortUsingComparator:),
|
||||
^NSComparisonResult(NSNumber *num1, NSNumber *num2) {
|
||||
return [num2 compare:num2];
|
||||
}];
|
||||
*/
|
||||
- (void)performSelectorWithArgsInBackground:(SEL)sel, ...;
|
||||
|
||||
/**
|
||||
Invokes a method of the receiver on the current thread after a delay.
|
||||
|
||||
@warning arc-performSelector-leaks
|
||||
|
||||
@param sel A selector that identifies the method to invoke. The method should
|
||||
not have a significant return value and should take no argument.
|
||||
If the selector is NULL or unrecognized,
|
||||
an NSInvalidArgumentException is raised after the delay.
|
||||
|
||||
@param delay The minimum time before which the message is sent. Specifying a
|
||||
delay of 0 does not necessarily cause the selector to be performed
|
||||
immediately. The selector is still queued on the thread's run loop
|
||||
and performed as soon as possible.
|
||||
|
||||
@discussion This method sets up a timer to perform the aSelector message on
|
||||
the current thread's run loop. The timer is configured to run in
|
||||
the default mode (NSDefaultRunLoopMode). When the timer fires, the
|
||||
thread attempts to dequeue the message from the run loop and
|
||||
perform the selector. It succeeds if the run loop is running and
|
||||
in the default mode; otherwise, the timer waits until the run loop
|
||||
is in the default mode.
|
||||
*/
|
||||
- (void)performSelector:(SEL)sel afterDelay:(NSTimeInterval)delay;
|
||||
|
||||
|
||||
#pragma mark - Swap method (Swizzling)
|
||||
///=============================================================================
|
||||
/// @name Swap method (Swizzling)
|
||||
///=============================================================================
|
||||
|
||||
/**
|
||||
Swap two instance method's implementation in one class. Dangerous, be careful.
|
||||
|
||||
@param originalSel Selector 1.
|
||||
@param newSel Selector 2.
|
||||
@return YES if swizzling succeed; otherwise, NO.
|
||||
*/
|
||||
+ (BOOL)swizzleInstanceMethod:(SEL)originalSel with:(SEL)newSel;
|
||||
|
||||
/**
|
||||
Swap two class method's implementation in one class. Dangerous, be careful.
|
||||
|
||||
@param originalSel Selector 1.
|
||||
@param newSel Selector 2.
|
||||
@return YES if swizzling succeed; otherwise, NO.
|
||||
*/
|
||||
+ (BOOL)swizzleClassMethod:(SEL)originalSel with:(SEL)newSel;
|
||||
|
||||
|
||||
#pragma mark - Associate value
|
||||
///=============================================================================
|
||||
/// @name Associate value
|
||||
///=============================================================================
|
||||
|
||||
/**
|
||||
Associate one object to `self`, as if it was a strong property (strong, nonatomic).
|
||||
|
||||
@param value The object to associate.
|
||||
@param key The pointer to get value from `self`.
|
||||
*/
|
||||
- (void)setAssociateValue:(nullable id)value withKey:(void *)key;
|
||||
|
||||
/**
|
||||
Associate one object to `self`, as if it was a weak property (week, nonatomic).
|
||||
|
||||
@param value The object to associate.
|
||||
@param key The pointer to get value from `self`.
|
||||
*/
|
||||
- (void)setAssociateWeakValue:(nullable id)value withKey:(void *)key;
|
||||
|
||||
/**
|
||||
Get the associated value from `self`.
|
||||
|
||||
@param key The pointer to get value from `self`.
|
||||
*/
|
||||
- (nullable id)getAssociatedValueForKey:(void *)key;
|
||||
|
||||
/**
|
||||
Remove all associated values.
|
||||
*/
|
||||
- (void)removeAssociatedValues;
|
||||
|
||||
|
||||
#pragma mark - Others
|
||||
///=============================================================================
|
||||
/// @name Others
|
||||
///=============================================================================
|
||||
|
||||
/**
|
||||
Returns the class name in NSString.
|
||||
*/
|
||||
+ (NSString *)className;
|
||||
|
||||
/**
|
||||
Returns the class name in NSString.
|
||||
|
||||
@discussion Apple has implemented this method in NSObject(NSLayoutConstraintCallsThis),
|
||||
but did not make it public.
|
||||
*/
|
||||
- (NSString *)className;
|
||||
|
||||
/**
|
||||
Returns a copy of the instance with `NSKeyedArchiver` and ``NSKeyedUnarchiver``.
|
||||
Returns nil if an error occurs.
|
||||
*/
|
||||
- (nullable id)deepCopy;
|
||||
|
||||
/**
|
||||
Returns a copy of the instance use archiver and unarchiver.
|
||||
Returns nil if an error occurs.
|
||||
|
||||
@param archiver NSKeyedArchiver class or any class inherited.
|
||||
@param unarchiver NSKeyedUnarchiver clsas or any class inherited.
|
||||
*/
|
||||
- (nullable id)deepCopyWithArchiver:(Class)archiver unarchiver:(Class)unarchiver;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
396
Pods/YYCategories/YYCategories/Foundation/NSObject+YYAdd.m
generated
Normal file
396
Pods/YYCategories/YYCategories/Foundation/NSObject+YYAdd.m
generated
Normal file
@@ -0,0 +1,396 @@
|
||||
//
|
||||
// NSObject+YYAdd.m
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 14/10/8.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import "NSObject+YYAdd.h"
|
||||
#import "YYCategoriesMacro.h"
|
||||
#import <objc/objc.h>
|
||||
#import <objc/runtime.h>
|
||||
|
||||
YYSYNTH_DUMMY_CLASS(NSObject_YYAdd)
|
||||
|
||||
|
||||
@implementation NSObject (YYAdd)
|
||||
|
||||
/*
|
||||
NSInvocation is much slower than objc_msgSend()...
|
||||
Do not use it if you have performance issues.
|
||||
*/
|
||||
|
||||
#define INIT_INV(_last_arg_, _return_) \
|
||||
NSMethodSignature * sig = [self methodSignatureForSelector:sel]; \
|
||||
if (!sig) { [self doesNotRecognizeSelector:sel]; return _return_; } \
|
||||
NSInvocation *inv = [NSInvocation invocationWithMethodSignature:sig]; \
|
||||
if (!inv) { [self doesNotRecognizeSelector:sel]; return _return_; } \
|
||||
[inv setTarget:self]; \
|
||||
[inv setSelector:sel]; \
|
||||
va_list args; \
|
||||
va_start(args, _last_arg_); \
|
||||
[NSObject setInv:inv withSig:sig andArgs:args]; \
|
||||
va_end(args);
|
||||
|
||||
- (id)performSelectorWithArgs:(SEL)sel, ...{
|
||||
INIT_INV(sel, nil);
|
||||
[inv invoke];
|
||||
return [NSObject getReturnFromInv:inv withSig:sig];
|
||||
}
|
||||
|
||||
- (void)performSelectorWithArgs:(SEL)sel afterDelay:(NSTimeInterval)delay, ...{
|
||||
INIT_INV(delay, );
|
||||
[inv retainArguments];
|
||||
[inv performSelector:@selector(invoke) withObject:nil afterDelay:delay];
|
||||
}
|
||||
|
||||
- (id)performSelectorWithArgsOnMainThread:(SEL)sel waitUntilDone:(BOOL)wait, ...{
|
||||
INIT_INV(wait, nil);
|
||||
if (!wait) [inv retainArguments];
|
||||
[inv performSelectorOnMainThread:@selector(invoke) withObject:nil waitUntilDone:wait];
|
||||
return wait ? [NSObject getReturnFromInv:inv withSig:sig] : nil;
|
||||
}
|
||||
|
||||
- (id)performSelectorWithArgs:(SEL)sel onThread:(NSThread *)thr waitUntilDone:(BOOL)wait, ...{
|
||||
INIT_INV(wait, nil);
|
||||
if (!wait) [inv retainArguments];
|
||||
[inv performSelector:@selector(invoke) onThread:thr withObject:nil waitUntilDone:wait];
|
||||
return wait ? [NSObject getReturnFromInv:inv withSig:sig] : nil;
|
||||
}
|
||||
|
||||
- (void)performSelectorWithArgsInBackground:(SEL)sel, ...{
|
||||
INIT_INV(sel, );
|
||||
[inv retainArguments];
|
||||
[inv performSelectorInBackground:@selector(invoke) withObject:nil];
|
||||
}
|
||||
|
||||
#undef INIT_INV
|
||||
|
||||
+ (id)getReturnFromInv:(NSInvocation *)inv withSig:(NSMethodSignature *)sig {
|
||||
NSUInteger length = [sig methodReturnLength];
|
||||
if (length == 0) return nil;
|
||||
|
||||
char *type = (char *)[sig methodReturnType];
|
||||
while (*type == 'r' || // const
|
||||
*type == 'n' || // in
|
||||
*type == 'N' || // inout
|
||||
*type == 'o' || // out
|
||||
*type == 'O' || // bycopy
|
||||
*type == 'R' || // byref
|
||||
*type == 'V') { // oneway
|
||||
type++; // cutoff useless prefix
|
||||
}
|
||||
|
||||
#define return_with_number(_type_) \
|
||||
do { \
|
||||
_type_ ret; \
|
||||
[inv getReturnValue:&ret]; \
|
||||
return @(ret); \
|
||||
} while (0)
|
||||
|
||||
switch (*type) {
|
||||
case 'v': return nil; // void
|
||||
case 'B': return_with_number(bool);
|
||||
case 'c': return_with_number(char);
|
||||
case 'C': return_with_number(unsigned char);
|
||||
case 's': return_with_number(short);
|
||||
case 'S': return_with_number(unsigned short);
|
||||
case 'i': return_with_number(int);
|
||||
case 'I': return_with_number(unsigned int);
|
||||
case 'l': return_with_number(int);
|
||||
case 'L': return_with_number(unsigned int);
|
||||
case 'q': return_with_number(long long);
|
||||
case 'Q': return_with_number(unsigned long long);
|
||||
case 'f': return_with_number(float);
|
||||
case 'd': return_with_number(double);
|
||||
case 'D': { // long double
|
||||
long double ret;
|
||||
[inv getReturnValue:&ret];
|
||||
return [NSNumber numberWithDouble:ret];
|
||||
};
|
||||
|
||||
case '@': { // id
|
||||
id ret = nil;
|
||||
[inv getReturnValue:&ret];
|
||||
return ret;
|
||||
};
|
||||
|
||||
case '#': { // Class
|
||||
Class ret = nil;
|
||||
[inv getReturnValue:&ret];
|
||||
return ret;
|
||||
};
|
||||
|
||||
default: { // struct / union / SEL / void* / unknown
|
||||
const char *objCType = [sig methodReturnType];
|
||||
char *buf = calloc(1, length);
|
||||
if (!buf) return nil;
|
||||
[inv getReturnValue:buf];
|
||||
NSValue *value = [NSValue valueWithBytes:buf objCType:objCType];
|
||||
free(buf);
|
||||
return value;
|
||||
};
|
||||
}
|
||||
#undef return_with_number
|
||||
}
|
||||
|
||||
+ (void)setInv:(NSInvocation *)inv withSig:(NSMethodSignature *)sig andArgs:(va_list)args {
|
||||
NSUInteger count = [sig numberOfArguments];
|
||||
for (int index = 2; index < count; index++) {
|
||||
char *type = (char *)[sig getArgumentTypeAtIndex:index];
|
||||
while (*type == 'r' || // const
|
||||
*type == 'n' || // in
|
||||
*type == 'N' || // inout
|
||||
*type == 'o' || // out
|
||||
*type == 'O' || // bycopy
|
||||
*type == 'R' || // byref
|
||||
*type == 'V') { // oneway
|
||||
type++; // cutoff useless prefix
|
||||
}
|
||||
|
||||
BOOL unsupportedType = NO;
|
||||
switch (*type) {
|
||||
case 'v': // 1: void
|
||||
case 'B': // 1: bool
|
||||
case 'c': // 1: char / BOOL
|
||||
case 'C': // 1: unsigned char
|
||||
case 's': // 2: short
|
||||
case 'S': // 2: unsigned short
|
||||
case 'i': // 4: int / NSInteger(32bit)
|
||||
case 'I': // 4: unsigned int / NSUInteger(32bit)
|
||||
case 'l': // 4: long(32bit)
|
||||
case 'L': // 4: unsigned long(32bit)
|
||||
{ // 'char' and 'short' will be promoted to 'int'.
|
||||
int arg = va_arg(args, int);
|
||||
[inv setArgument:&arg atIndex:index];
|
||||
} break;
|
||||
|
||||
case 'q': // 8: long long / long(64bit) / NSInteger(64bit)
|
||||
case 'Q': // 8: unsigned long long / unsigned long(64bit) / NSUInteger(64bit)
|
||||
{
|
||||
long long arg = va_arg(args, long long);
|
||||
[inv setArgument:&arg atIndex:index];
|
||||
} break;
|
||||
|
||||
case 'f': // 4: float / CGFloat(32bit)
|
||||
{ // 'float' will be promoted to 'double'.
|
||||
double arg = va_arg(args, double);
|
||||
float argf = arg;
|
||||
[inv setArgument:&argf atIndex:index];
|
||||
} break;
|
||||
|
||||
case 'd': // 8: double / CGFloat(64bit)
|
||||
{
|
||||
double arg = va_arg(args, double);
|
||||
[inv setArgument:&arg atIndex:index];
|
||||
} break;
|
||||
|
||||
case 'D': // 16: long double
|
||||
{
|
||||
long double arg = va_arg(args, long double);
|
||||
[inv setArgument:&arg atIndex:index];
|
||||
} break;
|
||||
|
||||
case '*': // char *
|
||||
case '^': // pointer
|
||||
{
|
||||
void *arg = va_arg(args, void *);
|
||||
[inv setArgument:&arg atIndex:index];
|
||||
} break;
|
||||
|
||||
case ':': // SEL
|
||||
{
|
||||
SEL arg = va_arg(args, SEL);
|
||||
[inv setArgument:&arg atIndex:index];
|
||||
} break;
|
||||
|
||||
case '#': // Class
|
||||
{
|
||||
Class arg = va_arg(args, Class);
|
||||
[inv setArgument:&arg atIndex:index];
|
||||
} break;
|
||||
|
||||
case '@': // id
|
||||
{
|
||||
id arg = va_arg(args, id);
|
||||
[inv setArgument:&arg atIndex:index];
|
||||
} break;
|
||||
|
||||
case '{': // struct
|
||||
{
|
||||
if (strcmp(type, @encode(CGPoint)) == 0) {
|
||||
CGPoint arg = va_arg(args, CGPoint);
|
||||
[inv setArgument:&arg atIndex:index];
|
||||
} else if (strcmp(type, @encode(CGSize)) == 0) {
|
||||
CGSize arg = va_arg(args, CGSize);
|
||||
[inv setArgument:&arg atIndex:index];
|
||||
} else if (strcmp(type, @encode(CGRect)) == 0) {
|
||||
CGRect arg = va_arg(args, CGRect);
|
||||
[inv setArgument:&arg atIndex:index];
|
||||
} else if (strcmp(type, @encode(CGVector)) == 0) {
|
||||
CGVector arg = va_arg(args, CGVector);
|
||||
[inv setArgument:&arg atIndex:index];
|
||||
} else if (strcmp(type, @encode(CGAffineTransform)) == 0) {
|
||||
CGAffineTransform arg = va_arg(args, CGAffineTransform);
|
||||
[inv setArgument:&arg atIndex:index];
|
||||
} else if (strcmp(type, @encode(CATransform3D)) == 0) {
|
||||
CATransform3D arg = va_arg(args, CATransform3D);
|
||||
[inv setArgument:&arg atIndex:index];
|
||||
} else if (strcmp(type, @encode(NSRange)) == 0) {
|
||||
NSRange arg = va_arg(args, NSRange);
|
||||
[inv setArgument:&arg atIndex:index];
|
||||
} else if (strcmp(type, @encode(UIOffset)) == 0) {
|
||||
UIOffset arg = va_arg(args, UIOffset);
|
||||
[inv setArgument:&arg atIndex:index];
|
||||
} else if (strcmp(type, @encode(UIEdgeInsets)) == 0) {
|
||||
UIEdgeInsets arg = va_arg(args, UIEdgeInsets);
|
||||
[inv setArgument:&arg atIndex:index];
|
||||
} else {
|
||||
unsupportedType = YES;
|
||||
}
|
||||
} break;
|
||||
|
||||
case '(': // union
|
||||
{
|
||||
unsupportedType = YES;
|
||||
} break;
|
||||
|
||||
case '[': // array
|
||||
{
|
||||
unsupportedType = YES;
|
||||
} break;
|
||||
|
||||
default: // what?!
|
||||
{
|
||||
unsupportedType = YES;
|
||||
} break;
|
||||
}
|
||||
|
||||
if (unsupportedType) {
|
||||
// Try with some dummy type...
|
||||
|
||||
NSUInteger size = 0;
|
||||
NSGetSizeAndAlignment(type, &size, NULL);
|
||||
|
||||
#define case_size(_size_) \
|
||||
else if (size <= 4 * _size_ ) { \
|
||||
struct dummy { char tmp[4 * _size_]; }; \
|
||||
struct dummy arg = va_arg(args, struct dummy); \
|
||||
[inv setArgument:&arg atIndex:index]; \
|
||||
}
|
||||
if (size == 0) { }
|
||||
case_size( 1) case_size( 2) case_size( 3) case_size( 4)
|
||||
case_size( 5) case_size( 6) case_size( 7) case_size( 8)
|
||||
case_size( 9) case_size(10) case_size(11) case_size(12)
|
||||
case_size(13) case_size(14) case_size(15) case_size(16)
|
||||
case_size(17) case_size(18) case_size(19) case_size(20)
|
||||
case_size(21) case_size(22) case_size(23) case_size(24)
|
||||
case_size(25) case_size(26) case_size(27) case_size(28)
|
||||
case_size(29) case_size(30) case_size(31) case_size(32)
|
||||
case_size(33) case_size(34) case_size(35) case_size(36)
|
||||
case_size(37) case_size(38) case_size(39) case_size(40)
|
||||
case_size(41) case_size(42) case_size(43) case_size(44)
|
||||
case_size(45) case_size(46) case_size(47) case_size(48)
|
||||
case_size(49) case_size(50) case_size(51) case_size(52)
|
||||
case_size(53) case_size(54) case_size(55) case_size(56)
|
||||
case_size(57) case_size(58) case_size(59) case_size(60)
|
||||
case_size(61) case_size(62) case_size(63) case_size(64)
|
||||
else {
|
||||
/*
|
||||
Larger than 256 byte?! I don't want to deal with this stuff up...
|
||||
Ignore this argument.
|
||||
*/
|
||||
struct dummy {char tmp;};
|
||||
for (int i = 0; i < size; i++) va_arg(args, struct dummy);
|
||||
NSLog(@"YYCategories performSelectorWithArgs unsupported type:%s (%lu bytes)",
|
||||
[sig getArgumentTypeAtIndex:index],(unsigned long)size);
|
||||
}
|
||||
#undef case_size
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)performSelector:(SEL)selector afterDelay:(NSTimeInterval)delay {
|
||||
[self performSelector:selector withObject:nil afterDelay:delay];
|
||||
}
|
||||
|
||||
+ (BOOL)swizzleInstanceMethod:(SEL)originalSel with:(SEL)newSel {
|
||||
Method originalMethod = class_getInstanceMethod(self, originalSel);
|
||||
Method newMethod = class_getInstanceMethod(self, newSel);
|
||||
if (!originalMethod || !newMethod) return NO;
|
||||
|
||||
class_addMethod(self,
|
||||
originalSel,
|
||||
class_getMethodImplementation(self, originalSel),
|
||||
method_getTypeEncoding(originalMethod));
|
||||
class_addMethod(self,
|
||||
newSel,
|
||||
class_getMethodImplementation(self, newSel),
|
||||
method_getTypeEncoding(newMethod));
|
||||
|
||||
method_exchangeImplementations(class_getInstanceMethod(self, originalSel),
|
||||
class_getInstanceMethod(self, newSel));
|
||||
return YES;
|
||||
}
|
||||
|
||||
+ (BOOL)swizzleClassMethod:(SEL)originalSel with:(SEL)newSel {
|
||||
Class class = object_getClass(self);
|
||||
Method originalMethod = class_getInstanceMethod(class, originalSel);
|
||||
Method newMethod = class_getInstanceMethod(class, newSel);
|
||||
if (!originalMethod || !newMethod) return NO;
|
||||
method_exchangeImplementations(originalMethod, newMethod);
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)setAssociateValue:(id)value withKey:(void *)key {
|
||||
objc_setAssociatedObject(self, key, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
|
||||
- (void)setAssociateWeakValue:(id)value withKey:(void *)key {
|
||||
objc_setAssociatedObject(self, key, value, OBJC_ASSOCIATION_ASSIGN);
|
||||
}
|
||||
|
||||
- (void)removeAssociatedValues {
|
||||
objc_removeAssociatedObjects(self);
|
||||
}
|
||||
|
||||
- (id)getAssociatedValueForKey:(void *)key {
|
||||
return objc_getAssociatedObject(self, key);
|
||||
}
|
||||
|
||||
+ (NSString *)className {
|
||||
return NSStringFromClass(self);
|
||||
}
|
||||
|
||||
- (NSString *)className {
|
||||
return [NSString stringWithUTF8String:class_getName([self class])];
|
||||
}
|
||||
|
||||
- (id)deepCopy {
|
||||
id obj = nil;
|
||||
@try {
|
||||
obj = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:self]];
|
||||
}
|
||||
@catch (NSException *exception) {
|
||||
NSLog(@"%@", exception);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
- (id)deepCopyWithArchiver:(Class)archiver unarchiver:(Class)unarchiver {
|
||||
id obj = nil;
|
||||
@try {
|
||||
obj = [unarchiver unarchiveObjectWithData:[archiver archivedDataWithRootObject:self]];
|
||||
}
|
||||
@catch (NSException *exception) {
|
||||
NSLog(@"%@", exception);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
@end
|
||||
31
Pods/YYCategories/YYCategories/Foundation/NSObject+YYAddForARC.h
generated
Normal file
31
Pods/YYCategories/YYCategories/Foundation/NSObject+YYAddForARC.h
generated
Normal file
@@ -0,0 +1,31 @@
|
||||
//
|
||||
// NSObject+YYAddForARC.h
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 13/12/15.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
/**
|
||||
Debug method for NSObject when using ARC.
|
||||
*/
|
||||
@interface NSObject (YYAddForARC)
|
||||
|
||||
/// Same as `retain`
|
||||
- (instancetype)arcDebugRetain;
|
||||
|
||||
/// Same as `release`
|
||||
- (oneway void)arcDebugRelease;
|
||||
|
||||
/// Same as `autorelease`
|
||||
- (instancetype)arcDebugAutorelease;
|
||||
|
||||
/// Same as `retainCount`
|
||||
- (NSUInteger)arcDebugRetainCount;
|
||||
|
||||
@end
|
||||
40
Pods/YYCategories/YYCategories/Foundation/NSObject+YYAddForARC.m
generated
Normal file
40
Pods/YYCategories/YYCategories/Foundation/NSObject+YYAddForARC.m
generated
Normal file
@@ -0,0 +1,40 @@
|
||||
//
|
||||
// NSObject+YYAddForARC.m
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 13/12/15.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import "NSObject+YYAddForARC.h"
|
||||
|
||||
@interface NSObject_YYAddForARC : NSObject @end
|
||||
@implementation NSObject_YYAddForARC @end
|
||||
|
||||
#if __has_feature(objc_arc)
|
||||
#error This file must be compiled without ARC. Specify the -fno-objc-arc flag to this file.
|
||||
#endif
|
||||
|
||||
|
||||
@implementation NSObject (YYAddForARC)
|
||||
|
||||
- (instancetype)arcDebugRetain {
|
||||
return [self retain];
|
||||
}
|
||||
|
||||
- (oneway void)arcDebugRelease {
|
||||
[self release];
|
||||
}
|
||||
|
||||
- (instancetype)arcDebugAutorelease {
|
||||
return [self autorelease];
|
||||
}
|
||||
|
||||
- (NSUInteger)arcDebugRetainCount {
|
||||
return [self retainCount];
|
||||
}
|
||||
|
||||
@end
|
||||
54
Pods/YYCategories/YYCategories/Foundation/NSObject+YYAddForKVO.h
generated
Normal file
54
Pods/YYCategories/YYCategories/Foundation/NSObject+YYAddForKVO.h
generated
Normal file
@@ -0,0 +1,54 @@
|
||||
//
|
||||
// NSObject+YYAddForKVO.h
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 14/10/15.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
Observer with block (KVO).
|
||||
*/
|
||||
@interface NSObject (YYAddForKVO)
|
||||
|
||||
/**
|
||||
Registers a block to receive KVO notifications for the specified key-path
|
||||
relative to the receiver.
|
||||
|
||||
@discussion The block and block captured objects are retained. Call
|
||||
`removeObserverBlocksForKeyPath:` or `removeObserverBlocks` to release.
|
||||
|
||||
@param keyPath The key path, relative to the receiver, of the property to
|
||||
observe. This value must not be nil.
|
||||
|
||||
@param block The block to register for KVO notifications.
|
||||
*/
|
||||
- (void)addObserverBlockForKeyPath:(NSString*)keyPath
|
||||
block:(void (^)(id _Nonnull obj, id _Nonnull oldVal, id _Nonnull newVal))block;
|
||||
|
||||
/**
|
||||
Stops all blocks (associated by `addObserverBlockForKeyPath:block:`) from
|
||||
receiving change notifications for the property specified by a given key-path
|
||||
relative to the receiver, and release these blocks.
|
||||
|
||||
@param keyPath A key-path, relative to the receiver, for which blocks is
|
||||
registered to receive KVO change notifications.
|
||||
*/
|
||||
- (void)removeObserverBlocksForKeyPath:(NSString*)keyPath;
|
||||
|
||||
/**
|
||||
Stops all blocks (associated by `addObserverBlockForKeyPath:block:`) from
|
||||
receiving change notifications, and release these blocks.
|
||||
*/
|
||||
- (void)removeObserverBlocks;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
110
Pods/YYCategories/YYCategories/Foundation/NSObject+YYAddForKVO.m
generated
Normal file
110
Pods/YYCategories/YYCategories/Foundation/NSObject+YYAddForKVO.m
generated
Normal file
@@ -0,0 +1,110 @@
|
||||
//
|
||||
// NSObject+YYAddForKVO.m
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 14/10/15.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import "NSObject+YYAddForKVO.h"
|
||||
#import "YYCategoriesMacro.h"
|
||||
#import <objc/objc.h>
|
||||
#import <objc/runtime.h>
|
||||
|
||||
YYSYNTH_DUMMY_CLASS(NSObject_YYAddForKVO)
|
||||
|
||||
|
||||
|
||||
|
||||
static const int block_key;
|
||||
|
||||
@interface _YYNSObjectKVOBlockTarget : NSObject
|
||||
|
||||
@property (nonatomic, copy) void (^block)(__weak id obj, id oldVal, id newVal);
|
||||
|
||||
- (id)initWithBlock:(void (^)(__weak id obj, id oldVal, id newVal))block;
|
||||
|
||||
@end
|
||||
|
||||
@implementation _YYNSObjectKVOBlockTarget
|
||||
|
||||
- (id)initWithBlock:(void (^)(__weak id obj, id oldVal, id newVal))block {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.block = block;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
|
||||
if (!self.block) return;
|
||||
|
||||
BOOL isPrior = [[change objectForKey:NSKeyValueChangeNotificationIsPriorKey] boolValue];
|
||||
if (isPrior) return;
|
||||
|
||||
NSKeyValueChange changeKind = [[change objectForKey:NSKeyValueChangeKindKey] integerValue];
|
||||
if (changeKind != NSKeyValueChangeSetting) return;
|
||||
|
||||
id oldVal = [change objectForKey:NSKeyValueChangeOldKey];
|
||||
if (oldVal == [NSNull null]) oldVal = nil;
|
||||
|
||||
id newVal = [change objectForKey:NSKeyValueChangeNewKey];
|
||||
if (newVal == [NSNull null]) newVal = nil;
|
||||
|
||||
self.block(object, oldVal, newVal);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
@implementation NSObject (YYAddForKVO)
|
||||
|
||||
- (void)addObserverBlockForKeyPath:(NSString *)keyPath block:(void (^)(__weak id obj, id oldVal, id newVal))block {
|
||||
if (!keyPath || !block) return;
|
||||
_YYNSObjectKVOBlockTarget *target = [[_YYNSObjectKVOBlockTarget alloc] initWithBlock:block];
|
||||
NSMutableDictionary *dic = [self _yy_allNSObjectObserverBlocks];
|
||||
NSMutableArray *arr = dic[keyPath];
|
||||
if (!arr) {
|
||||
arr = [NSMutableArray new];
|
||||
dic[keyPath] = arr;
|
||||
}
|
||||
[arr addObject:target];
|
||||
[self addObserver:target forKeyPath:keyPath options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:NULL];
|
||||
}
|
||||
|
||||
- (void)removeObserverBlocksForKeyPath:(NSString *)keyPath {
|
||||
if (!keyPath) return;
|
||||
NSMutableDictionary *dic = [self _yy_allNSObjectObserverBlocks];
|
||||
NSMutableArray *arr = dic[keyPath];
|
||||
[arr enumerateObjectsUsingBlock: ^(id obj, NSUInteger idx, BOOL *stop) {
|
||||
[self removeObserver:obj forKeyPath:keyPath];
|
||||
}];
|
||||
|
||||
[dic removeObjectForKey:keyPath];
|
||||
}
|
||||
|
||||
- (void)removeObserverBlocks {
|
||||
NSMutableDictionary *dic = [self _yy_allNSObjectObserverBlocks];
|
||||
[dic enumerateKeysAndObjectsUsingBlock: ^(NSString *key, NSArray *arr, BOOL *stop) {
|
||||
[arr enumerateObjectsUsingBlock: ^(id obj, NSUInteger idx, BOOL *stop) {
|
||||
[self removeObserver:obj forKeyPath:key];
|
||||
}];
|
||||
}];
|
||||
|
||||
[dic removeAllObjects];
|
||||
}
|
||||
|
||||
- (NSMutableDictionary *)_yy_allNSObjectObserverBlocks {
|
||||
NSMutableDictionary *targets = objc_getAssociatedObject(self, &block_key);
|
||||
if (!targets) {
|
||||
targets = [NSMutableDictionary new];
|
||||
objc_setAssociatedObject(self, &block_key, targets, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
return targets;
|
||||
}
|
||||
|
||||
@end
|
||||
409
Pods/YYCategories/YYCategories/Foundation/NSString+YYAdd.h
generated
Normal file
409
Pods/YYCategories/YYCategories/Foundation/NSString+YYAdd.h
generated
Normal file
@@ -0,0 +1,409 @@
|
||||
//
|
||||
// NSString+YYAdd.h
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 13/4/3.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
Provide hash, encrypt, encode and some common method for 'NSString'.
|
||||
*/
|
||||
@interface NSString (YYAdd)
|
||||
|
||||
#pragma mark - Hash
|
||||
///=============================================================================
|
||||
/// @name Hash
|
||||
///=============================================================================
|
||||
|
||||
/**
|
||||
Returns a lowercase NSString for md2 hash.
|
||||
*/
|
||||
- (nullable NSString *)md2String;
|
||||
|
||||
/**
|
||||
Returns a lowercase NSString for md4 hash.
|
||||
*/
|
||||
- (nullable NSString *)md4String;
|
||||
|
||||
/**
|
||||
Returns a lowercase NSString for md5 hash.
|
||||
*/
|
||||
- (nullable NSString *)md5String;
|
||||
|
||||
/**
|
||||
Returns a lowercase NSString for sha1 hash.
|
||||
*/
|
||||
- (nullable NSString *)sha1String;
|
||||
|
||||
/**
|
||||
Returns a lowercase NSString for sha224 hash.
|
||||
*/
|
||||
- (nullable NSString *)sha224String;
|
||||
|
||||
/**
|
||||
Returns a lowercase NSString for sha256 hash.
|
||||
*/
|
||||
- (nullable NSString *)sha256String;
|
||||
|
||||
/**
|
||||
Returns a lowercase NSString for sha384 hash.
|
||||
*/
|
||||
- (nullable NSString *)sha384String;
|
||||
|
||||
/**
|
||||
Returns a lowercase NSString for sha512 hash.
|
||||
*/
|
||||
- (nullable NSString *)sha512String;
|
||||
|
||||
/**
|
||||
Returns a lowercase NSString for hmac using algorithm md5 with key.
|
||||
@param key The hmac key.
|
||||
*/
|
||||
- (nullable NSString *)hmacMD5StringWithKey:(NSString *)key;
|
||||
|
||||
/**
|
||||
Returns a lowercase NSString for hmac using algorithm sha1 with key.
|
||||
@param key The hmac key.
|
||||
*/
|
||||
- (nullable NSString *)hmacSHA1StringWithKey:(NSString *)key;
|
||||
|
||||
/**
|
||||
Returns a lowercase NSString for hmac using algorithm sha224 with key.
|
||||
@param key The hmac key.
|
||||
*/
|
||||
- (nullable NSString *)hmacSHA224StringWithKey:(NSString *)key;
|
||||
|
||||
/**
|
||||
Returns a lowercase NSString for hmac using algorithm sha256 with key.
|
||||
@param key The hmac key.
|
||||
*/
|
||||
- (nullable NSString *)hmacSHA256StringWithKey:(NSString *)key;
|
||||
|
||||
/**
|
||||
Returns a lowercase NSString for hmac using algorithm sha384 with key.
|
||||
@param key The hmac key.
|
||||
*/
|
||||
- (nullable NSString *)hmacSHA384StringWithKey:(NSString *)key;
|
||||
|
||||
/**
|
||||
Returns a lowercase NSString for hmac using algorithm sha512 with key.
|
||||
@param key The hmac key.
|
||||
*/
|
||||
- (nullable NSString *)hmacSHA512StringWithKey:(NSString *)key;
|
||||
|
||||
/**
|
||||
Returns a lowercase NSString for crc32 hash.
|
||||
*/
|
||||
- (nullable NSString *)crc32String;
|
||||
|
||||
|
||||
#pragma mark - Encode and decode
|
||||
///=============================================================================
|
||||
/// @name Encode and decode
|
||||
///=============================================================================
|
||||
|
||||
/**
|
||||
Returns an NSString for base64 encoded.
|
||||
*/
|
||||
- (nullable NSString *)base64EncodedString;
|
||||
|
||||
/**
|
||||
Returns an NSString from base64 encoded string.
|
||||
@param base64Encoding The encoded string.
|
||||
*/
|
||||
+ (nullable NSString *)stringWithBase64EncodedString:(NSString *)base64EncodedString;
|
||||
|
||||
/**
|
||||
URL encode a string in utf-8.
|
||||
@return the encoded string.
|
||||
*/
|
||||
- (NSString *)stringByURLEncode;
|
||||
|
||||
/**
|
||||
URL decode a string in utf-8.
|
||||
@return the decoded string.
|
||||
*/
|
||||
- (NSString *)stringByURLDecode;
|
||||
|
||||
/**
|
||||
Escape commmon HTML to Entity.
|
||||
Example: "a<b" will be escape to "a<b".
|
||||
*/
|
||||
- (NSString *)stringByEscapingHTML;
|
||||
|
||||
#pragma mark - Drawing
|
||||
///=============================================================================
|
||||
/// @name Drawing
|
||||
///=============================================================================
|
||||
|
||||
/**
|
||||
Returns the size of the string if it were rendered with the specified constraints.
|
||||
|
||||
@param font The font to use for computing the string size.
|
||||
|
||||
@param size The maximum acceptable size for the string. This value is
|
||||
used to calculate where line breaks and wrapping would occur.
|
||||
|
||||
@param lineBreakMode The line break options for computing the size of the string.
|
||||
For a list of possible values, see NSLineBreakMode.
|
||||
|
||||
@return The width and height of the resulting string's bounding box.
|
||||
These values may be rounded up to the nearest whole number.
|
||||
*/
|
||||
- (CGSize)sizeForFont:(UIFont *)font size:(CGSize)size mode:(NSLineBreakMode)lineBreakMode;
|
||||
|
||||
/**
|
||||
Returns the width of the string if it were to be rendered with the specified
|
||||
font on a single line.
|
||||
|
||||
@param font The font to use for computing the string width.
|
||||
|
||||
@return The width of the resulting string's bounding box. These values may be
|
||||
rounded up to the nearest whole number.
|
||||
*/
|
||||
- (CGFloat)widthForFont:(UIFont *)font;
|
||||
|
||||
/**
|
||||
Returns the height of the string if it were rendered with the specified constraints.
|
||||
|
||||
@param font The font to use for computing the string size.
|
||||
|
||||
@param width The maximum acceptable width for the string. This value is used
|
||||
to calculate where line breaks and wrapping would occur.
|
||||
|
||||
@return The height of the resulting string's bounding box. These values
|
||||
may be rounded up to the nearest whole number.
|
||||
*/
|
||||
- (CGFloat)heightForFont:(UIFont *)font width:(CGFloat)width;
|
||||
|
||||
|
||||
#pragma mark - Regular Expression
|
||||
///=============================================================================
|
||||
/// @name Regular Expression
|
||||
///=============================================================================
|
||||
|
||||
/**
|
||||
Whether it can match the regular expression
|
||||
|
||||
@param regex The regular expression
|
||||
@param options The matching options to report.
|
||||
@return YES if can match the regex; otherwise, NO.
|
||||
*/
|
||||
- (BOOL)matchesRegex:(NSString *)regex options:(NSRegularExpressionOptions)options;
|
||||
|
||||
/**
|
||||
Match the regular expression, and executes a given block using each object in the matches.
|
||||
|
||||
@param regex The regular expression
|
||||
@param options The matching options to report.
|
||||
@param block The block to apply to elements in the array of matches.
|
||||
The block takes four arguments:
|
||||
match: The match substring.
|
||||
matchRange: The matching options.
|
||||
stop: A reference to a Boolean value. The block can set the value
|
||||
to YES to stop further processing of the array. The stop
|
||||
argument is an out-only argument. You should only ever set
|
||||
this Boolean to YES within the Block.
|
||||
*/
|
||||
- (void)enumerateRegexMatches:(NSString *)regex
|
||||
options:(NSRegularExpressionOptions)options
|
||||
usingBlock:(void (^)(NSString *match, NSRange matchRange, BOOL *stop))block;
|
||||
|
||||
/**
|
||||
Returns a new string containing matching regular expressions replaced with the template string.
|
||||
|
||||
@param regex The regular expression
|
||||
@param options The matching options to report.
|
||||
@param replacement The substitution template used when replacing matching instances.
|
||||
|
||||
@return A string with matching regular expressions replaced by the template string.
|
||||
*/
|
||||
- (NSString *)stringByReplacingRegex:(NSString *)regex
|
||||
options:(NSRegularExpressionOptions)options
|
||||
withString:(NSString *)replacement;
|
||||
|
||||
|
||||
#pragma mark - NSNumber Compatible
|
||||
///=============================================================================
|
||||
/// @name NSNumber Compatible
|
||||
///=============================================================================
|
||||
|
||||
// Now you can use NSString as a NSNumber.
|
||||
@property (readonly) char charValue;
|
||||
@property (readonly) unsigned char unsignedCharValue;
|
||||
@property (readonly) short shortValue;
|
||||
@property (readonly) unsigned short unsignedShortValue;
|
||||
@property (readonly) unsigned int unsignedIntValue;
|
||||
@property (readonly) long longValue;
|
||||
@property (readonly) unsigned long unsignedLongValue;
|
||||
@property (readonly) unsigned long long unsignedLongLongValue;
|
||||
@property (readonly) NSUInteger unsignedIntegerValue;
|
||||
|
||||
|
||||
#pragma mark - Utilities
|
||||
///=============================================================================
|
||||
/// @name Utilities
|
||||
///=============================================================================
|
||||
|
||||
/**
|
||||
Returns a new UUID NSString
|
||||
e.g. "D1178E50-2A4D-4F1F-9BD3-F6AAB00E06B1"
|
||||
*/
|
||||
+ (NSString *)stringWithUUID;
|
||||
|
||||
/**
|
||||
Returns a string containing the characters in a given UTF32Char.
|
||||
|
||||
@param char32 A UTF-32 character.
|
||||
@return A new string, or nil if the character is invalid.
|
||||
*/
|
||||
+ (NSString *)stringWithUTF32Char:(UTF32Char)char32;
|
||||
|
||||
/**
|
||||
Returns a string containing the characters in a given UTF32Char array.
|
||||
|
||||
@param char32 An array of UTF-32 character.
|
||||
@param length The character count in array.
|
||||
@return A new string, or nil if an error occurs.
|
||||
*/
|
||||
+ (NSString *)stringWithUTF32Chars:(const UTF32Char *)char32 length:(NSUInteger)length;
|
||||
|
||||
/**
|
||||
Enumerates the unicode characters (UTF-32) in the specified range of the string.
|
||||
|
||||
@param range The range within the string to enumerate substrings.
|
||||
@param block The block executed for the enumeration. The block takes four arguments:
|
||||
char32: The unicode character.
|
||||
range: The range in receiver. If the range.length is 1, the character is in BMP;
|
||||
otherwise (range.length is 2) the character is in none-BMP Plane and stored
|
||||
by a surrogate pair in the receiver.
|
||||
stop: A reference to a Boolean value that the block can use to stop the enumeration
|
||||
by setting *stop = YES; it should not touch *stop otherwise.
|
||||
*/
|
||||
- (void)enumerateUTF32CharInRange:(NSRange)range usingBlock:(void (^)(UTF32Char char32, NSRange range, BOOL *stop))block;
|
||||
|
||||
/**
|
||||
Trim blank characters (space and newline) in head and tail.
|
||||
@return the trimmed string.
|
||||
*/
|
||||
- (NSString *)stringByTrim;
|
||||
|
||||
/**
|
||||
Add scale modifier to the file name (without path extension),
|
||||
From @"name" to @"name@2x".
|
||||
|
||||
e.g.
|
||||
<table>
|
||||
<tr><th>Before </th><th>After(scale:2)</th></tr>
|
||||
<tr><td>"icon" </td><td>"icon@2x" </td></tr>
|
||||
<tr><td>"icon " </td><td>"icon @2x" </td></tr>
|
||||
<tr><td>"icon.top" </td><td>"icon.top@2x" </td></tr>
|
||||
<tr><td>"/p/name" </td><td>"/p/name@2x" </td></tr>
|
||||
<tr><td>"/path/" </td><td>"/path/" </td></tr>
|
||||
</table>
|
||||
|
||||
@param scale Resource scale.
|
||||
@return String by add scale modifier, or just return if it's not end with file name.
|
||||
*/
|
||||
- (NSString *)stringByAppendingNameScale:(CGFloat)scale;
|
||||
|
||||
/**
|
||||
Add scale modifier to the file path (with path extension),
|
||||
From @"name.png" to @"name@2x.png".
|
||||
|
||||
e.g.
|
||||
<table>
|
||||
<tr><th>Before </th><th>After(scale:2)</th></tr>
|
||||
<tr><td>"icon.png" </td><td>"icon@2x.png" </td></tr>
|
||||
<tr><td>"icon..png"</td><td>"icon.@2x.png"</td></tr>
|
||||
<tr><td>"icon" </td><td>"icon@2x" </td></tr>
|
||||
<tr><td>"icon " </td><td>"icon @2x" </td></tr>
|
||||
<tr><td>"icon." </td><td>"icon.@2x" </td></tr>
|
||||
<tr><td>"/p/name" </td><td>"/p/name@2x" </td></tr>
|
||||
<tr><td>"/path/" </td><td>"/path/" </td></tr>
|
||||
</table>
|
||||
|
||||
@param scale Resource scale.
|
||||
@return String by add scale modifier, or just return if it's not end with file name.
|
||||
*/
|
||||
- (NSString *)stringByAppendingPathScale:(CGFloat)scale;
|
||||
|
||||
/**
|
||||
Return the path scale.
|
||||
|
||||
e.g.
|
||||
<table>
|
||||
<tr><th>Path </th><th>Scale </th></tr>
|
||||
<tr><td>"icon.png" </td><td>1 </td></tr>
|
||||
<tr><td>"icon@2x.png" </td><td>2 </td></tr>
|
||||
<tr><td>"icon@2.5x.png" </td><td>2.5 </td></tr>
|
||||
<tr><td>"icon@2x" </td><td>1 </td></tr>
|
||||
<tr><td>"icon@2x..png" </td><td>1 </td></tr>
|
||||
<tr><td>"icon@2x.png/" </td><td>1 </td></tr>
|
||||
</table>
|
||||
*/
|
||||
- (CGFloat)pathScale;
|
||||
|
||||
/**
|
||||
nil, @"", @" ", @"\n" will Returns NO; otherwise Returns YES.
|
||||
*/
|
||||
- (BOOL)isNotBlank;
|
||||
|
||||
/**
|
||||
Returns YES if the target string is contained within the receiver.
|
||||
@param string A string to test the the receiver.
|
||||
|
||||
@discussion Apple has implemented this method in iOS8.
|
||||
*/
|
||||
- (BOOL)containsString:(NSString *)string;
|
||||
|
||||
/**
|
||||
Returns YES if the target CharacterSet is contained within the receiver.
|
||||
@param set A character set to test the the receiver.
|
||||
*/
|
||||
- (BOOL)containsCharacterSet:(NSCharacterSet *)set;
|
||||
|
||||
/**
|
||||
Try to parse this string and returns an `NSNumber`.
|
||||
@return Returns an `NSNumber` if parse succeed, or nil if an error occurs.
|
||||
*/
|
||||
- (NSNumber *)numberValue;
|
||||
|
||||
/**
|
||||
Returns an NSData using UTF-8 encoding.
|
||||
*/
|
||||
- (NSData *)dataValue;
|
||||
|
||||
/**
|
||||
Returns NSMakeRange(0, self.length).
|
||||
*/
|
||||
- (NSRange)rangeOfAll;
|
||||
|
||||
/**
|
||||
Returns an NSDictionary/NSArray which is decoded from receiver.
|
||||
Returns nil if an error occurs.
|
||||
|
||||
e.g. NSString: @"{"name":"a","count":2}" => NSDictionary: @[@"name":@"a",@"count":@2]
|
||||
*/
|
||||
- (id)jsonValueDecoded;
|
||||
|
||||
/**
|
||||
Create a string from the file in main bundle (similar to [UIImage imageNamed:]).
|
||||
|
||||
@param name The file name (in main bundle).
|
||||
|
||||
@return A new string create from the file in UTF-8 character encoding.
|
||||
*/
|
||||
+ (NSString *)stringNamed:(NSString *)name;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
414
Pods/YYCategories/YYCategories/Foundation/NSString+YYAdd.m
generated
Normal file
414
Pods/YYCategories/YYCategories/Foundation/NSString+YYAdd.m
generated
Normal file
@@ -0,0 +1,414 @@
|
||||
//
|
||||
// NSString+YYAdd.m
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 13/4/3.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import "NSString+YYAdd.h"
|
||||
#import "NSData+YYAdd.h"
|
||||
#import "NSNumber+YYAdd.h"
|
||||
#import "UIDevice+YYAdd.h"
|
||||
#import "YYCategoriesMacro.h"
|
||||
|
||||
YYSYNTH_DUMMY_CLASS(NSString_YYAdd)
|
||||
|
||||
|
||||
@implementation NSString (YYAdd)
|
||||
|
||||
- (NSString *)md2String {
|
||||
return [[self dataUsingEncoding:NSUTF8StringEncoding] md2String];
|
||||
}
|
||||
|
||||
- (NSString *)md4String {
|
||||
return [[self dataUsingEncoding:NSUTF8StringEncoding] md4String];
|
||||
}
|
||||
|
||||
- (NSString *)md5String {
|
||||
return [[self dataUsingEncoding:NSUTF8StringEncoding] md5String];
|
||||
}
|
||||
|
||||
- (NSString *)sha1String {
|
||||
return [[self dataUsingEncoding:NSUTF8StringEncoding] sha1String];
|
||||
}
|
||||
|
||||
- (NSString *)sha224String {
|
||||
return [[self dataUsingEncoding:NSUTF8StringEncoding] sha224String];
|
||||
}
|
||||
|
||||
- (NSString *)sha256String {
|
||||
return [[self dataUsingEncoding:NSUTF8StringEncoding] sha256String];
|
||||
}
|
||||
|
||||
- (NSString *)sha384String {
|
||||
return [[self dataUsingEncoding:NSUTF8StringEncoding] sha384String];
|
||||
}
|
||||
|
||||
- (NSString *)sha512String {
|
||||
return [[self dataUsingEncoding:NSUTF8StringEncoding] sha512String];
|
||||
}
|
||||
|
||||
- (NSString *)crc32String {
|
||||
return [[self dataUsingEncoding:NSUTF8StringEncoding] crc32String];
|
||||
}
|
||||
|
||||
- (NSString *)hmacMD5StringWithKey:(NSString *)key {
|
||||
return [[self dataUsingEncoding:NSUTF8StringEncoding]
|
||||
hmacMD5StringWithKey:key];
|
||||
}
|
||||
|
||||
- (NSString *)hmacSHA1StringWithKey:(NSString *)key {
|
||||
return [[self dataUsingEncoding:NSUTF8StringEncoding]
|
||||
hmacSHA1StringWithKey:key];
|
||||
}
|
||||
|
||||
- (NSString *)hmacSHA224StringWithKey:(NSString *)key {
|
||||
return [[self dataUsingEncoding:NSUTF8StringEncoding]
|
||||
hmacSHA224StringWithKey:key];
|
||||
}
|
||||
|
||||
- (NSString *)hmacSHA256StringWithKey:(NSString *)key {
|
||||
return [[self dataUsingEncoding:NSUTF8StringEncoding]
|
||||
hmacSHA256StringWithKey:key];
|
||||
}
|
||||
|
||||
- (NSString *)hmacSHA384StringWithKey:(NSString *)key {
|
||||
return [[self dataUsingEncoding:NSUTF8StringEncoding]
|
||||
hmacSHA384StringWithKey:key];
|
||||
}
|
||||
|
||||
- (NSString *)hmacSHA512StringWithKey:(NSString *)key {
|
||||
return [[self dataUsingEncoding:NSUTF8StringEncoding]
|
||||
hmacSHA512StringWithKey:key];
|
||||
}
|
||||
|
||||
- (NSString *)base64EncodedString {
|
||||
return [[self dataUsingEncoding:NSUTF8StringEncoding] base64EncodedString];
|
||||
}
|
||||
|
||||
+ (NSString *)stringWithBase64EncodedString:(NSString *)base64EncodedString {
|
||||
NSData *data = [NSData dataWithBase64EncodedString:base64EncodedString];
|
||||
return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
|
||||
}
|
||||
|
||||
- (NSString *)stringByURLEncode {
|
||||
if ([self respondsToSelector:@selector(stringByAddingPercentEncodingWithAllowedCharacters:)]) {
|
||||
/**
|
||||
AFNetworking/AFURLRequestSerialization.m
|
||||
|
||||
Returns a percent-escaped string following RFC 3986 for a query string key or value.
|
||||
RFC 3986 states that the following characters are "reserved" characters.
|
||||
- General Delimiters: ":", "#", "[", "]", "@", "?", "/"
|
||||
- Sub-Delimiters: "!", "$", "&", "'", "(", ")", "*", "+", ",", ";", "="
|
||||
In RFC 3986 - Section 3.4, it states that the "?" and "/" characters should not be escaped to allow
|
||||
query strings to include a URL. Therefore, all "reserved" characters with the exception of "?" and "/"
|
||||
should be percent-escaped in the query string.
|
||||
- parameter string: The string to be percent-escaped.
|
||||
- returns: The percent-escaped string.
|
||||
*/
|
||||
static NSString * const kAFCharactersGeneralDelimitersToEncode = @":#[]@"; // does not include "?" or "/" due to RFC 3986 - Section 3.4
|
||||
static NSString * const kAFCharactersSubDelimitersToEncode = @"!$&'()*+,;=";
|
||||
|
||||
NSMutableCharacterSet * allowedCharacterSet = [[NSCharacterSet URLQueryAllowedCharacterSet] mutableCopy];
|
||||
[allowedCharacterSet removeCharactersInString:[kAFCharactersGeneralDelimitersToEncode stringByAppendingString:kAFCharactersSubDelimitersToEncode]];
|
||||
static NSUInteger const batchSize = 50;
|
||||
|
||||
NSUInteger index = 0;
|
||||
NSMutableString *escaped = @"".mutableCopy;
|
||||
|
||||
while (index < self.length) {
|
||||
NSUInteger length = MIN(self.length - index, batchSize);
|
||||
NSRange range = NSMakeRange(index, length);
|
||||
// To avoid breaking up character sequences such as 👴🏻👮🏽
|
||||
range = [self rangeOfComposedCharacterSequencesForRange:range];
|
||||
NSString *substring = [self substringWithRange:range];
|
||||
NSString *encoded = [substring stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacterSet];
|
||||
[escaped appendString:encoded];
|
||||
|
||||
index += range.length;
|
||||
}
|
||||
return escaped;
|
||||
} else {
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
CFStringEncoding cfEncoding = CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding);
|
||||
NSString *encoded = (__bridge_transfer NSString *)
|
||||
CFURLCreateStringByAddingPercentEscapes(
|
||||
kCFAllocatorDefault,
|
||||
(__bridge CFStringRef)self,
|
||||
NULL,
|
||||
CFSTR("!#$&'()*+,/:;=?@[]"),
|
||||
cfEncoding);
|
||||
return encoded;
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString *)stringByURLDecode {
|
||||
if ([self respondsToSelector:@selector(stringByRemovingPercentEncoding)]) {
|
||||
return [self stringByRemovingPercentEncoding];
|
||||
} else {
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
CFStringEncoding en = CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding);
|
||||
NSString *decoded = [self stringByReplacingOccurrencesOfString:@"+"
|
||||
withString:@" "];
|
||||
decoded = (__bridge_transfer NSString *)
|
||||
CFURLCreateStringByReplacingPercentEscapesUsingEncoding(
|
||||
NULL,
|
||||
(__bridge CFStringRef)decoded,
|
||||
CFSTR(""),
|
||||
en);
|
||||
return decoded;
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString *)stringByEscapingHTML {
|
||||
NSUInteger len = self.length;
|
||||
if (!len) return self;
|
||||
|
||||
unichar *buf = malloc(sizeof(unichar) * len);
|
||||
if (!buf) return self;
|
||||
[self getCharacters:buf range:NSMakeRange(0, len)];
|
||||
|
||||
NSMutableString *result = [NSMutableString string];
|
||||
for (int i = 0; i < len; i++) {
|
||||
unichar c = buf[i];
|
||||
NSString *esc = nil;
|
||||
switch (c) {
|
||||
case 34: esc = @"""; break;
|
||||
case 38: esc = @"&"; break;
|
||||
case 39: esc = @"'"; break;
|
||||
case 60: esc = @"<"; break;
|
||||
case 62: esc = @">"; break;
|
||||
default: break;
|
||||
}
|
||||
if (esc) {
|
||||
[result appendString:esc];
|
||||
} else {
|
||||
CFStringAppendCharacters((CFMutableStringRef)result, &c, 1);
|
||||
}
|
||||
}
|
||||
free(buf);
|
||||
return result;
|
||||
}
|
||||
|
||||
- (CGSize)sizeForFont:(UIFont *)font size:(CGSize)size mode:(NSLineBreakMode)lineBreakMode {
|
||||
CGSize result;
|
||||
if (!font) font = [UIFont systemFontOfSize:12];
|
||||
if ([self respondsToSelector:@selector(boundingRectWithSize:options:attributes:context:)]) {
|
||||
NSMutableDictionary *attr = [NSMutableDictionary new];
|
||||
attr[NSFontAttributeName] = font;
|
||||
if (lineBreakMode != NSLineBreakByWordWrapping) {
|
||||
NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new];
|
||||
paragraphStyle.lineBreakMode = lineBreakMode;
|
||||
attr[NSParagraphStyleAttributeName] = paragraphStyle;
|
||||
}
|
||||
CGRect rect = [self boundingRectWithSize:size
|
||||
options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
|
||||
attributes:attr context:nil];
|
||||
result = rect.size;
|
||||
} else {
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
result = [self sizeWithFont:font constrainedToSize:size lineBreakMode:lineBreakMode];
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
- (CGFloat)widthForFont:(UIFont *)font {
|
||||
CGSize size = [self sizeForFont:font size:CGSizeMake(HUGE, HUGE) mode:NSLineBreakByWordWrapping];
|
||||
return size.width;
|
||||
}
|
||||
|
||||
- (CGFloat)heightForFont:(UIFont *)font width:(CGFloat)width {
|
||||
CGSize size = [self sizeForFont:font size:CGSizeMake(width, HUGE) mode:NSLineBreakByWordWrapping];
|
||||
return size.height;
|
||||
}
|
||||
|
||||
- (BOOL)matchesRegex:(NSString *)regex options:(NSRegularExpressionOptions)options {
|
||||
NSRegularExpression *pattern = [NSRegularExpression regularExpressionWithPattern:regex options:options error:NULL];
|
||||
if (!pattern) return NO;
|
||||
return ([pattern numberOfMatchesInString:self options:0 range:NSMakeRange(0, self.length)] > 0);
|
||||
}
|
||||
|
||||
- (void)enumerateRegexMatches:(NSString *)regex
|
||||
options:(NSRegularExpressionOptions)options
|
||||
usingBlock:(void (^)(NSString *match, NSRange matchRange, BOOL *stop))block {
|
||||
if (regex.length == 0 || !block) return;
|
||||
NSRegularExpression *pattern = [NSRegularExpression regularExpressionWithPattern:regex options:options error:nil];
|
||||
if (!regex) return;
|
||||
[pattern enumerateMatchesInString:self options:kNilOptions range:NSMakeRange(0, self.length) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
|
||||
block([self substringWithRange:result.range], result.range, stop);
|
||||
}];
|
||||
}
|
||||
|
||||
- (NSString *)stringByReplacingRegex:(NSString *)regex
|
||||
options:(NSRegularExpressionOptions)options
|
||||
withString:(NSString *)replacement; {
|
||||
NSRegularExpression *pattern = [NSRegularExpression regularExpressionWithPattern:regex options:options error:nil];
|
||||
if (!pattern) return self;
|
||||
return [pattern stringByReplacingMatchesInString:self options:0 range:NSMakeRange(0, [self length]) withTemplate:replacement];
|
||||
}
|
||||
|
||||
- (char)charValue {
|
||||
return self.numberValue.charValue;
|
||||
}
|
||||
|
||||
- (unsigned char) unsignedCharValue {
|
||||
return self.numberValue.unsignedCharValue;
|
||||
}
|
||||
|
||||
- (short) shortValue {
|
||||
return self.numberValue.shortValue;
|
||||
}
|
||||
|
||||
- (unsigned short) unsignedShortValue {
|
||||
return self.numberValue.unsignedShortValue;
|
||||
}
|
||||
|
||||
- (unsigned int) unsignedIntValue {
|
||||
return self.numberValue.unsignedIntValue;
|
||||
}
|
||||
|
||||
- (long) longValue {
|
||||
return self.numberValue.longValue;
|
||||
}
|
||||
|
||||
- (unsigned long) unsignedLongValue {
|
||||
return self.numberValue.unsignedLongValue;
|
||||
}
|
||||
|
||||
- (unsigned long long) unsignedLongLongValue {
|
||||
return self.numberValue.unsignedLongLongValue;
|
||||
}
|
||||
|
||||
- (NSUInteger) unsignedIntegerValue {
|
||||
return self.numberValue.unsignedIntegerValue;
|
||||
}
|
||||
|
||||
|
||||
+ (NSString *)stringWithUUID {
|
||||
CFUUIDRef uuid = CFUUIDCreate(NULL);
|
||||
CFStringRef string = CFUUIDCreateString(NULL, uuid);
|
||||
CFRelease(uuid);
|
||||
return (__bridge_transfer NSString *)string;
|
||||
}
|
||||
|
||||
+ (NSString *)stringWithUTF32Char:(UTF32Char)char32 {
|
||||
char32 = NSSwapHostIntToLittle(char32);
|
||||
return [[NSString alloc] initWithBytes:&char32 length:4 encoding:NSUTF32LittleEndianStringEncoding];
|
||||
}
|
||||
|
||||
+ (NSString *)stringWithUTF32Chars:(const UTF32Char *)char32 length:(NSUInteger)length {
|
||||
return [[NSString alloc] initWithBytes:(const void *)char32
|
||||
length:length * 4
|
||||
encoding:NSUTF32LittleEndianStringEncoding];
|
||||
}
|
||||
|
||||
- (void)enumerateUTF32CharInRange:(NSRange)range usingBlock:(void (^)(UTF32Char char32, NSRange range, BOOL *stop))block {
|
||||
NSString *str = self;
|
||||
if (range.location != 0 || range.length != self.length) {
|
||||
str = [self substringWithRange:range];
|
||||
}
|
||||
NSUInteger len = [str lengthOfBytesUsingEncoding:NSUTF32StringEncoding] / 4;
|
||||
UTF32Char *char32 = (UTF32Char *)[str cStringUsingEncoding:NSUTF32LittleEndianStringEncoding];
|
||||
if (len == 0 || char32 == NULL) return;
|
||||
|
||||
NSUInteger location = 0;
|
||||
BOOL stop = NO;
|
||||
NSRange subRange;
|
||||
UTF32Char oneChar;
|
||||
|
||||
for (NSUInteger i = 0; i < len; i++) {
|
||||
oneChar = char32[i];
|
||||
subRange = NSMakeRange(location, oneChar > 0xFFFF ? 2 : 1);
|
||||
block(oneChar, subRange, &stop);
|
||||
if (stop) return;
|
||||
location += subRange.length;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString *)stringByTrim {
|
||||
NSCharacterSet *set = [NSCharacterSet whitespaceAndNewlineCharacterSet];
|
||||
return [self stringByTrimmingCharactersInSet:set];
|
||||
}
|
||||
|
||||
- (NSString *)stringByAppendingNameScale:(CGFloat)scale {
|
||||
if (fabs(scale - 1) <= __FLT_EPSILON__ || self.length == 0 || [self hasSuffix:@"/"]) return self.copy;
|
||||
return [self stringByAppendingFormat:@"@%@x", @(scale)];
|
||||
}
|
||||
|
||||
- (NSString *)stringByAppendingPathScale:(CGFloat)scale {
|
||||
if (fabs(scale - 1) <= __FLT_EPSILON__ || self.length == 0 || [self hasSuffix:@"/"]) return self.copy;
|
||||
NSString *ext = self.pathExtension;
|
||||
NSRange extRange = NSMakeRange(self.length - ext.length, 0);
|
||||
if (ext.length > 0) extRange.location -= 1;
|
||||
NSString *scaleStr = [NSString stringWithFormat:@"@%@x", @(scale)];
|
||||
return [self stringByReplacingCharactersInRange:extRange withString:scaleStr];
|
||||
}
|
||||
|
||||
- (CGFloat)pathScale {
|
||||
if (self.length == 0 || [self hasSuffix:@"/"]) return 1;
|
||||
NSString *name = self.stringByDeletingPathExtension;
|
||||
__block CGFloat scale = 1;
|
||||
[name enumerateRegexMatches:@"@[0-9]+\\.?[0-9]*x$" options:NSRegularExpressionAnchorsMatchLines usingBlock: ^(NSString *match, NSRange matchRange, BOOL *stop) {
|
||||
scale = [match substringWithRange:NSMakeRange(1, match.length - 2)].doubleValue;
|
||||
}];
|
||||
return scale;
|
||||
}
|
||||
|
||||
- (BOOL)isNotBlank {
|
||||
NSCharacterSet *blank = [NSCharacterSet whitespaceAndNewlineCharacterSet];
|
||||
for (NSInteger i = 0; i < self.length; ++i) {
|
||||
unichar c = [self characterAtIndex:i];
|
||||
if (![blank characterIsMember:c]) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)containsString:(NSString *)string {
|
||||
if (string == nil) return NO;
|
||||
return [self rangeOfString:string].location != NSNotFound;
|
||||
}
|
||||
|
||||
- (BOOL)containsCharacterSet:(NSCharacterSet *)set {
|
||||
if (set == nil) return NO;
|
||||
return [self rangeOfCharacterFromSet:set].location != NSNotFound;
|
||||
}
|
||||
|
||||
- (NSNumber *)numberValue {
|
||||
return [NSNumber numberWithString:self];
|
||||
}
|
||||
|
||||
- (NSData *)dataValue {
|
||||
return [self dataUsingEncoding:NSUTF8StringEncoding];
|
||||
}
|
||||
|
||||
- (NSRange)rangeOfAll {
|
||||
return NSMakeRange(0, self.length);
|
||||
}
|
||||
|
||||
- (id)jsonValueDecoded {
|
||||
return [[self dataValue] jsonValueDecoded];
|
||||
}
|
||||
|
||||
+ (NSString *)stringNamed:(NSString *)name {
|
||||
NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:@""];
|
||||
NSString *str = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:NULL];
|
||||
if (!str) {
|
||||
path = [[NSBundle mainBundle] pathForResource:name ofType:@"txt"];
|
||||
str = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:NULL];
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
@end
|
||||
25
Pods/YYCategories/YYCategories/Foundation/NSThread+YYAdd.h
generated
Normal file
25
Pods/YYCategories/YYCategories/Foundation/NSThread+YYAdd.h
generated
Normal file
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// NSThread+YYAdd.h
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 15/7/3.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface NSThread (YYAdd)
|
||||
|
||||
/**
|
||||
Add an autorelease pool to current runloop for current thread.
|
||||
|
||||
@discussion If you create your own thread (NSThread/pthread), and you use
|
||||
runloop to manage your task, you may use this method to add an autorelease pool
|
||||
to the runloop. Its behavior is the same as the main thread's autorelease pool.
|
||||
*/
|
||||
+ (void)addAutoreleasePoolToCurrentRunloop;
|
||||
|
||||
@end
|
||||
107
Pods/YYCategories/YYCategories/Foundation/NSThread+YYAdd.m
generated
Normal file
107
Pods/YYCategories/YYCategories/Foundation/NSThread+YYAdd.m
generated
Normal file
@@ -0,0 +1,107 @@
|
||||
//
|
||||
// NSThread+YYAdd.h
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 15/7/3.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import "NSThread+YYAdd.h"
|
||||
#import <CoreFoundation/CoreFoundation.h>
|
||||
|
||||
@interface NSThread_YYAdd : NSObject @end
|
||||
@implementation NSThread_YYAdd @end
|
||||
|
||||
#if __has_feature(objc_arc)
|
||||
#error This file must be compiled without ARC. Specify the -fno-objc-arc flag to this file.
|
||||
#endif
|
||||
|
||||
static NSString *const YYNSThreadAutoleasePoolKey = @"YYNSThreadAutoleasePoolKey";
|
||||
static NSString *const YYNSThreadAutoleasePoolStackKey = @"YYNSThreadAutoleasePoolStackKey";
|
||||
|
||||
static const void *PoolStackRetainCallBack(CFAllocatorRef allocator, const void *value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
static void PoolStackReleaseCallBack(CFAllocatorRef allocator, const void *value) {
|
||||
CFRelease((CFTypeRef)value);
|
||||
}
|
||||
|
||||
|
||||
static inline void YYAutoreleasePoolPush() {
|
||||
NSMutableDictionary *dic = [NSThread currentThread].threadDictionary;
|
||||
NSMutableArray *poolStack = dic[YYNSThreadAutoleasePoolStackKey];
|
||||
|
||||
if (!poolStack) {
|
||||
/*
|
||||
do not retain pool on push,
|
||||
but release on pop to avoid memory analyze warning
|
||||
*/
|
||||
CFArrayCallBacks callbacks = {0};
|
||||
callbacks.retain = PoolStackRetainCallBack;
|
||||
callbacks.release = PoolStackReleaseCallBack;
|
||||
poolStack = (id)CFArrayCreateMutable(CFAllocatorGetDefault(), 0, &callbacks);
|
||||
dic[YYNSThreadAutoleasePoolStackKey] = poolStack;
|
||||
CFRelease(poolStack);
|
||||
}
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; //< create
|
||||
[poolStack addObject:pool]; // push
|
||||
}
|
||||
|
||||
static inline void YYAutoreleasePoolPop() {
|
||||
NSMutableDictionary *dic = [NSThread currentThread].threadDictionary;
|
||||
NSMutableArray *poolStack = dic[YYNSThreadAutoleasePoolStackKey];
|
||||
[poolStack removeLastObject]; // pop
|
||||
}
|
||||
|
||||
static void YYRunLoopAutoreleasePoolObserverCallBack(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info) {
|
||||
switch (activity) {
|
||||
case kCFRunLoopEntry: {
|
||||
YYAutoreleasePoolPush();
|
||||
} break;
|
||||
case kCFRunLoopBeforeWaiting: {
|
||||
YYAutoreleasePoolPop();
|
||||
YYAutoreleasePoolPush();
|
||||
} break;
|
||||
case kCFRunLoopExit: {
|
||||
YYAutoreleasePoolPop();
|
||||
} break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
static void YYRunloopAutoreleasePoolSetup() {
|
||||
CFRunLoopRef runloop = CFRunLoopGetCurrent();
|
||||
|
||||
CFRunLoopObserverRef pushObserver;
|
||||
pushObserver = CFRunLoopObserverCreate(CFAllocatorGetDefault(), kCFRunLoopEntry,
|
||||
true, // repeat
|
||||
-0x7FFFFFFF, // before other observers
|
||||
YYRunLoopAutoreleasePoolObserverCallBack, NULL);
|
||||
CFRunLoopAddObserver(runloop, pushObserver, kCFRunLoopCommonModes);
|
||||
CFRelease(pushObserver);
|
||||
|
||||
CFRunLoopObserverRef popObserver;
|
||||
popObserver = CFRunLoopObserverCreate(CFAllocatorGetDefault(), kCFRunLoopBeforeWaiting | kCFRunLoopExit,
|
||||
true, // repeat
|
||||
0x7FFFFFFF, // after other observers
|
||||
YYRunLoopAutoreleasePoolObserverCallBack, NULL);
|
||||
CFRunLoopAddObserver(runloop, popObserver, kCFRunLoopCommonModes);
|
||||
CFRelease(popObserver);
|
||||
}
|
||||
|
||||
@implementation NSThread (YYAdd)
|
||||
|
||||
+ (void)addAutoreleasePoolToCurrentRunloop {
|
||||
if ([NSThread isMainThread]) return; // The main thread already has autorelease pool.
|
||||
NSThread *thread = [self currentThread];
|
||||
if (!thread) return;
|
||||
if (thread.threadDictionary[YYNSThreadAutoleasePoolKey]) return; // already added
|
||||
YYRunloopAutoreleasePoolSetup();
|
||||
thread.threadDictionary[YYNSThreadAutoleasePoolKey] = YYNSThreadAutoleasePoolKey; // mark the state
|
||||
}
|
||||
|
||||
@end
|
||||
66
Pods/YYCategories/YYCategories/Foundation/NSTimer+YYAdd.h
generated
Normal file
66
Pods/YYCategories/YYCategories/Foundation/NSTimer+YYAdd.h
generated
Normal file
@@ -0,0 +1,66 @@
|
||||
//
|
||||
// NSTimer+YYAdd.h
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 14/15/11.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
Provides extensions for `NSTimer`.
|
||||
*/
|
||||
@interface NSTimer (YYAdd)
|
||||
|
||||
/**
|
||||
Creates and returns a new NSTimer object and schedules it on the current run
|
||||
loop in the default mode.
|
||||
|
||||
@discussion After seconds seconds have elapsed, the timer fires,
|
||||
sending the message aSelector to target.
|
||||
|
||||
@param seconds The number of seconds between firings of the timer. If seconds
|
||||
is less than or equal to 0.0, this method chooses the
|
||||
nonnegative value of 0.1 milliseconds instead.
|
||||
|
||||
@param block The block to invoke when the timer fires. The timer maintains
|
||||
a strong reference to the block until it (the timer) is invalidated.
|
||||
|
||||
@param repeats If YES, the timer will repeatedly reschedule itself until
|
||||
invalidated. If NO, the timer will be invalidated after it fires.
|
||||
|
||||
@return A new NSTimer object, configured according to the specified parameters.
|
||||
*/
|
||||
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)seconds block:(void (^)(NSTimer *timer))block repeats:(BOOL)repeats;
|
||||
|
||||
/**
|
||||
Creates and returns a new NSTimer object initialized with the specified block.
|
||||
|
||||
@discussion You must add the new timer to a run loop, using addTimer:forMode:.
|
||||
Then, after seconds have elapsed, the timer fires, invoking
|
||||
block. (If the timer is configured to repeat, there is no need
|
||||
to subsequently re-add the timer to the run loop.)
|
||||
|
||||
@param seconds The number of seconds between firings of the timer. If seconds
|
||||
is less than or equal to 0.0, this method chooses the
|
||||
nonnegative value of 0.1 milliseconds instead.
|
||||
|
||||
@param block The block to invoke when the timer fires. The timer instructs
|
||||
the block to maintain a strong reference to its arguments.
|
||||
|
||||
@param repeats If YES, the timer will repeatedly reschedule itself until
|
||||
invalidated. If NO, the timer will be invalidated after it fires.
|
||||
|
||||
@return A new NSTimer object, configured according to the specified parameters.
|
||||
*/
|
||||
+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)seconds block:(void (^)(NSTimer *timer))block repeats:(BOOL)repeats;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
35
Pods/YYCategories/YYCategories/Foundation/NSTimer+YYAdd.m
generated
Normal file
35
Pods/YYCategories/YYCategories/Foundation/NSTimer+YYAdd.m
generated
Normal file
@@ -0,0 +1,35 @@
|
||||
//
|
||||
// NSTimer+YYAdd.m
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 14/15/11.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import "NSTimer+YYAdd.h"
|
||||
#import "YYCategoriesMacro.h"
|
||||
|
||||
YYSYNTH_DUMMY_CLASS(NSTimer_YYAdd)
|
||||
|
||||
|
||||
@implementation NSTimer (YYAdd)
|
||||
|
||||
+ (void)_yy_ExecBlock:(NSTimer *)timer {
|
||||
if ([timer userInfo]) {
|
||||
void (^block)(NSTimer *timer) = (void (^)(NSTimer *timer))[timer userInfo];
|
||||
block(timer);
|
||||
}
|
||||
}
|
||||
|
||||
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)seconds block:(void (^)(NSTimer *timer))block repeats:(BOOL)repeats {
|
||||
return [NSTimer scheduledTimerWithTimeInterval:seconds target:self selector:@selector(_yy_ExecBlock:) userInfo:[block copy] repeats:repeats];
|
||||
}
|
||||
|
||||
+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)seconds block:(void (^)(NSTimer *timer))block repeats:(BOOL)repeats {
|
||||
return [NSTimer timerWithTimeInterval:seconds target:self selector:@selector(_yy_ExecBlock:) userInfo:[block copy] repeats:repeats];
|
||||
}
|
||||
|
||||
@end
|
||||
97
Pods/YYCategories/YYCategories/Quartz/CALayer+YYAdd.h
generated
Normal file
97
Pods/YYCategories/YYCategories/Quartz/CALayer+YYAdd.h
generated
Normal file
@@ -0,0 +1,97 @@
|
||||
//
|
||||
// CALayer+YYAdd.h
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 14/5/10.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
Provides extensions for `CALayer`.
|
||||
*/
|
||||
@interface CALayer (YYAdd)
|
||||
|
||||
/**
|
||||
Take snapshot without transform, image's size equals to bounds.
|
||||
*/
|
||||
- (nullable UIImage *)snapshotImage;
|
||||
|
||||
/**
|
||||
Take snapshot without transform, PDF's page size equals to bounds.
|
||||
*/
|
||||
- (nullable NSData *)snapshotPDF;
|
||||
|
||||
/**
|
||||
Shortcut to set the layer's shadow
|
||||
|
||||
@param color Shadow Color
|
||||
@param offset Shadow offset
|
||||
@param radius Shadow radius
|
||||
*/
|
||||
- (void)setLayerShadow:(UIColor*)color offset:(CGSize)offset radius:(CGFloat)radius;
|
||||
|
||||
/**
|
||||
Remove all sublayers.
|
||||
*/
|
||||
- (void)removeAllSublayers;
|
||||
|
||||
@property (nonatomic) CGFloat left; ///< Shortcut for frame.origin.x.
|
||||
@property (nonatomic) CGFloat top; ///< Shortcut for frame.origin.y
|
||||
@property (nonatomic) CGFloat right; ///< Shortcut for frame.origin.x + frame.size.width
|
||||
@property (nonatomic) CGFloat bottom; ///< Shortcut for frame.origin.y + frame.size.height
|
||||
@property (nonatomic) CGFloat width; ///< Shortcut for frame.size.width.
|
||||
@property (nonatomic) CGFloat height; ///< Shortcut for frame.size.height.
|
||||
@property (nonatomic) CGPoint center; ///< Shortcut for center.
|
||||
@property (nonatomic) CGFloat centerX; ///< Shortcut for center.x
|
||||
@property (nonatomic) CGFloat centerY; ///< Shortcut for center.y
|
||||
@property (nonatomic) CGPoint origin; ///< Shortcut for frame.origin.
|
||||
@property (nonatomic, getter=frameSize, setter=setFrameSize:) CGSize size; ///< Shortcut for frame.size.
|
||||
|
||||
|
||||
@property (nonatomic) CGFloat transformRotation; ///< key path "tranform.rotation"
|
||||
@property (nonatomic) CGFloat transformRotationX; ///< key path "tranform.rotation.x"
|
||||
@property (nonatomic) CGFloat transformRotationY; ///< key path "tranform.rotation.y"
|
||||
@property (nonatomic) CGFloat transformRotationZ; ///< key path "tranform.rotation.z"
|
||||
@property (nonatomic) CGFloat transformScale; ///< key path "tranform.scale"
|
||||
@property (nonatomic) CGFloat transformScaleX; ///< key path "tranform.scale.x"
|
||||
@property (nonatomic) CGFloat transformScaleY; ///< key path "tranform.scale.y"
|
||||
@property (nonatomic) CGFloat transformScaleZ; ///< key path "tranform.scale.z"
|
||||
@property (nonatomic) CGFloat transformTranslationX; ///< key path "tranform.translation.x"
|
||||
@property (nonatomic) CGFloat transformTranslationY; ///< key path "tranform.translation.y"
|
||||
@property (nonatomic) CGFloat transformTranslationZ; ///< key path "tranform.translation.z"
|
||||
|
||||
/**
|
||||
Shortcut for transform.m34, -1/1000 is a good value.
|
||||
It should be set before other transform shortcut.
|
||||
*/
|
||||
@property (nonatomic) CGFloat transformDepth;
|
||||
|
||||
/**
|
||||
Wrapper for `contentsGravity` property.
|
||||
*/
|
||||
@property (nonatomic) UIViewContentMode contentMode;
|
||||
|
||||
/**
|
||||
Add a fade animation to layer's contents when the contents is changed.
|
||||
|
||||
@param duration Animation duration
|
||||
@param curve Animation curve.
|
||||
*/
|
||||
- (void)addFadeAnimationWithDuration:(NSTimeInterval)duration curve:(UIViewAnimationCurve)curve;
|
||||
|
||||
/**
|
||||
Cancel fade animation which is added with "-addFadeAnimationWithDuration:curve:".
|
||||
*/
|
||||
- (void)removePreviousFadeAnimation;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
324
Pods/YYCategories/YYCategories/Quartz/CALayer+YYAdd.m
generated
Normal file
324
Pods/YYCategories/YYCategories/Quartz/CALayer+YYAdd.m
generated
Normal file
@@ -0,0 +1,324 @@
|
||||
//
|
||||
// CALayer+YYAdd.m
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 14/5/10.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import "CALayer+YYAdd.h"
|
||||
#import "YYCategoriesMacro.h"
|
||||
#import "YYCGUtilities.h"
|
||||
|
||||
YYSYNTH_DUMMY_CLASS(CALayer_YYAdd)
|
||||
|
||||
|
||||
@implementation CALayer (YYAdd)
|
||||
|
||||
- (UIImage *)snapshotImage {
|
||||
UIGraphicsBeginImageContextWithOptions(self.bounds.size, self.opaque, 0);
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
[self renderInContext:context];
|
||||
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
return image;
|
||||
}
|
||||
|
||||
- (NSData *)snapshotPDF {
|
||||
CGRect bounds = self.bounds;
|
||||
NSMutableData* data = [NSMutableData data];
|
||||
CGDataConsumerRef consumer = CGDataConsumerCreateWithCFData((__bridge CFMutableDataRef)data);
|
||||
CGContextRef context = CGPDFContextCreate(consumer, &bounds, NULL);
|
||||
CGDataConsumerRelease(consumer);
|
||||
if (!context) return nil;
|
||||
CGPDFContextBeginPage(context, NULL);
|
||||
CGContextTranslateCTM(context, 0, bounds.size.height);
|
||||
CGContextScaleCTM(context, 1.0, -1.0);
|
||||
[self renderInContext:context];
|
||||
CGPDFContextEndPage(context);
|
||||
CGPDFContextClose(context);
|
||||
CGContextRelease(context);
|
||||
return data;
|
||||
}
|
||||
|
||||
- (void)setLayerShadow:(UIColor*)color offset:(CGSize)offset radius:(CGFloat)radius {
|
||||
self.shadowColor = color.CGColor;
|
||||
self.shadowOffset = offset;
|
||||
self.shadowRadius = radius;
|
||||
self.shadowOpacity = 1;
|
||||
self.shouldRasterize = YES;
|
||||
self.rasterizationScale = [UIScreen mainScreen].scale;
|
||||
}
|
||||
|
||||
- (void)removeAllSublayers {
|
||||
while (self.sublayers.count) {
|
||||
[self.sublayers.lastObject removeFromSuperlayer];
|
||||
}
|
||||
}
|
||||
|
||||
- (CGFloat)left {
|
||||
return self.frame.origin.x;
|
||||
}
|
||||
|
||||
- (void)setLeft:(CGFloat)x {
|
||||
CGRect frame = self.frame;
|
||||
frame.origin.x = x;
|
||||
self.frame = frame;
|
||||
}
|
||||
|
||||
- (CGFloat)top {
|
||||
return self.frame.origin.y;
|
||||
}
|
||||
|
||||
- (void)setTop:(CGFloat)y {
|
||||
CGRect frame = self.frame;
|
||||
frame.origin.y = y;
|
||||
self.frame = frame;
|
||||
}
|
||||
|
||||
- (CGFloat)right {
|
||||
return self.frame.origin.x + self.frame.size.width;
|
||||
}
|
||||
|
||||
- (void)setRight:(CGFloat)right {
|
||||
CGRect frame = self.frame;
|
||||
frame.origin.x = right - frame.size.width;
|
||||
self.frame = frame;
|
||||
}
|
||||
|
||||
- (CGFloat)bottom {
|
||||
return self.frame.origin.y + self.frame.size.height;
|
||||
}
|
||||
|
||||
- (void)setBottom:(CGFloat)bottom {
|
||||
CGRect frame = self.frame;
|
||||
frame.origin.y = bottom - frame.size.height;
|
||||
self.frame = frame;
|
||||
}
|
||||
|
||||
- (CGFloat)width {
|
||||
return self.frame.size.width;
|
||||
}
|
||||
|
||||
- (void)setWidth:(CGFloat)width {
|
||||
CGRect frame = self.frame;
|
||||
frame.size.width = width;
|
||||
self.frame = frame;
|
||||
}
|
||||
|
||||
- (CGFloat)height {
|
||||
return self.frame.size.height;
|
||||
}
|
||||
|
||||
- (void)setHeight:(CGFloat)height {
|
||||
CGRect frame = self.frame;
|
||||
frame.size.height = height;
|
||||
self.frame = frame;
|
||||
}
|
||||
|
||||
- (CGPoint)center {
|
||||
return CGPointMake(self.frame.origin.x + self.frame.size.width * 0.5,
|
||||
self.frame.origin.y + self.frame.size.height * 0.5);
|
||||
}
|
||||
|
||||
- (void)setCenter:(CGPoint)center {
|
||||
CGRect frame = self.frame;
|
||||
frame.origin.x = center.x - frame.size.width * 0.5;
|
||||
frame.origin.y = center.y - frame.size.height * 0.5;
|
||||
self.frame = frame;
|
||||
}
|
||||
|
||||
- (CGFloat)centerX {
|
||||
return self.frame.origin.x + self.frame.size.width * 0.5;
|
||||
}
|
||||
|
||||
- (void)setCenterX:(CGFloat)centerX {
|
||||
CGRect frame = self.frame;
|
||||
frame.origin.x = centerX - frame.size.width * 0.5;
|
||||
self.frame = frame;
|
||||
}
|
||||
|
||||
- (CGFloat)centerY {
|
||||
return self.frame.origin.y + self.frame.size.height * 0.5;
|
||||
}
|
||||
|
||||
- (void)setCenterY:(CGFloat)centerY {
|
||||
CGRect frame = self.frame;
|
||||
frame.origin.y = centerY - frame.size.height * 0.5;
|
||||
self.frame = frame;
|
||||
}
|
||||
|
||||
- (CGPoint)origin {
|
||||
return self.frame.origin;
|
||||
}
|
||||
|
||||
- (void)setOrigin:(CGPoint)origin {
|
||||
CGRect frame = self.frame;
|
||||
frame.origin = origin;
|
||||
self.frame = frame;
|
||||
}
|
||||
|
||||
- (CGSize)frameSize {
|
||||
return self.frame.size;
|
||||
}
|
||||
|
||||
- (void)setFrameSize:(CGSize)size {
|
||||
CGRect frame = self.frame;
|
||||
frame.size = size;
|
||||
self.frame = frame;
|
||||
}
|
||||
|
||||
- (CGFloat)transformRotation {
|
||||
NSNumber *v = [self valueForKeyPath:@"transform.rotation"];
|
||||
return v.doubleValue;
|
||||
}
|
||||
|
||||
- (void)setTransformRotation:(CGFloat)v {
|
||||
[self setValue:@(v) forKeyPath:@"transform.rotation"];
|
||||
}
|
||||
|
||||
- (CGFloat)transformRotationX {
|
||||
NSNumber *v = [self valueForKeyPath:@"transform.rotation.x"];
|
||||
return v.doubleValue;
|
||||
}
|
||||
|
||||
- (void)setTransformRotationX:(CGFloat)v {
|
||||
[self setValue:@(v) forKeyPath:@"transform.rotation.x"];
|
||||
}
|
||||
|
||||
- (CGFloat)transformRotationY {
|
||||
NSNumber *v = [self valueForKeyPath:@"transform.rotation.y"];
|
||||
return v.doubleValue;
|
||||
}
|
||||
|
||||
- (void)setTransformRotationY:(CGFloat)v {
|
||||
[self setValue:@(v) forKeyPath:@"transform.rotation.y"];
|
||||
}
|
||||
|
||||
- (CGFloat)transformRotationZ {
|
||||
NSNumber *v = [self valueForKeyPath:@"transform.rotation.z"];
|
||||
return v.doubleValue;
|
||||
}
|
||||
|
||||
- (void)setTransformRotationZ:(CGFloat)v {
|
||||
[self setValue:@(v) forKeyPath:@"transform.rotation.z"];
|
||||
}
|
||||
|
||||
- (CGFloat)transformScaleX {
|
||||
NSNumber *v = [self valueForKeyPath:@"transform.scale.x"];
|
||||
return v.doubleValue;
|
||||
}
|
||||
|
||||
- (void)setTransformScaleX:(CGFloat)v {
|
||||
[self setValue:@(v) forKeyPath:@"transform.scale.x"];
|
||||
}
|
||||
|
||||
- (CGFloat)transformScaleY {
|
||||
NSNumber *v = [self valueForKeyPath:@"transform.scale.y"];
|
||||
return v.doubleValue;
|
||||
}
|
||||
|
||||
- (void)setTransformScaleY:(CGFloat)v {
|
||||
[self setValue:@(v) forKeyPath:@"transform.scale.y"];
|
||||
}
|
||||
|
||||
- (CGFloat)transformScaleZ {
|
||||
NSNumber *v = [self valueForKeyPath:@"transform.scale.z"];
|
||||
return v.doubleValue;
|
||||
}
|
||||
|
||||
- (void)setTransformScaleZ:(CGFloat)v {
|
||||
[self setValue:@(v) forKeyPath:@"transform.scale.z"];
|
||||
}
|
||||
|
||||
- (CGFloat)transformScale {
|
||||
NSNumber *v = [self valueForKeyPath:@"transform.scale"];
|
||||
return v.doubleValue;
|
||||
}
|
||||
|
||||
- (void)setTransformScale:(CGFloat)v {
|
||||
[self setValue:@(v) forKeyPath:@"transform.scale"];
|
||||
}
|
||||
|
||||
- (CGFloat)transformTranslationX {
|
||||
NSNumber *v = [self valueForKeyPath:@"transform.translation.x"];
|
||||
return v.doubleValue;
|
||||
}
|
||||
|
||||
- (void)setTransformTranslationX:(CGFloat)v {
|
||||
[self setValue:@(v) forKeyPath:@"transform.translation.x"];
|
||||
}
|
||||
|
||||
- (CGFloat)transformTranslationY {
|
||||
NSNumber *v = [self valueForKeyPath:@"transform.translation.y"];
|
||||
return v.doubleValue;
|
||||
}
|
||||
|
||||
- (void)setTransformTranslationY:(CGFloat)v {
|
||||
[self setValue:@(v) forKeyPath:@"transform.translation.y"];
|
||||
}
|
||||
|
||||
- (CGFloat)transformTranslationZ {
|
||||
NSNumber *v = [self valueForKeyPath:@"transform.translation.z"];
|
||||
return v.doubleValue;
|
||||
}
|
||||
|
||||
- (void)setTransformTranslationZ:(CGFloat)v {
|
||||
[self setValue:@(v) forKeyPath:@"transform.translation.z"];
|
||||
}
|
||||
|
||||
- (CGFloat)transformDepth {
|
||||
return self.transform.m34;
|
||||
}
|
||||
|
||||
- (void)setTransformDepth:(CGFloat)v {
|
||||
CATransform3D d = self.transform;
|
||||
d.m34 = v;
|
||||
self.transform = d;
|
||||
}
|
||||
|
||||
- (UIViewContentMode)contentMode {
|
||||
return YYCAGravityToUIViewContentMode(self.contentsGravity);
|
||||
}
|
||||
|
||||
- (void)setContentMode:(UIViewContentMode)contentMode {
|
||||
self.contentsGravity = YYUIViewContentModeToCAGravity(contentMode);
|
||||
}
|
||||
|
||||
- (void)addFadeAnimationWithDuration:(NSTimeInterval)duration curve:(UIViewAnimationCurve)curve {
|
||||
if (duration <= 0) return;
|
||||
|
||||
NSString *mediaFunction;
|
||||
switch (curve) {
|
||||
case UIViewAnimationCurveEaseInOut: {
|
||||
mediaFunction = kCAMediaTimingFunctionEaseInEaseOut;
|
||||
} break;
|
||||
case UIViewAnimationCurveEaseIn: {
|
||||
mediaFunction = kCAMediaTimingFunctionEaseIn;
|
||||
} break;
|
||||
case UIViewAnimationCurveEaseOut: {
|
||||
mediaFunction = kCAMediaTimingFunctionEaseOut;
|
||||
} break;
|
||||
case UIViewAnimationCurveLinear: {
|
||||
mediaFunction = kCAMediaTimingFunctionLinear;
|
||||
} break;
|
||||
default: {
|
||||
mediaFunction = kCAMediaTimingFunctionLinear;
|
||||
} break;
|
||||
}
|
||||
|
||||
CATransition *transition = [CATransition animation];
|
||||
transition.duration = duration;
|
||||
transition.timingFunction = [CAMediaTimingFunction functionWithName:mediaFunction];
|
||||
transition.type = kCATransitionFade;
|
||||
[self addAnimation:transition forKey:@"yykit.fade"];
|
||||
}
|
||||
|
||||
- (void)removePreviousFadeAnimation {
|
||||
[self removeAnimationForKey:@"yykit.fade"];
|
||||
}
|
||||
|
||||
@end
|
||||
330
Pods/YYCategories/YYCategories/Quartz/YYCGUtilities.h
generated
Normal file
330
Pods/YYCategories/YYCategories/Quartz/YYCGUtilities.h
generated
Normal file
@@ -0,0 +1,330 @@
|
||||
//
|
||||
// YYCGUtilities.h
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 15/2/28.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/// Create an `ARGB` Bitmap context. Returns NULL if an error occurs.
|
||||
///
|
||||
/// @discussion The function is same as UIGraphicsBeginImageContextWithOptions(),
|
||||
/// but it doesn't push the context to UIGraphic, so you can retain the context for reuse.
|
||||
CGContextRef _Nullable YYCGContextCreateARGBBitmapContext(CGSize size, BOOL opaque, CGFloat scale);
|
||||
|
||||
/// Create a `DeviceGray` Bitmap context. Returns NULL if an error occurs.
|
||||
CGContextRef _Nullable YYCGContextCreateGrayBitmapContext(CGSize size, CGFloat scale);
|
||||
|
||||
|
||||
|
||||
/// Get main screen's scale.
|
||||
CGFloat YYScreenScale();
|
||||
|
||||
/// Get main screen's size. Height is always larger than width.
|
||||
CGSize YYScreenSize();
|
||||
|
||||
|
||||
|
||||
/// Convert degrees to radians.
|
||||
static inline CGFloat DegreesToRadians(CGFloat degrees) {
|
||||
return degrees * M_PI / 180;
|
||||
}
|
||||
|
||||
/// Convert radians to degrees.
|
||||
static inline CGFloat RadiansToDegrees(CGFloat radians) {
|
||||
return radians * 180 / M_PI;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Get the transform rotation.
|
||||
/// @return the rotation in radians [-PI,PI] ([-180°,180°])
|
||||
static inline CGFloat CGAffineTransformGetRotation(CGAffineTransform transform) {
|
||||
return atan2(transform.b, transform.a);
|
||||
}
|
||||
|
||||
/// Get the transform's scale.x
|
||||
static inline CGFloat CGAffineTransformGetScaleX(CGAffineTransform transform) {
|
||||
return sqrt(transform.a * transform.a + transform.c * transform.c);
|
||||
}
|
||||
|
||||
/// Get the transform's scale.y
|
||||
static inline CGFloat CGAffineTransformGetScaleY(CGAffineTransform transform) {
|
||||
return sqrt(transform.b * transform.b + transform.d * transform.d);
|
||||
}
|
||||
|
||||
/// Get the transform's translate.x
|
||||
static inline CGFloat CGAffineTransformGetTranslateX(CGAffineTransform transform) {
|
||||
return transform.tx;
|
||||
}
|
||||
|
||||
/// Get the transform's translate.y
|
||||
static inline CGFloat CGAffineTransformGetTranslateY(CGAffineTransform transform) {
|
||||
return transform.ty;
|
||||
}
|
||||
|
||||
/**
|
||||
If you have 3 pair of points transformed by a same CGAffineTransform:
|
||||
p1 (transform->) q1
|
||||
p2 (transform->) q2
|
||||
p3 (transform->) q3
|
||||
This method returns the original transform matrix from these 3 pair of points.
|
||||
|
||||
@see http://stackoverflow.com/questions/13291796/calculate-values-for-a-cgaffinetransform-from-three-points-in-each-of-two-uiview
|
||||
*/
|
||||
CGAffineTransform YYCGAffineTransformGetFromPoints(CGPoint before[3], CGPoint after[3]);
|
||||
|
||||
/// Get the transform which can converts a point from the coordinate system of a given view to another.
|
||||
CGAffineTransform YYCGAffineTransformGetFromViews(UIView *from, UIView *to);
|
||||
|
||||
/// Create a skew transform.
|
||||
static inline CGAffineTransform CGAffineTransformMakeSkew(CGFloat x, CGFloat y){
|
||||
CGAffineTransform transform = CGAffineTransformIdentity;
|
||||
transform.c = -x;
|
||||
transform.b = y;
|
||||
return transform;
|
||||
}
|
||||
|
||||
/// Negates/inverts a UIEdgeInsets.
|
||||
static inline UIEdgeInsets UIEdgeInsetsInvert(UIEdgeInsets insets) {
|
||||
return UIEdgeInsetsMake(-insets.top, -insets.left, -insets.bottom, -insets.right);
|
||||
}
|
||||
|
||||
/// Convert CALayer's gravity string to UIViewContentMode.
|
||||
UIViewContentMode YYCAGravityToUIViewContentMode(NSString *gravity);
|
||||
|
||||
/// Convert UIViewContentMode to CALayer's gravity string.
|
||||
NSString *YYUIViewContentModeToCAGravity(UIViewContentMode contentMode);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Returns a rectangle to fit the @param rect with specified content mode.
|
||||
|
||||
@param rect The constrant rect
|
||||
@param size The content size
|
||||
@param mode The content mode
|
||||
@return A rectangle for the given content mode.
|
||||
@discussion UIViewContentModeRedraw is same as UIViewContentModeScaleToFill.
|
||||
*/
|
||||
CGRect YYCGRectFitWithContentMode(CGRect rect, CGSize size, UIViewContentMode mode);
|
||||
|
||||
/// Returns the center for the rectangle.
|
||||
static inline CGPoint CGRectGetCenter(CGRect rect) {
|
||||
return CGPointMake(CGRectGetMidX(rect), CGRectGetMidY(rect));
|
||||
}
|
||||
|
||||
/// Returns the area of the rectangle.
|
||||
static inline CGFloat CGRectGetArea(CGRect rect) {
|
||||
if (CGRectIsNull(rect)) return 0;
|
||||
rect = CGRectStandardize(rect);
|
||||
return rect.size.width * rect.size.height;
|
||||
}
|
||||
|
||||
/// Returns the distance between two points.
|
||||
static inline CGFloat CGPointGetDistanceToPoint(CGPoint p1, CGPoint p2) {
|
||||
return sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));
|
||||
}
|
||||
|
||||
/// Returns the minmium distance between a point to a rectangle.
|
||||
static inline CGFloat CGPointGetDistanceToRect(CGPoint p, CGRect r) {
|
||||
r = CGRectStandardize(r);
|
||||
if (CGRectContainsPoint(r, p)) return 0;
|
||||
CGFloat distV, distH;
|
||||
if (CGRectGetMinY(r) <= p.y && p.y <= CGRectGetMaxY(r)) {
|
||||
distV = 0;
|
||||
} else {
|
||||
distV = p.y < CGRectGetMinY(r) ? CGRectGetMinY(r) - p.y : p.y - CGRectGetMaxY(r);
|
||||
}
|
||||
if (CGRectGetMinX(r) <= p.x && p.x <= CGRectGetMaxX(r)) {
|
||||
distH = 0;
|
||||
} else {
|
||||
distH = p.x < CGRectGetMinX(r) ? CGRectGetMinX(r) - p.x : p.x - CGRectGetMaxX(r);
|
||||
}
|
||||
return MAX(distV, distH);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Convert point to pixel.
|
||||
static inline CGFloat CGFloatToPixel(CGFloat value) {
|
||||
return value * YYScreenScale();
|
||||
}
|
||||
|
||||
/// Convert pixel to point.
|
||||
static inline CGFloat CGFloatFromPixel(CGFloat value) {
|
||||
return value / YYScreenScale();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// floor point value for pixel-aligned
|
||||
static inline CGFloat CGFloatPixelFloor(CGFloat value) {
|
||||
CGFloat scale = YYScreenScale();
|
||||
return floor(value * scale) / scale;
|
||||
}
|
||||
|
||||
/// round point value for pixel-aligned
|
||||
static inline CGFloat CGFloatPixelRound(CGFloat value) {
|
||||
CGFloat scale = YYScreenScale();
|
||||
return round(value * scale) / scale;
|
||||
}
|
||||
|
||||
/// ceil point value for pixel-aligned
|
||||
static inline CGFloat CGFloatPixelCeil(CGFloat value) {
|
||||
CGFloat scale = YYScreenScale();
|
||||
return ceil(value * scale) / scale;
|
||||
}
|
||||
|
||||
/// round point value to .5 pixel for path stroke (odd pixel line width pixel-aligned)
|
||||
static inline CGFloat CGFloatPixelHalf(CGFloat value) {
|
||||
CGFloat scale = YYScreenScale();
|
||||
return (floor(value * scale) + 0.5) / scale;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// floor point value for pixel-aligned
|
||||
static inline CGPoint CGPointPixelFloor(CGPoint point) {
|
||||
CGFloat scale = YYScreenScale();
|
||||
return CGPointMake(floor(point.x * scale) / scale,
|
||||
floor(point.y * scale) / scale);
|
||||
}
|
||||
|
||||
/// round point value for pixel-aligned
|
||||
static inline CGPoint CGPointPixelRound(CGPoint point) {
|
||||
CGFloat scale = YYScreenScale();
|
||||
return CGPointMake(round(point.x * scale) / scale,
|
||||
round(point.y * scale) / scale);
|
||||
}
|
||||
|
||||
/// ceil point value for pixel-aligned
|
||||
static inline CGPoint CGPointPixelCeil(CGPoint point) {
|
||||
CGFloat scale = YYScreenScale();
|
||||
return CGPointMake(ceil(point.x * scale) / scale,
|
||||
ceil(point.y * scale) / scale);
|
||||
}
|
||||
|
||||
/// round point value to .5 pixel for path stroke (odd pixel line width pixel-aligned)
|
||||
static inline CGPoint CGPointPixelHalf(CGPoint point) {
|
||||
CGFloat scale = YYScreenScale();
|
||||
return CGPointMake((floor(point.x * scale) + 0.5) / scale,
|
||||
(floor(point.y * scale) + 0.5) / scale);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// floor point value for pixel-aligned
|
||||
static inline CGSize CGSizePixelFloor(CGSize size) {
|
||||
CGFloat scale = YYScreenScale();
|
||||
return CGSizeMake(floor(size.width * scale) / scale,
|
||||
floor(size.height * scale) / scale);
|
||||
}
|
||||
|
||||
/// round point value for pixel-aligned
|
||||
static inline CGSize CGSizePixelRound(CGSize size) {
|
||||
CGFloat scale = YYScreenScale();
|
||||
return CGSizeMake(round(size.width * scale) / scale,
|
||||
round(size.height * scale) / scale);
|
||||
}
|
||||
|
||||
/// ceil point value for pixel-aligned
|
||||
static inline CGSize CGSizePixelCeil(CGSize size) {
|
||||
CGFloat scale = YYScreenScale();
|
||||
return CGSizeMake(ceil(size.width * scale) / scale,
|
||||
ceil(size.height * scale) / scale);
|
||||
}
|
||||
|
||||
/// round point value to .5 pixel for path stroke (odd pixel line width pixel-aligned)
|
||||
static inline CGSize CGSizePixelHalf(CGSize size) {
|
||||
CGFloat scale = YYScreenScale();
|
||||
return CGSizeMake((floor(size.width * scale) + 0.5) / scale,
|
||||
(floor(size.height * scale) + 0.5) / scale);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// floor point value for pixel-aligned
|
||||
static inline CGRect CGRectPixelFloor(CGRect rect) {
|
||||
CGPoint origin = CGPointPixelCeil(rect.origin);
|
||||
CGPoint corner = CGPointPixelFloor(CGPointMake(rect.origin.x + rect.size.width,
|
||||
rect.origin.y + rect.size.height));
|
||||
CGRect ret = CGRectMake(origin.x, origin.y, corner.x - origin.x, corner.y - origin.y);
|
||||
if (ret.size.width < 0) ret.size.width = 0;
|
||||
if (ret.size.height < 0) ret.size.height = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// round point value for pixel-aligned
|
||||
static inline CGRect CGRectPixelRound(CGRect rect) {
|
||||
CGPoint origin = CGPointPixelRound(rect.origin);
|
||||
CGPoint corner = CGPointPixelRound(CGPointMake(rect.origin.x + rect.size.width,
|
||||
rect.origin.y + rect.size.height));
|
||||
return CGRectMake(origin.x, origin.y, corner.x - origin.x, corner.y - origin.y);
|
||||
}
|
||||
|
||||
/// ceil point value for pixel-aligned
|
||||
static inline CGRect CGRectPixelCeil(CGRect rect) {
|
||||
CGPoint origin = CGPointPixelFloor(rect.origin);
|
||||
CGPoint corner = CGPointPixelCeil(CGPointMake(rect.origin.x + rect.size.width,
|
||||
rect.origin.y + rect.size.height));
|
||||
return CGRectMake(origin.x, origin.y, corner.x - origin.x, corner.y - origin.y);
|
||||
}
|
||||
|
||||
/// round point value to .5 pixel for path stroke (odd pixel line width pixel-aligned)
|
||||
static inline CGRect CGRectPixelHalf(CGRect rect) {
|
||||
CGPoint origin = CGPointPixelHalf(rect.origin);
|
||||
CGPoint corner = CGPointPixelHalf(CGPointMake(rect.origin.x + rect.size.width,
|
||||
rect.origin.y + rect.size.height));
|
||||
return CGRectMake(origin.x, origin.y, corner.x - origin.x, corner.y - origin.y);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// floor UIEdgeInset for pixel-aligned
|
||||
static inline UIEdgeInsets UIEdgeInsetPixelFloor(UIEdgeInsets insets) {
|
||||
insets.top = CGFloatPixelFloor(insets.top);
|
||||
insets.left = CGFloatPixelFloor(insets.left);
|
||||
insets.bottom = CGFloatPixelFloor(insets.bottom);
|
||||
insets.right = CGFloatPixelFloor(insets.right);
|
||||
return insets;
|
||||
}
|
||||
|
||||
/// ceil UIEdgeInset for pixel-aligned
|
||||
static inline UIEdgeInsets UIEdgeInsetPixelCeil(UIEdgeInsets insets) {
|
||||
insets.top = CGFloatPixelCeil(insets.top);
|
||||
insets.left = CGFloatPixelCeil(insets.left);
|
||||
insets.bottom = CGFloatPixelCeil(insets.bottom);
|
||||
insets.right = CGFloatPixelCeil(insets.right);
|
||||
return insets;
|
||||
}
|
||||
|
||||
// main screen's scale
|
||||
#ifndef kScreenScale
|
||||
#define kScreenScale YYScreenScale()
|
||||
#endif
|
||||
|
||||
// main screen's size (portrait)
|
||||
#ifndef kScreenSize
|
||||
#define kScreenSize YYScreenSize()
|
||||
#endif
|
||||
|
||||
// main screen's width (portrait)
|
||||
#ifndef kScreenWidth
|
||||
#define kScreenWidth YYScreenSize().width
|
||||
#endif
|
||||
|
||||
// main screen's height (portrait)
|
||||
#ifndef kScreenHeight
|
||||
#define kScreenHeight YYScreenSize().height
|
||||
#endif
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
271
Pods/YYCategories/YYCategories/Quartz/YYCGUtilities.m
generated
Normal file
271
Pods/YYCategories/YYCategories/Quartz/YYCGUtilities.m
generated
Normal file
@@ -0,0 +1,271 @@
|
||||
//
|
||||
// YYCGUtilities.m
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 15/2/28.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import "YYCGUtilities.h"
|
||||
#import <Accelerate/Accelerate.h>
|
||||
#import "UIView+YYAdd.h"
|
||||
|
||||
CGContextRef YYCGContextCreateARGBBitmapContext(CGSize size, BOOL opaque, CGFloat scale) {
|
||||
size_t width = ceil(size.width * scale);
|
||||
size_t height = ceil(size.height * scale);
|
||||
if (width < 1 || height < 1) return NULL;
|
||||
|
||||
//pre-multiplied ARGB, 8-bits per component
|
||||
CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
|
||||
CGImageAlphaInfo alphaInfo = (opaque ? kCGImageAlphaNoneSkipFirst : kCGImageAlphaPremultipliedFirst);
|
||||
CGContextRef context = CGBitmapContextCreate(NULL, width, height, 8, 0, space, kCGBitmapByteOrderDefault | alphaInfo);
|
||||
CGColorSpaceRelease(space);
|
||||
if (context) {
|
||||
CGContextTranslateCTM(context, 0, height);
|
||||
CGContextScaleCTM(context, scale, -scale);
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
CGContextRef YYCGContextCreateGrayBitmapContext(CGSize size, CGFloat scale) {
|
||||
size_t width = ceil(size.width * scale);
|
||||
size_t height = ceil(size.height * scale);
|
||||
if (width < 1 || height < 1) return NULL;
|
||||
|
||||
//DeviceGray, 8-bits per component
|
||||
CGColorSpaceRef space = CGColorSpaceCreateDeviceGray();
|
||||
CGImageAlphaInfo alphaInfo = kCGImageAlphaNone;
|
||||
CGContextRef context = CGBitmapContextCreate(NULL, width, height, 8, 0, space, kCGBitmapByteOrderDefault | alphaInfo);
|
||||
CGColorSpaceRelease(space);
|
||||
if (context) {
|
||||
CGContextTranslateCTM(context, 0, height);
|
||||
CGContextScaleCTM(context, scale, -scale);
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
CGFloat YYScreenScale() {
|
||||
static CGFloat scale;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
scale = [UIScreen mainScreen].scale;
|
||||
});
|
||||
return scale;
|
||||
}
|
||||
|
||||
CGSize YYScreenSize() {
|
||||
static CGSize size;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
size = [UIScreen mainScreen].bounds.size;
|
||||
if (size.height < size.width) {
|
||||
CGFloat tmp = size.height;
|
||||
size.height = size.width;
|
||||
size.width = tmp;
|
||||
}
|
||||
});
|
||||
return size;
|
||||
}
|
||||
|
||||
// return 0 when succeed
|
||||
static int matrix_invert(__CLPK_integer N, double *matrix) {
|
||||
__CLPK_integer error = 0;
|
||||
__CLPK_integer pivot_tmp[6 * 6];
|
||||
__CLPK_integer *pivot = pivot_tmp;
|
||||
double workspace_tmp[6 * 6];
|
||||
double *workspace = workspace_tmp;
|
||||
bool need_free = false;
|
||||
|
||||
if (N > 6) {
|
||||
need_free = true;
|
||||
pivot = malloc(N * N * sizeof(__CLPK_integer));
|
||||
if (!pivot) return -1;
|
||||
workspace = malloc(N * sizeof(double));
|
||||
if (!workspace) {
|
||||
free(pivot);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
dgetrf_(&N, &N, matrix, &N, pivot, &error);
|
||||
|
||||
if (error == 0) {
|
||||
dgetri_(&N, matrix, &N, pivot, workspace, &N, &error);
|
||||
}
|
||||
|
||||
if (need_free) {
|
||||
free(pivot);
|
||||
free(workspace);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
CGAffineTransform YYCGAffineTransformGetFromPoints(CGPoint before[3], CGPoint after[3]) {
|
||||
if (before == NULL || after == NULL) return CGAffineTransformIdentity;
|
||||
|
||||
CGPoint p1, p2, p3, q1, q2, q3;
|
||||
p1 = before[0]; p2 = before[1]; p3 = before[2];
|
||||
q1 = after[0]; q2 = after[1]; q3 = after[2];
|
||||
|
||||
double A[36];
|
||||
A[ 0] = p1.x; A[ 1] = p1.y; A[ 2] = 0; A[ 3] = 0; A[ 4] = 1; A[ 5] = 0;
|
||||
A[ 6] = 0; A[ 7] = 0; A[ 8] = p1.x; A[ 9] = p1.y; A[10] = 0; A[11] = 1;
|
||||
A[12] = p2.x; A[13] = p2.y; A[14] = 0; A[15] = 0; A[16] = 1; A[17] = 0;
|
||||
A[18] = 0; A[19] = 0; A[20] = p2.x; A[21] = p2.y; A[22] = 0; A[23] = 1;
|
||||
A[24] = p3.x; A[25] = p3.y; A[26] = 0; A[27] = 0; A[28] = 1; A[29] = 0;
|
||||
A[30] = 0; A[31] = 0; A[32] = p3.x; A[33] = p3.y; A[34] = 0; A[35] = 1;
|
||||
|
||||
int error = matrix_invert(6, A);
|
||||
if (error) return CGAffineTransformIdentity;
|
||||
|
||||
double B[6];
|
||||
B[0] = q1.x; B[1] = q1.y; B[2] = q2.x; B[3] = q2.y; B[4] = q3.x; B[5] = q3.y;
|
||||
|
||||
double M[6];
|
||||
M[0] = A[ 0] * B[0] + A[ 1] * B[1] + A[ 2] * B[2] + A[ 3] * B[3] + A[ 4] * B[4] + A[ 5] * B[5];
|
||||
M[1] = A[ 6] * B[0] + A[ 7] * B[1] + A[ 8] * B[2] + A[ 9] * B[3] + A[10] * B[4] + A[11] * B[5];
|
||||
M[2] = A[12] * B[0] + A[13] * B[1] + A[14] * B[2] + A[15] * B[3] + A[16] * B[4] + A[17] * B[5];
|
||||
M[3] = A[18] * B[0] + A[19] * B[1] + A[20] * B[2] + A[21] * B[3] + A[22] * B[4] + A[23] * B[5];
|
||||
M[4] = A[24] * B[0] + A[25] * B[1] + A[26] * B[2] + A[27] * B[3] + A[28] * B[4] + A[29] * B[5];
|
||||
M[5] = A[30] * B[0] + A[31] * B[1] + A[32] * B[2] + A[33] * B[3] + A[34] * B[4] + A[35] * B[5];
|
||||
|
||||
CGAffineTransform transform = CGAffineTransformMake(M[0], M[2], M[1], M[3], M[4], M[5]);
|
||||
return transform;
|
||||
}
|
||||
|
||||
CGAffineTransform YYCGAffineTransformGetFromViews(UIView *from, UIView *to) {
|
||||
if (!from || !to) return CGAffineTransformIdentity;
|
||||
|
||||
CGPoint before[3], after[3];
|
||||
before[0] = CGPointMake(0, 0);
|
||||
before[1] = CGPointMake(0, 1);
|
||||
before[2] = CGPointMake(1, 0);
|
||||
after[0] = [from convertPoint:before[0] toViewOrWindow:to];
|
||||
after[1] = [from convertPoint:before[1] toViewOrWindow:to];
|
||||
after[2] = [from convertPoint:before[2] toViewOrWindow:to];
|
||||
|
||||
return YYCGAffineTransformGetFromPoints(before, after);
|
||||
}
|
||||
|
||||
UIViewContentMode YYCAGravityToUIViewContentMode(NSString *gravity) {
|
||||
static NSDictionary *dic;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
dic = @{ kCAGravityCenter:@(UIViewContentModeCenter),
|
||||
kCAGravityTop:@(UIViewContentModeTop),
|
||||
kCAGravityBottom:@(UIViewContentModeBottom),
|
||||
kCAGravityLeft:@(UIViewContentModeLeft),
|
||||
kCAGravityRight:@(UIViewContentModeRight),
|
||||
kCAGravityTopLeft:@(UIViewContentModeTopLeft),
|
||||
kCAGravityTopRight:@(UIViewContentModeTopRight),
|
||||
kCAGravityBottomLeft:@(UIViewContentModeBottomLeft),
|
||||
kCAGravityBottomRight:@(UIViewContentModeBottomRight),
|
||||
kCAGravityResize:@(UIViewContentModeScaleToFill),
|
||||
kCAGravityResizeAspect:@(UIViewContentModeScaleAspectFit),
|
||||
kCAGravityResizeAspectFill:@(UIViewContentModeScaleAspectFill) };
|
||||
});
|
||||
if (!gravity) return UIViewContentModeScaleToFill;
|
||||
return (UIViewContentMode)((NSNumber *)dic[gravity]).integerValue;
|
||||
}
|
||||
|
||||
NSString *YYUIViewContentModeToCAGravity(UIViewContentMode contentMode) {
|
||||
switch (contentMode) {
|
||||
case UIViewContentModeScaleToFill: return kCAGravityResize;
|
||||
case UIViewContentModeScaleAspectFit: return kCAGravityResizeAspect;
|
||||
case UIViewContentModeScaleAspectFill: return kCAGravityResizeAspectFill;
|
||||
case UIViewContentModeRedraw: return kCAGravityResize;
|
||||
case UIViewContentModeCenter: return kCAGravityCenter;
|
||||
case UIViewContentModeTop: return kCAGravityTop;
|
||||
case UIViewContentModeBottom: return kCAGravityBottom;
|
||||
case UIViewContentModeLeft: return kCAGravityLeft;
|
||||
case UIViewContentModeRight: return kCAGravityRight;
|
||||
case UIViewContentModeTopLeft: return kCAGravityTopLeft;
|
||||
case UIViewContentModeTopRight: return kCAGravityTopRight;
|
||||
case UIViewContentModeBottomLeft: return kCAGravityBottomLeft;
|
||||
case UIViewContentModeBottomRight: return kCAGravityBottomRight;
|
||||
default: return kCAGravityResize;
|
||||
}
|
||||
}
|
||||
|
||||
CGRect YYCGRectFitWithContentMode(CGRect rect, CGSize size, UIViewContentMode mode) {
|
||||
rect = CGRectStandardize(rect);
|
||||
size.width = size.width < 0 ? -size.width : size.width;
|
||||
size.height = size.height < 0 ? -size.height : size.height;
|
||||
CGPoint center = CGPointMake(CGRectGetMidX(rect), CGRectGetMidY(rect));
|
||||
switch (mode) {
|
||||
case UIViewContentModeScaleAspectFit:
|
||||
case UIViewContentModeScaleAspectFill: {
|
||||
if (rect.size.width < 0.01 || rect.size.height < 0.01 ||
|
||||
size.width < 0.01 || size.height < 0.01) {
|
||||
rect.origin = center;
|
||||
rect.size = CGSizeZero;
|
||||
} else {
|
||||
CGFloat scale;
|
||||
if (mode == UIViewContentModeScaleAspectFit) {
|
||||
if (size.width / size.height < rect.size.width / rect.size.height) {
|
||||
scale = rect.size.height / size.height;
|
||||
} else {
|
||||
scale = rect.size.width / size.width;
|
||||
}
|
||||
} else {
|
||||
if (size.width / size.height < rect.size.width / rect.size.height) {
|
||||
scale = rect.size.width / size.width;
|
||||
} else {
|
||||
scale = rect.size.height / size.height;
|
||||
}
|
||||
}
|
||||
size.width *= scale;
|
||||
size.height *= scale;
|
||||
rect.size = size;
|
||||
rect.origin = CGPointMake(center.x - size.width * 0.5, center.y - size.height * 0.5);
|
||||
}
|
||||
} break;
|
||||
case UIViewContentModeCenter: {
|
||||
rect.size = size;
|
||||
rect.origin = CGPointMake(center.x - size.width * 0.5, center.y - size.height * 0.5);
|
||||
} break;
|
||||
case UIViewContentModeTop: {
|
||||
rect.origin.x = center.x - size.width * 0.5;
|
||||
rect.size = size;
|
||||
} break;
|
||||
case UIViewContentModeBottom: {
|
||||
rect.origin.x = center.x - size.width * 0.5;
|
||||
rect.origin.y += rect.size.height - size.height;
|
||||
rect.size = size;
|
||||
} break;
|
||||
case UIViewContentModeLeft: {
|
||||
rect.origin.y = center.y - size.height * 0.5;
|
||||
rect.size = size;
|
||||
} break;
|
||||
case UIViewContentModeRight: {
|
||||
rect.origin.y = center.y - size.height * 0.5;
|
||||
rect.origin.x += rect.size.width - size.width;
|
||||
rect.size = size;
|
||||
} break;
|
||||
case UIViewContentModeTopLeft: {
|
||||
rect.size = size;
|
||||
} break;
|
||||
case UIViewContentModeTopRight: {
|
||||
rect.origin.x += rect.size.width - size.width;
|
||||
rect.size = size;
|
||||
} break;
|
||||
case UIViewContentModeBottomLeft: {
|
||||
rect.origin.y += rect.size.height - size.height;
|
||||
rect.size = size;
|
||||
} break;
|
||||
case UIViewContentModeBottomRight: {
|
||||
rect.origin.x += rect.size.width - size.width;
|
||||
rect.origin.y += rect.size.height - size.height;
|
||||
rect.size = size;
|
||||
} break;
|
||||
case UIViewContentModeScaleToFill:
|
||||
case UIViewContentModeRedraw:
|
||||
default: {
|
||||
rect = rect;
|
||||
}
|
||||
}
|
||||
return rect;
|
||||
}
|
||||
85
Pods/YYCategories/YYCategories/UIKit/UIApplication+YYAdd.h
generated
Normal file
85
Pods/YYCategories/YYCategories/UIKit/UIApplication+YYAdd.h
generated
Normal file
@@ -0,0 +1,85 @@
|
||||
//
|
||||
// UIApplication+YYAdd.h
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 13/4/4.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
Provides extensions for `UIApplication`.
|
||||
*/
|
||||
@interface UIApplication (YYAdd)
|
||||
|
||||
/// "Documents" folder in this app's sandbox.
|
||||
@property (nonatomic, readonly) NSURL *documentsURL;
|
||||
@property (nonatomic, readonly) NSString *documentsPath;
|
||||
|
||||
/// "Caches" folder in this app's sandbox.
|
||||
@property (nonatomic, readonly) NSURL *cachesURL;
|
||||
@property (nonatomic, readonly) NSString *cachesPath;
|
||||
|
||||
/// "Library" folder in this app's sandbox.
|
||||
@property (nonatomic, readonly) NSURL *libraryURL;
|
||||
@property (nonatomic, readonly) NSString *libraryPath;
|
||||
|
||||
/// Application's Bundle Name (show in SpringBoard).
|
||||
@property (nullable, nonatomic, readonly) NSString *appBundleName;
|
||||
|
||||
/// Application's Bundle ID. e.g. "com.ibireme.MyApp"
|
||||
@property (nullable, nonatomic, readonly) NSString *appBundleID;
|
||||
|
||||
/// Application's Version. e.g. "1.2.0"
|
||||
@property (nullable, nonatomic, readonly) NSString *appVersion;
|
||||
|
||||
/// Application's Build number. e.g. "123"
|
||||
@property (nullable, nonatomic, readonly) NSString *appBuildVersion;
|
||||
|
||||
/// Whether this app is priated (not install from appstore).
|
||||
@property (nonatomic, readonly) BOOL isPirated;
|
||||
|
||||
/// Whether this app is being debugged (debugger attached).
|
||||
@property (nonatomic, readonly) BOOL isBeingDebugged;
|
||||
|
||||
/// Current thread real memory used in byte. (-1 when error occurs)
|
||||
@property (nonatomic, readonly) int64_t memoryUsage;
|
||||
|
||||
/// Current thread CPU usage, 1.0 means 100%. (-1 when error occurs)
|
||||
@property (nonatomic, readonly) float cpuUsage;
|
||||
|
||||
|
||||
/**
|
||||
Increments the number of active network requests.
|
||||
If this number was zero before incrementing, this will start animating the
|
||||
status bar network activity indicator.
|
||||
|
||||
This method is thread safe.
|
||||
*/
|
||||
- (void)incrementNetworkActivityCount;
|
||||
|
||||
/**
|
||||
Decrements the number of active network requests.
|
||||
If this number becomes zero after decrementing, this will stop animating the
|
||||
status bar network activity indicator.
|
||||
|
||||
This method is thread safe.
|
||||
*/
|
||||
- (void)decrementNetworkActivityCount;
|
||||
|
||||
|
||||
/// Returns YES in App Extension.
|
||||
+ (BOOL)isAppExtension;
|
||||
|
||||
/// Same as sharedApplication, but returns nil in App Extension.
|
||||
+ (nullable UIApplication *)sharedExtensionApplication;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
239
Pods/YYCategories/YYCategories/UIKit/UIApplication+YYAdd.m
generated
Normal file
239
Pods/YYCategories/YYCategories/UIKit/UIApplication+YYAdd.m
generated
Normal file
@@ -0,0 +1,239 @@
|
||||
//
|
||||
// UIApplication+YYAdd.m
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 13/4/4.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import "UIApplication+YYAdd.h"
|
||||
#import "NSArray+YYAdd.h"
|
||||
#import "NSObject+YYAdd.h"
|
||||
#import "YYCategoriesMacro.h"
|
||||
#import "UIDevice+YYAdd.h"
|
||||
#import <sys/sysctl.h>
|
||||
#import <mach/mach.h>
|
||||
#import <objc/runtime.h>
|
||||
|
||||
YYSYNTH_DUMMY_CLASS(UIApplication_YYAdd)
|
||||
|
||||
#define kNetworkIndicatorDelay (1/30.0)
|
||||
@interface _YYUIApplicationNetworkIndicatorInfo : NSObject
|
||||
@property (nonatomic, assign) NSInteger count;
|
||||
@property (nonatomic, strong) NSTimer *timer;
|
||||
@end
|
||||
|
||||
@implementation _YYUIApplicationNetworkIndicatorInfo
|
||||
@end
|
||||
|
||||
|
||||
@implementation UIApplication (YYAdd)
|
||||
|
||||
- (NSURL *)documentsURL {
|
||||
return [[[NSFileManager defaultManager]
|
||||
URLsForDirectory:NSDocumentDirectory
|
||||
inDomains:NSUserDomainMask] lastObject];
|
||||
}
|
||||
|
||||
- (NSString *)documentsPath {
|
||||
return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
|
||||
}
|
||||
|
||||
- (NSURL *)cachesURL {
|
||||
return [[[NSFileManager defaultManager]
|
||||
URLsForDirectory:NSCachesDirectory
|
||||
inDomains:NSUserDomainMask] lastObject];
|
||||
}
|
||||
|
||||
- (NSString *)cachesPath {
|
||||
return [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
|
||||
}
|
||||
|
||||
- (NSURL *)libraryURL {
|
||||
return [[[NSFileManager defaultManager]
|
||||
URLsForDirectory:NSLibraryDirectory
|
||||
inDomains:NSUserDomainMask] lastObject];
|
||||
}
|
||||
|
||||
- (NSString *)libraryPath {
|
||||
return [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) firstObject];
|
||||
}
|
||||
|
||||
- (BOOL)isPirated {
|
||||
if ([[UIDevice currentDevice] isSimulator]) return YES; // Simulator is not from appstore
|
||||
|
||||
if (getgid() <= 10) return YES; // process ID shouldn't be root
|
||||
|
||||
if ([[[NSBundle mainBundle] infoDictionary] objectForKey:@"SignerIdentity"]) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
if (![self _yy_fileExistInMainBundle:@"_CodeSignature"]) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
if (![self _yy_fileExistInMainBundle:@"SC_Info"]) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
//if someone really want to crack your app, this method is useless..
|
||||
//you may change this method's name, encrypt the code and do more check..
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)_yy_fileExistInMainBundle:(NSString *)name {
|
||||
NSString *bundlePath = [[NSBundle mainBundle] bundlePath];
|
||||
NSString *path = [NSString stringWithFormat:@"%@/%@", bundlePath, name];
|
||||
return [[NSFileManager defaultManager] fileExistsAtPath:path];
|
||||
}
|
||||
|
||||
- (NSString *)appBundleName {
|
||||
return [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"];
|
||||
}
|
||||
|
||||
- (NSString *)appBundleID {
|
||||
return [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIdentifier"];
|
||||
}
|
||||
|
||||
- (NSString *)appVersion {
|
||||
return [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
|
||||
}
|
||||
|
||||
- (NSString *)appBuildVersion {
|
||||
return [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"];
|
||||
}
|
||||
|
||||
- (BOOL)isBeingDebugged {
|
||||
size_t size = sizeof(struct kinfo_proc);
|
||||
struct kinfo_proc info;
|
||||
int ret = 0, name[4];
|
||||
memset(&info, 0, sizeof(struct kinfo_proc));
|
||||
|
||||
name[0] = CTL_KERN;
|
||||
name[1] = KERN_PROC;
|
||||
name[2] = KERN_PROC_PID; name[3] = getpid();
|
||||
|
||||
if (ret == (sysctl(name, 4, &info, &size, NULL, 0))) {
|
||||
return ret != 0;
|
||||
}
|
||||
return (info.kp_proc.p_flag & P_TRACED) ? YES : NO;
|
||||
}
|
||||
|
||||
- (int64_t)memoryUsage {
|
||||
struct task_basic_info info;
|
||||
mach_msg_type_number_t size = sizeof(info);
|
||||
kern_return_t kern = task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&info, &size);
|
||||
if (kern != KERN_SUCCESS) return -1;
|
||||
return info.resident_size;
|
||||
}
|
||||
|
||||
- (float)cpuUsage {
|
||||
kern_return_t kr;
|
||||
task_info_data_t tinfo;
|
||||
mach_msg_type_number_t task_info_count;
|
||||
|
||||
task_info_count = TASK_INFO_MAX;
|
||||
kr = task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)tinfo, &task_info_count);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
thread_array_t thread_list;
|
||||
mach_msg_type_number_t thread_count;
|
||||
|
||||
thread_info_data_t thinfo;
|
||||
mach_msg_type_number_t thread_info_count;
|
||||
|
||||
thread_basic_info_t basic_info_th;
|
||||
|
||||
kr = task_threads(mach_task_self(), &thread_list, &thread_count);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
long tot_sec = 0;
|
||||
long tot_usec = 0;
|
||||
float tot_cpu = 0;
|
||||
int j;
|
||||
|
||||
for (j = 0; j < thread_count; j++) {
|
||||
thread_info_count = THREAD_INFO_MAX;
|
||||
kr = thread_info(thread_list[j], THREAD_BASIC_INFO,
|
||||
(thread_info_t)thinfo, &thread_info_count);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
basic_info_th = (thread_basic_info_t)thinfo;
|
||||
|
||||
if (!(basic_info_th->flags & TH_FLAGS_IDLE)) {
|
||||
tot_sec = tot_sec + basic_info_th->user_time.seconds + basic_info_th->system_time.seconds;
|
||||
tot_usec = tot_usec + basic_info_th->system_time.microseconds + basic_info_th->system_time.microseconds;
|
||||
tot_cpu = tot_cpu + basic_info_th->cpu_usage / (float)TH_USAGE_SCALE;
|
||||
}
|
||||
}
|
||||
|
||||
kr = vm_deallocate(mach_task_self(), (vm_offset_t)thread_list, thread_count * sizeof(thread_t));
|
||||
assert(kr == KERN_SUCCESS);
|
||||
|
||||
return tot_cpu;
|
||||
}
|
||||
|
||||
YYSYNTH_DYNAMIC_PROPERTY_OBJECT(networkActivityInfo, setNetworkActivityInfo, RETAIN_NONATOMIC, _YYUIApplicationNetworkIndicatorInfo *);
|
||||
|
||||
- (void)_delaySetActivity:(NSTimer *)timer {
|
||||
NSNumber *visiable = timer.userInfo;
|
||||
if (self.networkActivityIndicatorVisible != visiable.boolValue) {
|
||||
[self setNetworkActivityIndicatorVisible:visiable.boolValue];
|
||||
}
|
||||
[timer invalidate];
|
||||
}
|
||||
|
||||
- (void)_changeNetworkActivityCount:(NSInteger)delta {
|
||||
@synchronized(self){
|
||||
dispatch_async_on_main_queue(^{
|
||||
_YYUIApplicationNetworkIndicatorInfo *info = [self networkActivityInfo];
|
||||
if (!info) {
|
||||
info = [_YYUIApplicationNetworkIndicatorInfo new];
|
||||
[self setNetworkActivityInfo:info];
|
||||
}
|
||||
NSInteger count = info.count;
|
||||
count += delta;
|
||||
info.count = count;
|
||||
[info.timer invalidate];
|
||||
info.timer = [NSTimer timerWithTimeInterval:kNetworkIndicatorDelay target:self selector:@selector(_delaySetActivity:) userInfo:@(info.count > 0) repeats:NO];
|
||||
[[NSRunLoop mainRunLoop] addTimer:info.timer forMode:NSRunLoopCommonModes];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
- (void)incrementNetworkActivityCount {
|
||||
[self _changeNetworkActivityCount:1];
|
||||
}
|
||||
|
||||
- (void)decrementNetworkActivityCount {
|
||||
[self _changeNetworkActivityCount:-1];
|
||||
}
|
||||
|
||||
+ (BOOL)isAppExtension {
|
||||
static BOOL isAppExtension = NO;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
Class cls = NSClassFromString(@"UIApplication");
|
||||
if(!cls || ![cls respondsToSelector:@selector(sharedApplication)]) isAppExtension = YES;
|
||||
if ([[[NSBundle mainBundle] bundlePath] hasSuffix:@".appex"]) isAppExtension = YES;
|
||||
});
|
||||
return isAppExtension;
|
||||
}
|
||||
|
||||
+ (UIApplication *)sharedExtensionApplication {
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wundeclared-selector"
|
||||
return [self isAppExtension] ? nil : [UIApplication performSelector:@selector(sharedApplication)];
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
|
||||
@end
|
||||
32
Pods/YYCategories/YYCategories/UIKit/UIBarButtonItem+YYAdd.h
generated
Normal file
32
Pods/YYCategories/YYCategories/UIKit/UIBarButtonItem+YYAdd.h
generated
Normal file
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// UIBarButtonItem+YYAdd.h
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 13/10/15.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
Provides extensions for `UIBarButtonItem`.
|
||||
*/
|
||||
@interface UIBarButtonItem (YYAdd)
|
||||
|
||||
/**
|
||||
The block that invoked when the item is selected. The objects captured by block
|
||||
will retained by the ButtonItem.
|
||||
|
||||
@discussion This param is conflict with `target` and `action` property.
|
||||
Set this will set `target` and `action` property to some internal objects.
|
||||
*/
|
||||
@property (nullable, nonatomic, copy) void (^actionBlock)(id);
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
62
Pods/YYCategories/YYCategories/UIKit/UIBarButtonItem+YYAdd.m
generated
Normal file
62
Pods/YYCategories/YYCategories/UIKit/UIBarButtonItem+YYAdd.m
generated
Normal file
@@ -0,0 +1,62 @@
|
||||
//
|
||||
// UIBarButtonItem+YYAdd.m
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 13/10/15.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import "UIBarButtonItem+YYAdd.h"
|
||||
#import "YYCategoriesMacro.h"
|
||||
#import <objc/runtime.h>
|
||||
|
||||
YYSYNTH_DUMMY_CLASS(UIBarButtonItem_YYAdd)
|
||||
|
||||
|
||||
static const int block_key;
|
||||
|
||||
@interface _YYUIBarButtonItemBlockTarget : NSObject
|
||||
|
||||
@property (nonatomic, copy) void (^block)(id sender);
|
||||
|
||||
- (id)initWithBlock:(void (^)(id sender))block;
|
||||
- (void)invoke:(id)sender;
|
||||
|
||||
@end
|
||||
|
||||
@implementation _YYUIBarButtonItemBlockTarget
|
||||
|
||||
- (id)initWithBlock:(void (^)(id sender))block{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_block = [block copy];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)invoke:(id)sender {
|
||||
if (self.block) self.block(sender);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation UIBarButtonItem (YYAdd)
|
||||
|
||||
- (void)setActionBlock:(void (^)(id sender))block {
|
||||
_YYUIBarButtonItemBlockTarget *target = [[_YYUIBarButtonItemBlockTarget alloc] initWithBlock:block];
|
||||
objc_setAssociatedObject(self, &block_key, target, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
|
||||
[self setTarget:target];
|
||||
[self setAction:@selector(invoke:)];
|
||||
}
|
||||
|
||||
- (void (^)(id)) actionBlock {
|
||||
_YYUIBarButtonItemBlockTarget *target = objc_getAssociatedObject(self, &block_key);
|
||||
return target.block;
|
||||
}
|
||||
|
||||
@end
|
||||
37
Pods/YYCategories/YYCategories/UIKit/UIBezierPath+YYAdd.h
generated
Normal file
37
Pods/YYCategories/YYCategories/UIKit/UIBezierPath+YYAdd.h
generated
Normal file
@@ -0,0 +1,37 @@
|
||||
//
|
||||
// UIBezierPath+YYAdd.h
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 14/10/30.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
Provides extensions for `UIBezierPath`.
|
||||
*/
|
||||
@interface UIBezierPath (YYAdd)
|
||||
|
||||
/**
|
||||
Creates and returns a new UIBezierPath object initialized with the text glyphs
|
||||
generated from the specified font.
|
||||
|
||||
@discussion It doesnot support apple emoji. If you want get emoji image, try
|
||||
[UIImage imageWithEmoji:size:] in `UIImage(YYAdd)`.
|
||||
|
||||
@param text The text to generate glyph path.
|
||||
@param font The font to generate glyph path.
|
||||
|
||||
@return A new path object with the text and font, or nil if an error occurs.
|
||||
*/
|
||||
+ (nullable UIBezierPath *)bezierPathWithText:(NSString *)text font:(UIFont *)font;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
64
Pods/YYCategories/YYCategories/UIKit/UIBezierPath+YYAdd.m
generated
Normal file
64
Pods/YYCategories/YYCategories/UIKit/UIBezierPath+YYAdd.m
generated
Normal file
@@ -0,0 +1,64 @@
|
||||
//
|
||||
// UIBezierPath+YYAdd.m
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 14/10/30.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import "UIBezierPath+YYAdd.h"
|
||||
#import "UIFont+YYAdd.h"
|
||||
#import <CoreText/CoreText.h>
|
||||
#import "YYCategoriesMacro.h"
|
||||
|
||||
YYSYNTH_DUMMY_CLASS(UIBezierPath_YYAdd)
|
||||
|
||||
|
||||
@implementation UIBezierPath (YYAdd)
|
||||
|
||||
+ (UIBezierPath *)bezierPathWithText:(NSString *)text font:(UIFont *)font {
|
||||
CTFontRef ctFont = font.CTFontRef;
|
||||
if (!ctFont) return nil;
|
||||
NSDictionary *attrs = @{ (__bridge id)kCTFontAttributeName:(__bridge id)ctFont };
|
||||
NSAttributedString *attrString = [[NSAttributedString alloc] initWithString:text attributes:attrs];
|
||||
CFRelease(ctFont);
|
||||
|
||||
CTLineRef line = CTLineCreateWithAttributedString((__bridge CFTypeRef)attrString);
|
||||
if (!line) return nil;
|
||||
|
||||
CGMutablePathRef cgPath = CGPathCreateMutable();
|
||||
CFArrayRef runs = CTLineGetGlyphRuns(line);
|
||||
for (CFIndex iRun = 0, iRunMax = CFArrayGetCount(runs); iRun < iRunMax; iRun++) {
|
||||
CTRunRef run = (CTRunRef)CFArrayGetValueAtIndex(runs, iRun);
|
||||
CTFontRef runFont = CFDictionaryGetValue(CTRunGetAttributes(run), kCTFontAttributeName);
|
||||
|
||||
for (CFIndex iGlyph = 0, iGlyphMax = CTRunGetGlyphCount(run); iGlyph < iGlyphMax; iGlyph++) {
|
||||
CFRange glyphRange = CFRangeMake(iGlyph, 1);
|
||||
CGGlyph glyph;
|
||||
CGPoint position;
|
||||
CTRunGetGlyphs(run, glyphRange, &glyph);
|
||||
CTRunGetPositions(run, glyphRange, &position);
|
||||
|
||||
CGPathRef glyphPath = CTFontCreatePathForGlyph(runFont, glyph, NULL);
|
||||
if (glyphPath) {
|
||||
CGAffineTransform transform = CGAffineTransformMakeTranslation(position.x, position.y);
|
||||
CGPathAddPath(cgPath, &transform, glyphPath);
|
||||
CGPathRelease(glyphPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
UIBezierPath *path = [UIBezierPath bezierPathWithCGPath:cgPath];
|
||||
CGRect boundingBox = CGPathGetPathBoundingBox(cgPath);
|
||||
CFRelease(cgPath);
|
||||
CFRelease(line);
|
||||
|
||||
[path applyTransform:CGAffineTransformMakeScale(1.0, -1.0)];
|
||||
[path applyTransform:CGAffineTransformMakeTranslation(0.0, boundingBox.size.height)];
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
@end
|
||||
358
Pods/YYCategories/YYCategories/UIKit/UIColor+YYAdd.h
generated
Normal file
358
Pods/YYCategories/YYCategories/UIKit/UIColor+YYAdd.h
generated
Normal file
@@ -0,0 +1,358 @@
|
||||
//
|
||||
// UIColor+YYAdd.h
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 13/4/4.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
extern void YY_RGB2HSL(CGFloat r, CGFloat g, CGFloat b,
|
||||
CGFloat *h, CGFloat *s, CGFloat *l);
|
||||
|
||||
extern void YY_HSL2RGB(CGFloat h, CGFloat s, CGFloat l,
|
||||
CGFloat *r, CGFloat *g, CGFloat *b);
|
||||
|
||||
extern void YY_RGB2HSB(CGFloat r, CGFloat g, CGFloat b,
|
||||
CGFloat *h, CGFloat *s, CGFloat *v);
|
||||
|
||||
extern void YY_HSB2RGB(CGFloat h, CGFloat s, CGFloat v,
|
||||
CGFloat *r, CGFloat *g, CGFloat *b);
|
||||
|
||||
extern void YY_RGB2CMYK(CGFloat r, CGFloat g, CGFloat b,
|
||||
CGFloat *c, CGFloat *m, CGFloat *y, CGFloat *k);
|
||||
|
||||
extern void YY_CMYK2RGB(CGFloat c, CGFloat m, CGFloat y, CGFloat k,
|
||||
CGFloat *r, CGFloat *g, CGFloat *b);
|
||||
|
||||
extern void YY_HSB2HSL(CGFloat h, CGFloat s, CGFloat b,
|
||||
CGFloat *hh, CGFloat *ss, CGFloat *ll);
|
||||
|
||||
extern void YY_HSL2HSB(CGFloat h, CGFloat s, CGFloat l,
|
||||
CGFloat *hh, CGFloat *ss, CGFloat *bb);
|
||||
|
||||
|
||||
/*
|
||||
Create UIColor with a hex string.
|
||||
Example: UIColorHex(0xF0F), UIColorHex(66ccff), UIColorHex(#66CCFF88)
|
||||
|
||||
Valid format: #RGB #RGBA #RRGGBB #RRGGBBAA 0xRGB ...
|
||||
The `#` or "0x" sign is not required.
|
||||
*/
|
||||
#ifndef UIColorHex
|
||||
#define UIColorHex(_hex_) [UIColor colorWithHexString:((__bridge NSString *)CFSTR(#_hex_))]
|
||||
#endif
|
||||
|
||||
/**
|
||||
Provide some method for `UIColor` to convert color between
|
||||
RGB,HSB,HSL,CMYK and Hex.
|
||||
|
||||
| Color space | Meaning |
|
||||
|-------------|----------------------------------------|
|
||||
| RGB * | Red, Green, Blue |
|
||||
| HSB(HSV) * | Hue, Saturation, Brightness (Value) |
|
||||
| HSL | Hue, Saturation, Lightness |
|
||||
| CMYK | Cyan, Magenta, Yellow, Black |
|
||||
|
||||
Apple use RGB & HSB default.
|
||||
|
||||
All the value in this category is float number in the range `0.0` to `1.0`.
|
||||
Values below `0.0` are interpreted as `0.0`,
|
||||
and values above `1.0` are interpreted as `1.0`.
|
||||
|
||||
If you want convert color between more color space (CIEXYZ,Lab,YUV...),
|
||||
see https://github.com/ibireme/yy_color_convertor
|
||||
*/
|
||||
@interface UIColor (YYAdd)
|
||||
|
||||
|
||||
#pragma mark - Create a UIColor Object
|
||||
///=============================================================================
|
||||
/// @name Creating a UIColor Object
|
||||
///=============================================================================
|
||||
|
||||
/**
|
||||
Creates and returns a color object using the specified opacity
|
||||
and HSL color space component values.
|
||||
|
||||
@param hue The hue component of the color object in the HSL color space,
|
||||
specified as a value from 0.0 to 1.0.
|
||||
|
||||
@param saturation The saturation component of the color object in the HSL color space,
|
||||
specified as a value from 0.0 to 1.0.
|
||||
|
||||
@param lightness The lightness component of the color object in the HSL color space,
|
||||
specified as a value from 0.0 to 1.0.
|
||||
|
||||
@param alpha The opacity value of the color object,
|
||||
specified as a value from 0.0 to 1.0.
|
||||
|
||||
@return The color object. The color information represented by this
|
||||
object is in the device RGB colorspace.
|
||||
*/
|
||||
+ (UIColor *)colorWithHue:(CGFloat)hue
|
||||
saturation:(CGFloat)saturation
|
||||
lightness:(CGFloat)lightness
|
||||
alpha:(CGFloat)alpha;
|
||||
|
||||
/**
|
||||
Creates and returns a color object using the specified opacity
|
||||
and CMYK color space component values.
|
||||
|
||||
@param cyan The cyan component of the color object in the CMYK color space,
|
||||
specified as a value from 0.0 to 1.0.
|
||||
|
||||
@param magenta The magenta component of the color object in the CMYK color space,
|
||||
specified as a value from 0.0 to 1.0.
|
||||
|
||||
@param yellow The yellow component of the color object in the CMYK color space,
|
||||
specified as a value from 0.0 to 1.0.
|
||||
|
||||
@param black The black component of the color object in the CMYK color space,
|
||||
specified as a value from 0.0 to 1.0.
|
||||
|
||||
@param alpha The opacity value of the color object,
|
||||
specified as a value from 0.0 to 1.0.
|
||||
|
||||
@return The color object. The color information represented by this
|
||||
object is in the device RGB colorspace.
|
||||
*/
|
||||
+ (UIColor *)colorWithCyan:(CGFloat)cyan
|
||||
magenta:(CGFloat)magenta
|
||||
yellow:(CGFloat)yellow
|
||||
black:(CGFloat)black
|
||||
alpha:(CGFloat)alpha;
|
||||
|
||||
/**
|
||||
Creates and returns a color object using the hex RGB color values.
|
||||
|
||||
@param rgbValue The rgb value such as 0x66ccff.
|
||||
|
||||
@return The color object. The color information represented by this
|
||||
object is in the device RGB colorspace.
|
||||
*/
|
||||
+ (UIColor *)colorWithRGB:(uint32_t)rgbValue;
|
||||
|
||||
/**
|
||||
Creates and returns a color object using the hex RGBA color values.
|
||||
|
||||
@param rgbaValue The rgb value such as 0x66ccffff.
|
||||
|
||||
@return The color object. The color information represented by this
|
||||
object is in the device RGB colorspace.
|
||||
*/
|
||||
+ (UIColor *)colorWithRGBA:(uint32_t)rgbaValue;
|
||||
|
||||
/**
|
||||
Creates and returns a color object using the specified opacity and RGB hex value.
|
||||
|
||||
@param rgbValue The rgb value such as 0x66CCFF.
|
||||
|
||||
@param alpha The opacity value of the color object,
|
||||
specified as a value from 0.0 to 1.0.
|
||||
|
||||
@return The color object. The color information represented by this
|
||||
object is in the device RGB colorspace.
|
||||
*/
|
||||
+ (UIColor *)colorWithRGB:(uint32_t)rgbValue alpha:(CGFloat)alpha;
|
||||
|
||||
/**
|
||||
Creates and returns a color object from hex string.
|
||||
|
||||
@discussion:
|
||||
Valid format: #RGB #RGBA #RRGGBB #RRGGBBAA 0xRGB ...
|
||||
The `#` or "0x" sign is not required.
|
||||
The alpha will be set to 1.0 if there is no alpha component.
|
||||
It will return nil when an error occurs in parsing.
|
||||
|
||||
Example: @"0xF0F", @"66ccff", @"#66CCFF88"
|
||||
|
||||
@param hexStr The hex string value for the new color.
|
||||
|
||||
@return An UIColor object from string, or nil if an error occurs.
|
||||
*/
|
||||
+ (nullable UIColor *)colorWithHexString:(NSString *)hexStr;
|
||||
|
||||
/**
|
||||
Creates and returns a color object by add new color.
|
||||
|
||||
@param add the color added
|
||||
|
||||
@param blendMode add color blend mode
|
||||
*/
|
||||
- (UIColor *)colorByAddColor:(UIColor *)add blendMode:(CGBlendMode)blendMode;
|
||||
|
||||
/**
|
||||
Creates and returns a color object by change components.
|
||||
|
||||
@param hueDelta the hue change delta specified as a value
|
||||
from -1.0 to 1.0. 0 means no change.
|
||||
|
||||
@param saturationDelta the saturation change delta specified as a value
|
||||
from -1.0 to 1.0. 0 means no change.
|
||||
|
||||
@param brightnessDelta the brightness change delta specified as a value
|
||||
from -1.0 to 1.0. 0 means no change.
|
||||
|
||||
@param alphaDelta the alpha change delta specified as a value
|
||||
from -1.0 to 1.0. 0 means no change.
|
||||
*/
|
||||
- (UIColor *)colorByChangeHue:(CGFloat)hueDelta
|
||||
saturation:(CGFloat)saturationDelta
|
||||
brightness:(CGFloat)brightnessDelta
|
||||
alpha:(CGFloat)alphaDelta;
|
||||
|
||||
|
||||
#pragma mark - Get color's description
|
||||
///=============================================================================
|
||||
/// @name Get color's description
|
||||
///=============================================================================
|
||||
|
||||
/**
|
||||
Returns the rgb value in hex.
|
||||
@return hex value of RGB,such as 0x66ccff.
|
||||
*/
|
||||
- (uint32_t)rgbValue;
|
||||
|
||||
/**
|
||||
Returns the rgba value in hex.
|
||||
|
||||
@return hex value of RGBA,such as 0x66ccffff.
|
||||
*/
|
||||
- (uint32_t)rgbaValue;
|
||||
|
||||
/**
|
||||
Returns the color's RGB value as a hex string (lowercase).
|
||||
Such as @"0066cc".
|
||||
|
||||
It will return nil when the color space is not RGB
|
||||
|
||||
@return The color's value as a hex string.
|
||||
*/
|
||||
- (nullable NSString *)hexString;
|
||||
|
||||
/**
|
||||
Returns the color's RGBA value as a hex string (lowercase).
|
||||
Such as @"0066ccff".
|
||||
|
||||
It will return nil when the color space is not RGBA
|
||||
|
||||
@return The color's value as a hex string.
|
||||
*/
|
||||
- (nullable NSString *)hexStringWithAlpha;
|
||||
|
||||
|
||||
#pragma mark - Retrieving Color Information
|
||||
///=============================================================================
|
||||
/// @name Retrieving Color Information
|
||||
///=============================================================================
|
||||
|
||||
/**
|
||||
Returns the components that make up the color in the HSL color space.
|
||||
|
||||
@param hue On return, the hue component of the color object,
|
||||
specified as a value between 0.0 and 1.0.
|
||||
|
||||
@param saturation On return, the saturation component of the color object,
|
||||
specified as a value between 0.0 and 1.0.
|
||||
|
||||
@param lightness On return, the lightness component of the color object,
|
||||
specified as a value between 0.0 and 1.0.
|
||||
|
||||
@param alpha On return, the alpha component of the color object,
|
||||
specified as a value between 0.0 and 1.0.
|
||||
|
||||
@return YES if the color could be converted, NO otherwise.
|
||||
*/
|
||||
- (BOOL)getHue:(CGFloat *)hue
|
||||
saturation:(CGFloat *)saturation
|
||||
lightness:(CGFloat *)lightness
|
||||
alpha:(CGFloat *)alpha;
|
||||
|
||||
/**
|
||||
Returns the components that make up the color in the CMYK color space.
|
||||
|
||||
@param cyan On return, the cyan component of the color object,
|
||||
specified as a value between 0.0 and 1.0.
|
||||
|
||||
@param magenta On return, the magenta component of the color object,
|
||||
specified as a value between 0.0 and 1.0.
|
||||
|
||||
@param yellow On return, the yellow component of the color object,
|
||||
specified as a value between 0.0 and 1.0.
|
||||
|
||||
@param black On return, the black component of the color object,
|
||||
specified as a value between 0.0 and 1.0.
|
||||
|
||||
@param alpha On return, the alpha component of the color object,
|
||||
specified as a value between 0.0 and 1.0.
|
||||
|
||||
@return YES if the color could be converted, NO otherwise.
|
||||
*/
|
||||
- (BOOL)getCyan:(CGFloat *)cyan
|
||||
magenta:(CGFloat *)magenta
|
||||
yellow:(CGFloat *)yellow
|
||||
black:(CGFloat *)black
|
||||
alpha:(CGFloat *)alpha;
|
||||
|
||||
/**
|
||||
The color's red component value in RGB color space.
|
||||
The value of this property is a float in the range `0.0` to `1.0`.
|
||||
*/
|
||||
@property (nonatomic, readonly) CGFloat red;
|
||||
|
||||
/**
|
||||
The color's green component value in RGB color space.
|
||||
The value of this property is a float in the range `0.0` to `1.0`.
|
||||
*/
|
||||
@property (nonatomic, readonly) CGFloat green;
|
||||
|
||||
/**
|
||||
The color's blue component value in RGB color space.
|
||||
The value of this property is a float in the range `0.0` to `1.0`.
|
||||
*/
|
||||
@property (nonatomic, readonly) CGFloat blue;
|
||||
|
||||
/**
|
||||
The color's hue component value in HSB color space.
|
||||
The value of this property is a float in the range `0.0` to `1.0`.
|
||||
*/
|
||||
@property (nonatomic, readonly) CGFloat hue;
|
||||
|
||||
/**
|
||||
The color's saturation component value in HSB color space.
|
||||
The value of this property is a float in the range `0.0` to `1.0`.
|
||||
*/
|
||||
@property (nonatomic, readonly) CGFloat saturation;
|
||||
|
||||
/**
|
||||
The color's brightness component value in HSB color space.
|
||||
The value of this property is a float in the range `0.0` to `1.0`.
|
||||
*/
|
||||
@property (nonatomic, readonly) CGFloat brightness;
|
||||
|
||||
/**
|
||||
The color's alpha component value.
|
||||
The value of this property is a float in the range `0.0` to `1.0`.
|
||||
*/
|
||||
@property (nonatomic, readonly) CGFloat alpha;
|
||||
|
||||
/**
|
||||
The color's colorspace model.
|
||||
*/
|
||||
@property (nonatomic, readonly) CGColorSpaceModel colorSpaceModel;
|
||||
|
||||
/**
|
||||
Readable colorspace string.
|
||||
*/
|
||||
@property (nullable, nonatomic, readonly) NSString *colorSpaceString;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
472
Pods/YYCategories/YYCategories/UIKit/UIColor+YYAdd.m
generated
Normal file
472
Pods/YYCategories/YYCategories/UIKit/UIColor+YYAdd.m
generated
Normal file
@@ -0,0 +1,472 @@
|
||||
//
|
||||
// UIColor+YYAdd.m
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 13/4/4.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import "UIColor+YYAdd.h"
|
||||
#import "NSString+YYAdd.h"
|
||||
#import "YYCategoriesMacro.h"
|
||||
|
||||
YYSYNTH_DUMMY_CLASS(UIColor_YYAdd)
|
||||
|
||||
|
||||
#define CLAMP_COLOR_VALUE(v) (v) = (v) < 0 ? 0 : (v) > 1 ? 1 : (v)
|
||||
|
||||
void YY_RGB2HSL(CGFloat r, CGFloat g, CGFloat b,
|
||||
CGFloat *h, CGFloat *s, CGFloat *l) {
|
||||
CLAMP_COLOR_VALUE(r);
|
||||
CLAMP_COLOR_VALUE(g);
|
||||
CLAMP_COLOR_VALUE(b);
|
||||
|
||||
CGFloat max, min, delta, sum;
|
||||
max = fmaxf(r, fmaxf(g, b));
|
||||
min = fminf(r, fminf(g, b));
|
||||
delta = max - min;
|
||||
sum = max + min;
|
||||
|
||||
*l = sum / 2; // Lightness
|
||||
if (delta == 0) { // No Saturation, so Hue is undefined (achromatic)
|
||||
*h = *s = 0;
|
||||
return;
|
||||
}
|
||||
*s = delta / (sum < 1 ? sum : 2 - sum); // Saturation
|
||||
if (r == max) *h = (g - b) / delta / 6; // color between y & m
|
||||
else if (g == max) *h = (2 + (b - r) / delta) / 6; // color between c & y
|
||||
else *h = (4 + (r - g) / delta) / 6; // color between m & y
|
||||
if (*h < 0) *h += 1;
|
||||
}
|
||||
|
||||
void YY_HSL2RGB(CGFloat h, CGFloat s, CGFloat l,
|
||||
CGFloat *r, CGFloat *g, CGFloat *b) {
|
||||
CLAMP_COLOR_VALUE(h);
|
||||
CLAMP_COLOR_VALUE(s);
|
||||
CLAMP_COLOR_VALUE(l);
|
||||
|
||||
if (s == 0) { // No Saturation, Hue is undefined (achromatic)
|
||||
*r = *g = *b = l;
|
||||
return;
|
||||
}
|
||||
|
||||
CGFloat q;
|
||||
q = (l <= 0.5) ? (l * (1 + s)) : (l + s - (l * s));
|
||||
if (q <= 0) {
|
||||
*r = *g = *b = 0.0;
|
||||
} else {
|
||||
*r = *g = *b = 0;
|
||||
int sextant;
|
||||
CGFloat m, sv, fract, vsf, mid1, mid2;
|
||||
m = l + l - q;
|
||||
sv = (q - m) / q;
|
||||
if (h == 1) h = 0;
|
||||
h *= 6.0;
|
||||
sextant = h;
|
||||
fract = h - sextant;
|
||||
vsf = q * sv * fract;
|
||||
mid1 = m + vsf;
|
||||
mid2 = q - vsf;
|
||||
switch (sextant) {
|
||||
case 0: *r = q; *g = mid1; *b = m; break;
|
||||
case 1: *r = mid2; *g = q; *b = m; break;
|
||||
case 2: *r = m; *g = q; *b = mid1; break;
|
||||
case 3: *r = m; *g = mid2; *b = q; break;
|
||||
case 4: *r = mid1; *g = m; *b = q; break;
|
||||
case 5: *r = q; *g = m; *b = mid2; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void YY_RGB2HSB(CGFloat r, CGFloat g, CGFloat b,
|
||||
CGFloat *h, CGFloat *s, CGFloat *v) {
|
||||
CLAMP_COLOR_VALUE(r);
|
||||
CLAMP_COLOR_VALUE(g);
|
||||
CLAMP_COLOR_VALUE(b);
|
||||
|
||||
CGFloat max, min, delta;
|
||||
max = fmax(r, fmax(g, b));
|
||||
min = fmin(r, fmin(g, b));
|
||||
delta = max - min;
|
||||
|
||||
*v = max; // Brightness
|
||||
if (delta == 0) { // No Saturation, so Hue is undefined (achromatic)
|
||||
*h = *s = 0;
|
||||
return;
|
||||
}
|
||||
*s = delta / max; // Saturation
|
||||
|
||||
if (r == max) *h = (g - b) / delta / 6; // color between y & m
|
||||
else if (g == max) *h = (2 + (b - r) / delta) / 6; // color between c & y
|
||||
else *h = (4 + (r - g) / delta) / 6; // color between m & c
|
||||
if (*h < 0) *h += 1;
|
||||
}
|
||||
|
||||
void YY_HSB2RGB(CGFloat h, CGFloat s, CGFloat v,
|
||||
CGFloat *r, CGFloat *g, CGFloat *b) {
|
||||
CLAMP_COLOR_VALUE(h);
|
||||
CLAMP_COLOR_VALUE(s);
|
||||
CLAMP_COLOR_VALUE(v);
|
||||
|
||||
if (s == 0) {
|
||||
*r = *g = *b = v; // No Saturation, so Hue is undefined (Achromatic)
|
||||
} else {
|
||||
int sextant;
|
||||
CGFloat f, p, q, t;
|
||||
if (h == 1) h = 0;
|
||||
h *= 6;
|
||||
sextant = floor(h);
|
||||
f = h - sextant;
|
||||
p = v * (1 - s);
|
||||
q = v * (1 - s * f);
|
||||
t = v * (1 - s * (1 - f));
|
||||
switch (sextant) {
|
||||
case 0: *r = v; *g = t; *b = p; break;
|
||||
case 1: *r = q; *g = v; *b = p; break;
|
||||
case 2: *r = p; *g = v; *b = t; break;
|
||||
case 3: *r = p; *g = q; *b = v; break;
|
||||
case 4: *r = t; *g = p; *b = v; break;
|
||||
case 5: *r = v; *g = p; *b = q; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void YY_RGB2CMYK(CGFloat r, CGFloat g, CGFloat b,
|
||||
CGFloat *c, CGFloat *m, CGFloat *y, CGFloat *k) {
|
||||
CLAMP_COLOR_VALUE(r);
|
||||
CLAMP_COLOR_VALUE(g);
|
||||
CLAMP_COLOR_VALUE(b);
|
||||
|
||||
*c = 1 - r;
|
||||
*m = 1 - g;
|
||||
*y = 1 - b;
|
||||
*k = fmin(*c, fmin(*m, *y));
|
||||
|
||||
if (*k == 1) {
|
||||
*c = *m = *y = 0; // Pure black
|
||||
} else {
|
||||
*c = (*c - *k) / (1 - *k);
|
||||
*m = (*m - *k) / (1 - *k);
|
||||
*y = (*y - *k) / (1 - *k);
|
||||
}
|
||||
}
|
||||
|
||||
void YY_CMYK2RGB(CGFloat c, CGFloat m, CGFloat y, CGFloat k,
|
||||
CGFloat *r, CGFloat *g, CGFloat *b) {
|
||||
CLAMP_COLOR_VALUE(c);
|
||||
CLAMP_COLOR_VALUE(m);
|
||||
CLAMP_COLOR_VALUE(y);
|
||||
CLAMP_COLOR_VALUE(k);
|
||||
|
||||
*r = (1 - c) * (1 - k);
|
||||
*g = (1 - m) * (1 - k);
|
||||
*b = (1 - y) * (1 - k);
|
||||
}
|
||||
|
||||
void YY_HSB2HSL(CGFloat h, CGFloat s, CGFloat b,
|
||||
CGFloat *hh, CGFloat *ss, CGFloat *ll) {
|
||||
CLAMP_COLOR_VALUE(h);
|
||||
CLAMP_COLOR_VALUE(s);
|
||||
CLAMP_COLOR_VALUE(b);
|
||||
|
||||
*hh = h;
|
||||
*ll = (2 - s) * b / 2;
|
||||
if (*ll <= 0.5) {
|
||||
*ss = (s) / ((2 - s));
|
||||
} else {
|
||||
*ss = (s * b) / (2 - (2 - s) * b);
|
||||
}
|
||||
}
|
||||
|
||||
void YY_HSL2HSB(CGFloat h, CGFloat s, CGFloat l,
|
||||
CGFloat *hh, CGFloat *ss, CGFloat *bb) {
|
||||
CLAMP_COLOR_VALUE(h);
|
||||
CLAMP_COLOR_VALUE(s);
|
||||
CLAMP_COLOR_VALUE(l);
|
||||
|
||||
*hh = h;
|
||||
if (l <= 0.5) {
|
||||
*bb = (s + 1) * l;
|
||||
*ss = (2 * s) / (s + 1);
|
||||
} else {
|
||||
*bb = l + s * (1 - l);
|
||||
*ss = (2 * s * (1 - l)) / *bb;
|
||||
}
|
||||
}
|
||||
|
||||
@implementation UIColor (YYAdd)
|
||||
|
||||
+ (UIColor *)colorWithHue:(CGFloat)hue
|
||||
saturation:(CGFloat)saturation
|
||||
lightness:(CGFloat)lightness
|
||||
alpha:(CGFloat)alpha {
|
||||
CGFloat r, g, b;
|
||||
YY_HSL2RGB(hue, saturation, lightness, &r, &g, &b);
|
||||
return [UIColor colorWithRed:r green:g blue:b alpha:alpha];
|
||||
}
|
||||
+ (UIColor *)colorWithCyan:(CGFloat)cyan
|
||||
magenta:(CGFloat)magenta
|
||||
yellow:(CGFloat)yellow
|
||||
black:(CGFloat)black
|
||||
alpha:(CGFloat)alpha {
|
||||
CGFloat r, g, b;
|
||||
YY_CMYK2RGB(cyan, magenta, yellow, black, &r, &g, &b);
|
||||
return [UIColor colorWithRed:r green:g blue:b alpha:alpha];
|
||||
}
|
||||
|
||||
+ (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];
|
||||
}
|
||||
|
||||
+ (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];
|
||||
}
|
||||
|
||||
- (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;
|
||||
}
|
||||
|
||||
- (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;
|
||||
}
|
||||
|
||||
static inline NSUInteger hexStrToInt(NSString *str) {
|
||||
uint32_t result = 0;
|
||||
sscanf([str UTF8String], "%X", &result);
|
||||
return result;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
+ (instancetype)colorWithHexString:(NSString *)hexStr {
|
||||
CGFloat r, g, b, a;
|
||||
if (hexStrToRGBA(hexStr, &r, &g, &b, &a)) {
|
||||
return [UIColor colorWithRed:r green:g blue:b alpha:a];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSString *)hexString {
|
||||
return [self hexStringWithAlpha:NO];
|
||||
}
|
||||
|
||||
- (NSString *)hexStringWithAlpha {
|
||||
return [self hexStringWithAlpha:YES];
|
||||
}
|
||||
|
||||
- (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;
|
||||
}
|
||||
|
||||
- (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];
|
||||
}
|
||||
|
||||
- (UIColor *)colorByChangeHue:(CGFloat)h saturation:(CGFloat)s brightness:(CGFloat)b alpha:(CGFloat)a {
|
||||
CGFloat hh, ss, bb, aa;
|
||||
if (![self getHue:&hh saturation:&ss brightness:&bb alpha:&aa]) {
|
||||
return self;
|
||||
}
|
||||
hh += h;
|
||||
ss += s;
|
||||
bb += b;
|
||||
aa += a;
|
||||
hh -= (int)hh;
|
||||
hh = hh < 0 ? hh + 1 : hh;
|
||||
ss = ss < 0 ? 0 : ss > 1 ? 1 : ss;
|
||||
bb = bb < 0 ? 0 : bb > 1 ? 1 : bb;
|
||||
aa = aa < 0 ? 0 : aa > 1 ? 1 : aa;
|
||||
return [UIColor colorWithHue:hh saturation:ss brightness:bb alpha:aa];
|
||||
}
|
||||
|
||||
- (BOOL)getHue:(CGFloat *)hue
|
||||
saturation:(CGFloat *)saturation
|
||||
lightness:(CGFloat *)lightness
|
||||
alpha:(CGFloat *)alpha {
|
||||
CGFloat r, g, b, a;
|
||||
if (![self getRed:&r green:&g blue:&b alpha:&a]) {
|
||||
return NO;
|
||||
}
|
||||
YY_RGB2HSL(r, g, b, hue, saturation, lightness);
|
||||
*alpha = a;
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)getCyan:(CGFloat *)cyan
|
||||
magenta:(CGFloat *)magenta
|
||||
yellow:(CGFloat *)yellow
|
||||
black:(CGFloat *)black
|
||||
alpha:(CGFloat *)alpha {
|
||||
CGFloat r, g, b, a;
|
||||
if (![self getRed:&r green:&g blue:&b alpha:&a]) {
|
||||
return NO;
|
||||
}
|
||||
YY_RGB2CMYK(r, g, b, cyan, magenta, yellow, black);
|
||||
*alpha = a;
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (CGFloat)red {
|
||||
CGFloat r = 0, g, b, a;
|
||||
[self getRed:&r green:&g blue:&b alpha:&a];
|
||||
return r;
|
||||
}
|
||||
|
||||
- (CGFloat)green {
|
||||
CGFloat r, g = 0, b, a;
|
||||
[self getRed:&r green:&g blue:&b alpha:&a];
|
||||
return g;
|
||||
}
|
||||
|
||||
- (CGFloat)blue {
|
||||
CGFloat r, g, b = 0, a;
|
||||
[self getRed:&r green:&g blue:&b alpha:&a];
|
||||
return b;
|
||||
}
|
||||
|
||||
- (CGFloat)alpha {
|
||||
return CGColorGetAlpha(self.CGColor);
|
||||
}
|
||||
|
||||
- (CGFloat)hue {
|
||||
CGFloat h = 0, s, b, a;
|
||||
[self getHue:&h saturation:&s brightness:&b alpha:&a];
|
||||
return h;
|
||||
}
|
||||
|
||||
- (CGFloat)saturation {
|
||||
CGFloat h, s = 0, b, a;
|
||||
[self getHue:&h saturation:&s brightness:&b alpha:&a];
|
||||
return s;
|
||||
}
|
||||
|
||||
- (CGFloat)brightness {
|
||||
CGFloat h, s, b = 0, a;
|
||||
[self getHue:&h saturation:&s brightness:&b alpha:&a];
|
||||
return b;
|
||||
}
|
||||
|
||||
- (CGColorSpaceModel)colorSpaceModel {
|
||||
return CGColorSpaceGetModel(CGColorGetColorSpace(self.CGColor));
|
||||
}
|
||||
|
||||
- (NSString *)colorSpaceString {
|
||||
CGColorSpaceModel model = CGColorSpaceGetModel(CGColorGetColorSpace(self.CGColor));
|
||||
switch (model) {
|
||||
case kCGColorSpaceModelUnknown:
|
||||
return @"kCGColorSpaceModelUnknown";
|
||||
|
||||
case kCGColorSpaceModelMonochrome:
|
||||
return @"kCGColorSpaceModelMonochrome";
|
||||
|
||||
case kCGColorSpaceModelRGB:
|
||||
return @"kCGColorSpaceModelRGB";
|
||||
|
||||
case kCGColorSpaceModelCMYK:
|
||||
return @"kCGColorSpaceModelCMYK";
|
||||
|
||||
case kCGColorSpaceModelLab:
|
||||
return @"kCGColorSpaceModelLab";
|
||||
|
||||
case kCGColorSpaceModelDeviceN:
|
||||
return @"kCGColorSpaceModelDeviceN";
|
||||
|
||||
case kCGColorSpaceModelIndexed:
|
||||
return @"kCGColorSpaceModelIndexed";
|
||||
|
||||
case kCGColorSpaceModelPattern:
|
||||
return @"kCGColorSpaceModelPattern";
|
||||
|
||||
default:
|
||||
return @"ColorSpaceInvalid";
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
78
Pods/YYCategories/YYCategories/UIKit/UIControl+YYAdd.h
generated
Normal file
78
Pods/YYCategories/YYCategories/UIKit/UIControl+YYAdd.h
generated
Normal file
@@ -0,0 +1,78 @@
|
||||
//
|
||||
// UIControl+YYAdd.h
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 13/4/5.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
Provides extensions for `UIControl`.
|
||||
*/
|
||||
@interface UIControl (YYAdd)
|
||||
|
||||
/**
|
||||
Removes all targets and actions for a particular event (or events)
|
||||
from an internal dispatch table.
|
||||
*/
|
||||
- (void)removeAllTargets;
|
||||
|
||||
/**
|
||||
Adds or replaces a target and action for a particular event (or events)
|
||||
to an internal dispatch table.
|
||||
|
||||
@param target The target object—that is, the object to which the
|
||||
action message is sent. If this is nil, the responder
|
||||
chain is searched for an object willing to respond to the
|
||||
action message.
|
||||
|
||||
@param action A selector identifying an action message. It cannot be NULL.
|
||||
|
||||
@param controlEvents A bitmask specifying the control events for which the
|
||||
action message is sent.
|
||||
*/
|
||||
- (void)setTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents;
|
||||
|
||||
/**
|
||||
Adds a block for a particular event (or events) to an internal dispatch table.
|
||||
It will cause a strong reference to @a block.
|
||||
|
||||
@param block The block which is invoked then the action message is
|
||||
sent (cannot be nil). The block is retained.
|
||||
|
||||
@param controlEvents A bitmask specifying the control events for which the
|
||||
action message is sent.
|
||||
*/
|
||||
- (void)addBlockForControlEvents:(UIControlEvents)controlEvents block:(void (^)(id sender))block;
|
||||
|
||||
/**
|
||||
Adds or replaces a block for a particular event (or events) to an internal
|
||||
dispatch table. It will cause a strong reference to @a block.
|
||||
|
||||
@param block The block which is invoked then the action message is
|
||||
sent (cannot be nil). The block is retained.
|
||||
|
||||
@param controlEvents A bitmask specifying the control events for which the
|
||||
action message is sent.
|
||||
*/
|
||||
- (void)setBlockForControlEvents:(UIControlEvents)controlEvents block:(void (^)(id sender))block;
|
||||
|
||||
/**
|
||||
Removes all blocks for a particular event (or events) from an internal
|
||||
dispatch table.
|
||||
|
||||
@param controlEvents A bitmask specifying the control events for which the
|
||||
action message is sent.
|
||||
*/
|
||||
- (void)removeAllBlocksForControlEvents:(UIControlEvents)controlEvents;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
118
Pods/YYCategories/YYCategories/UIKit/UIControl+YYAdd.m
generated
Normal file
118
Pods/YYCategories/YYCategories/UIKit/UIControl+YYAdd.m
generated
Normal file
@@ -0,0 +1,118 @@
|
||||
//
|
||||
// UIControl+YYAdd.m
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 13/4/5.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import "UIControl+YYAdd.h"
|
||||
#import "YYCategoriesMacro.h"
|
||||
#import <objc/runtime.h>
|
||||
|
||||
YYSYNTH_DUMMY_CLASS(UIControl_YYAdd)
|
||||
|
||||
|
||||
static const int block_key;
|
||||
|
||||
@interface _YYUIControlBlockTarget : NSObject
|
||||
|
||||
@property (nonatomic, copy) void (^block)(id sender);
|
||||
@property (nonatomic, assign) UIControlEvents events;
|
||||
|
||||
- (id)initWithBlock:(void (^)(id sender))block events:(UIControlEvents)events;
|
||||
- (void)invoke:(id)sender;
|
||||
|
||||
@end
|
||||
|
||||
@implementation _YYUIControlBlockTarget
|
||||
|
||||
- (id)initWithBlock:(void (^)(id sender))block events:(UIControlEvents)events {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_block = [block copy];
|
||||
_events = events;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)invoke:(id)sender {
|
||||
if (_block) _block(sender);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
@implementation UIControl (YYAdd)
|
||||
|
||||
- (void)removeAllTargets {
|
||||
[[self allTargets] enumerateObjectsUsingBlock: ^(id object, BOOL *stop) {
|
||||
[self removeTarget:object action:NULL forControlEvents:UIControlEventAllEvents];
|
||||
}];
|
||||
[[self _yy_allUIControlBlockTargets] removeAllObjects];
|
||||
}
|
||||
|
||||
- (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];
|
||||
}
|
||||
|
||||
- (void)addBlockForControlEvents:(UIControlEvents)controlEvents
|
||||
block:(void (^)(id sender))block {
|
||||
if (!controlEvents) return;
|
||||
_YYUIControlBlockTarget *target = [[_YYUIControlBlockTarget alloc]
|
||||
initWithBlock:block events:controlEvents];
|
||||
[self addTarget:target action:@selector(invoke:) forControlEvents:controlEvents];
|
||||
NSMutableArray *targets = [self _yy_allUIControlBlockTargets];
|
||||
[targets addObject:target];
|
||||
}
|
||||
|
||||
- (void)setBlockForControlEvents:(UIControlEvents)controlEvents
|
||||
block:(void (^)(id sender))block {
|
||||
[self removeAllBlocksForControlEvents:UIControlEventAllEvents];
|
||||
[self addBlockForControlEvents:controlEvents block:block];
|
||||
}
|
||||
|
||||
- (void)removeAllBlocksForControlEvents:(UIControlEvents)controlEvents {
|
||||
if (!controlEvents) return;
|
||||
|
||||
NSMutableArray *targets = [self _yy_allUIControlBlockTargets];
|
||||
NSMutableArray *removes = [NSMutableArray array];
|
||||
for (_YYUIControlBlockTarget *target in targets) {
|
||||
if (target.events & controlEvents) {
|
||||
UIControlEvents newEvent = target.events & (~controlEvents);
|
||||
if (newEvent) {
|
||||
[self removeTarget:target action:@selector(invoke:) forControlEvents:target.events];
|
||||
target.events = newEvent;
|
||||
[self addTarget:target action:@selector(invoke:) forControlEvents:target.events];
|
||||
} else {
|
||||
[self removeTarget:target action:@selector(invoke:) forControlEvents:target.events];
|
||||
[removes addObject:target];
|
||||
}
|
||||
}
|
||||
}
|
||||
[targets removeObjectsInArray:removes];
|
||||
}
|
||||
|
||||
- (NSMutableArray *)_yy_allUIControlBlockTargets {
|
||||
NSMutableArray *targets = objc_getAssociatedObject(self, &block_key);
|
||||
if (!targets) {
|
||||
targets = [NSMutableArray array];
|
||||
objc_setAssociatedObject(self, &block_key, targets, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
return targets;
|
||||
}
|
||||
|
||||
@end
|
||||
191
Pods/YYCategories/YYCategories/UIKit/UIDevice+YYAdd.h
generated
Normal file
191
Pods/YYCategories/YYCategories/UIKit/UIDevice+YYAdd.h
generated
Normal file
@@ -0,0 +1,191 @@
|
||||
//
|
||||
// UIDevice+YYAdd.h
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 13/4/3.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
Provides extensions for `UIDevice`.
|
||||
*/
|
||||
@interface UIDevice (YYAdd)
|
||||
|
||||
|
||||
#pragma mark - Device Information
|
||||
///=============================================================================
|
||||
/// @name Device Information
|
||||
///=============================================================================
|
||||
|
||||
/// Device system version (e.g. 8.1)
|
||||
+ (double)systemVersion;
|
||||
|
||||
/// Whether the device is iPad/iPad mini.
|
||||
@property (nonatomic, readonly) BOOL isPad;
|
||||
|
||||
/// Whether the device is a simulator.
|
||||
@property (nonatomic, readonly) BOOL isSimulator;
|
||||
|
||||
/// Whether the device is jailbroken.
|
||||
@property (nonatomic, readonly) BOOL isJailbroken;
|
||||
|
||||
/// Wherher the device can make phone calls.
|
||||
@property (nonatomic, readonly) BOOL canMakePhoneCalls NS_EXTENSION_UNAVAILABLE_IOS("");
|
||||
|
||||
/// The device's machine model. e.g. "iPhone6,1" "iPad4,6"
|
||||
/// @see http://theiphonewiki.com/wiki/Models
|
||||
@property (nullable, nonatomic, readonly) NSString *machineModel;
|
||||
|
||||
/// The device's machine model name. e.g. "iPhone 5s" "iPad mini 2"
|
||||
/// @see http://theiphonewiki.com/wiki/Models
|
||||
@property (nullable, nonatomic, readonly) NSString *machineModelName;
|
||||
|
||||
/// The System's startup time.
|
||||
@property (nonatomic, readonly) NSDate *systemUptime;
|
||||
|
||||
|
||||
#pragma mark - Network Information
|
||||
///=============================================================================
|
||||
/// @name Network Information
|
||||
///=============================================================================
|
||||
|
||||
/// WIFI IP address of this device (can be nil). e.g. @"192.168.1.111"
|
||||
@property (nullable, nonatomic, readonly) NSString *ipAddressWIFI;
|
||||
|
||||
/// Cell IP address of this device (can be nil). e.g. @"10.2.2.222"
|
||||
@property (nullable, nonatomic, readonly) NSString *ipAddressCell;
|
||||
|
||||
|
||||
/**
|
||||
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.
|
||||
*/
|
||||
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,
|
||||
};
|
||||
|
||||
/**
|
||||
Get device network traffic bytes.
|
||||
|
||||
@discussion This is a counter since the device's last boot time.
|
||||
Usage:
|
||||
|
||||
uint64_t bytes = [[UIDevice currentDevice] getNetworkTrafficBytes:YYNetworkTrafficTypeALL];
|
||||
NSTimeInterval time = CACurrentMediaTime();
|
||||
|
||||
uint64_t bytesPerSecond = (bytes - _lastBytes) / (time - _lastTime);
|
||||
|
||||
_lastBytes = bytes;
|
||||
_lastTime = time;
|
||||
|
||||
|
||||
@param type traffic types
|
||||
@return bytes counter.
|
||||
*/
|
||||
- (uint64_t)getNetworkTrafficBytes:(YYNetworkTrafficType)types;
|
||||
|
||||
#pragma mark - Disk Space
|
||||
///=============================================================================
|
||||
/// @name Disk Space
|
||||
///=============================================================================
|
||||
|
||||
/// Total disk space in byte. (-1 when error occurs)
|
||||
@property (nonatomic, readonly) int64_t diskSpace;
|
||||
|
||||
/// Free disk space in byte. (-1 when error occurs)
|
||||
@property (nonatomic, readonly) int64_t diskSpaceFree;
|
||||
|
||||
/// Used disk space in byte. (-1 when error occurs)
|
||||
@property (nonatomic, readonly) int64_t diskSpaceUsed;
|
||||
|
||||
|
||||
#pragma mark - Memory Information
|
||||
///=============================================================================
|
||||
/// @name Memory Information
|
||||
///=============================================================================
|
||||
|
||||
/// Total physical memory in byte. (-1 when error occurs)
|
||||
@property (nonatomic, readonly) int64_t memoryTotal;
|
||||
|
||||
/// Used (active + inactive + wired) memory in byte. (-1 when error occurs)
|
||||
@property (nonatomic, readonly) int64_t memoryUsed;
|
||||
|
||||
/// Free memory in byte. (-1 when error occurs)
|
||||
@property (nonatomic, readonly) int64_t memoryFree;
|
||||
|
||||
/// Acvite memory in byte. (-1 when error occurs)
|
||||
@property (nonatomic, readonly) int64_t memoryActive;
|
||||
|
||||
/// Inactive memory in byte. (-1 when error occurs)
|
||||
@property (nonatomic, readonly) int64_t memoryInactive;
|
||||
|
||||
/// Wired memory in byte. (-1 when error occurs)
|
||||
@property (nonatomic, readonly) int64_t memoryWired;
|
||||
|
||||
/// Purgable memory in byte. (-1 when error occurs)
|
||||
@property (nonatomic, readonly) int64_t memoryPurgable;
|
||||
|
||||
#pragma mark - CPU Information
|
||||
///=============================================================================
|
||||
/// @name CPU Information
|
||||
///=============================================================================
|
||||
|
||||
/// Avaliable CPU processor count.
|
||||
@property (nonatomic, readonly) NSUInteger cpuCount;
|
||||
|
||||
/// Current CPU usage, 1.0 means 100%. (-1 when error occurs)
|
||||
@property (nonatomic, readonly) float cpuUsage;
|
||||
|
||||
/// Current CPU usage per processor (array of NSNumber), 1.0 means 100%. (nil when error occurs)
|
||||
@property (nullable, nonatomic, readonly) NSArray<NSNumber *> *cpuUsagePerProcessor;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
#ifndef kSystemVersion
|
||||
#define kSystemVersion [UIDevice systemVersion]
|
||||
#endif
|
||||
|
||||
#ifndef kiOS6Later
|
||||
#define kiOS6Later (kSystemVersion >= 6)
|
||||
#endif
|
||||
|
||||
#ifndef kiOS7Later
|
||||
#define kiOS7Later (kSystemVersion >= 7)
|
||||
#endif
|
||||
|
||||
#ifndef kiOS8Later
|
||||
#define kiOS8Later (kSystemVersion >= 8)
|
||||
#endif
|
||||
|
||||
#ifndef kiOS9Later
|
||||
#define kiOS9Later (kSystemVersion >= 9)
|
||||
#endif
|
||||
516
Pods/YYCategories/YYCategories/UIKit/UIDevice+YYAdd.m
generated
Normal file
516
Pods/YYCategories/YYCategories/UIKit/UIDevice+YYAdd.m
generated
Normal file
@@ -0,0 +1,516 @@
|
||||
//
|
||||
// UIDevice+YYAdd.m
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 13/4/3.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import "UIDevice+YYAdd.h"
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <mach/mach.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <ifaddrs.h>
|
||||
#import "YYCategoriesMacro.h"
|
||||
#import "NSString+YYAdd.h"
|
||||
|
||||
YYSYNTH_DUMMY_CLASS(UIDevice_YYAdd)
|
||||
|
||||
|
||||
@implementation UIDevice (YYAdd)
|
||||
|
||||
+ (double)systemVersion {
|
||||
static double version;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
version = [UIDevice currentDevice].systemVersion.doubleValue;
|
||||
});
|
||||
return version;
|
||||
}
|
||||
|
||||
- (BOOL)isPad {
|
||||
static dispatch_once_t one;
|
||||
static BOOL pad;
|
||||
dispatch_once(&one, ^{
|
||||
pad = UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad;
|
||||
});
|
||||
return pad;
|
||||
}
|
||||
|
||||
- (BOOL)isSimulator {
|
||||
static dispatch_once_t one;
|
||||
static BOOL simu;
|
||||
dispatch_once(&one, ^{
|
||||
simu = NSNotFound != [[self model] rangeOfString:@"Simulator"].location;
|
||||
});
|
||||
return simu;
|
||||
}
|
||||
|
||||
- (BOOL)isJailbroken {
|
||||
if ([self isSimulator]) return NO; // Dont't check simulator
|
||||
|
||||
// iOS9 URL Scheme query changed ...
|
||||
// NSURL *cydiaURL = [NSURL URLWithString:@"cydia://package"];
|
||||
// if ([[UIApplication sharedApplication] canOpenURL:cydiaURL]) return YES;
|
||||
|
||||
NSArray *paths = @[@"/Applications/Cydia.app",
|
||||
@"/private/var/lib/apt/",
|
||||
@"/private/var/lib/cydia",
|
||||
@"/private/var/stash"];
|
||||
for (NSString *path in paths) {
|
||||
if ([[NSFileManager defaultManager] fileExistsAtPath:path]) return YES;
|
||||
}
|
||||
|
||||
FILE *bash = fopen("/bin/bash", "r");
|
||||
if (bash != NULL) {
|
||||
fclose(bash);
|
||||
return YES;
|
||||
}
|
||||
|
||||
NSString *path = [NSString stringWithFormat:@"/private/%@", [NSString stringWithUUID]];
|
||||
if ([@"test" writeToFile : path atomically : YES encoding : NSUTF8StringEncoding error : NULL]) {
|
||||
[[NSFileManager defaultManager] removeItemAtPath:path error:nil];
|
||||
return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
#ifdef __IPHONE_OS_VERSION_MIN_REQUIRED
|
||||
- (BOOL)canMakePhoneCalls {
|
||||
__block BOOL can;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
can = [[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"tel://"]];
|
||||
});
|
||||
return can;
|
||||
}
|
||||
#endif
|
||||
|
||||
- (NSString *)ipAddressWithIfaName:(NSString *)name {
|
||||
if (name.length == 0) return nil;
|
||||
NSString *address = nil;
|
||||
struct ifaddrs *addrs = NULL;
|
||||
if (getifaddrs(&addrs) == 0) {
|
||||
struct ifaddrs *addr = addrs;
|
||||
while (addr) {
|
||||
if ([[NSString stringWithUTF8String:addr->ifa_name] isEqualToString:name]) {
|
||||
sa_family_t family = addr->ifa_addr->sa_family;
|
||||
switch (family) {
|
||||
case AF_INET: { // IPv4
|
||||
char str[INET_ADDRSTRLEN] = {0};
|
||||
inet_ntop(family, &(((struct sockaddr_in *)addr->ifa_addr)->sin_addr), str, sizeof(str));
|
||||
if (strlen(str) > 0) {
|
||||
address = [NSString stringWithUTF8String:str];
|
||||
}
|
||||
} break;
|
||||
|
||||
case AF_INET6: { // IPv6
|
||||
char str[INET6_ADDRSTRLEN] = {0};
|
||||
inet_ntop(family, &(((struct sockaddr_in6 *)addr->ifa_addr)->sin6_addr), str, sizeof(str));
|
||||
if (strlen(str) > 0) {
|
||||
address = [NSString stringWithUTF8String:str];
|
||||
}
|
||||
}
|
||||
|
||||
default: break;
|
||||
}
|
||||
if (address) break;
|
||||
}
|
||||
addr = addr->ifa_next;
|
||||
}
|
||||
}
|
||||
freeifaddrs(addrs);
|
||||
return address;
|
||||
}
|
||||
|
||||
- (NSString *)ipAddressWIFI {
|
||||
return [self ipAddressWithIfaName:@"en0"];
|
||||
}
|
||||
|
||||
- (NSString *)ipAddressCell {
|
||||
return [self ipAddressWithIfaName:@"pdp_ip0"];
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static uint64_t yy_net_counter_get_by_type(yy_net_interface_counter *counter, YYNetworkTrafficType type) {
|
||||
uint64_t bytes = 0;
|
||||
if (type & YYNetworkTrafficTypeWWANSent) bytes += counter->pdp_ip_out;
|
||||
if (type & YYNetworkTrafficTypeWWANReceived) bytes += counter->pdp_ip_in;
|
||||
if (type & YYNetworkTrafficTypeWIFISent) bytes += counter->en_out;
|
||||
if (type & YYNetworkTrafficTypeWIFIReceived) bytes += counter->en_in;
|
||||
if (type & YYNetworkTrafficTypeAWDLSent) bytes += counter->awdl_out;
|
||||
if (type & YYNetworkTrafficTypeAWDLReceived) bytes += counter->awdl_in;
|
||||
return bytes;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
- (uint64_t)getNetworkTrafficBytes:(YYNetworkTrafficType)types {
|
||||
yy_net_interface_counter counter = yy_get_net_interface_counter();
|
||||
return yy_net_counter_get_by_type(&counter, types);
|
||||
}
|
||||
|
||||
- (NSString *)machineModel {
|
||||
static dispatch_once_t one;
|
||||
static NSString *model;
|
||||
dispatch_once(&one, ^{
|
||||
size_t size;
|
||||
sysctlbyname("hw.machine", NULL, &size, NULL, 0);
|
||||
char *machine = malloc(size);
|
||||
sysctlbyname("hw.machine", machine, &size, NULL, 0);
|
||||
model = [NSString stringWithUTF8String:machine];
|
||||
free(machine);
|
||||
});
|
||||
return model;
|
||||
}
|
||||
|
||||
- (NSString *)machineModelName {
|
||||
static dispatch_once_t one;
|
||||
static NSString *name;
|
||||
dispatch_once(&one, ^{
|
||||
NSString *model = [self machineModel];
|
||||
if (!model) return;
|
||||
NSDictionary *dic = @{
|
||||
@"Watch1,1" : @"Apple Watch 38mm",
|
||||
@"Watch1,2" : @"Apple Watch 42mm",
|
||||
@"Watch2,3" : @"Apple Watch Series 2 38mm",
|
||||
@"Watch2,4" : @"Apple Watch Series 2 42mm",
|
||||
@"Watch2,6" : @"Apple Watch Series 1 38mm",
|
||||
@"Watch1,7" : @"Apple Watch Series 1 42mm",
|
||||
|
||||
@"iPod1,1" : @"iPod touch 1",
|
||||
@"iPod2,1" : @"iPod touch 2",
|
||||
@"iPod3,1" : @"iPod touch 3",
|
||||
@"iPod4,1" : @"iPod touch 4",
|
||||
@"iPod5,1" : @"iPod touch 5",
|
||||
@"iPod7,1" : @"iPod touch 6",
|
||||
|
||||
@"iPhone1,1" : @"iPhone 1G",
|
||||
@"iPhone1,2" : @"iPhone 3G",
|
||||
@"iPhone2,1" : @"iPhone 3GS",
|
||||
@"iPhone3,1" : @"iPhone 4 (GSM)",
|
||||
@"iPhone3,2" : @"iPhone 4",
|
||||
@"iPhone3,3" : @"iPhone 4 (CDMA)",
|
||||
@"iPhone4,1" : @"iPhone 4S",
|
||||
@"iPhone5,1" : @"iPhone 5",
|
||||
@"iPhone5,2" : @"iPhone 5",
|
||||
@"iPhone5,3" : @"iPhone 5c",
|
||||
@"iPhone5,4" : @"iPhone 5c",
|
||||
@"iPhone6,1" : @"iPhone 5s",
|
||||
@"iPhone6,2" : @"iPhone 5s",
|
||||
@"iPhone7,1" : @"iPhone 6 Plus",
|
||||
@"iPhone7,2" : @"iPhone 6",
|
||||
@"iPhone8,1" : @"iPhone 6s",
|
||||
@"iPhone8,2" : @"iPhone 6s Plus",
|
||||
@"iPhone8,4" : @"iPhone SE",
|
||||
@"iPhone9,1" : @"iPhone 7",
|
||||
@"iPhone9,2" : @"iPhone 7 Plus",
|
||||
@"iPhone9,3" : @"iPhone 7",
|
||||
@"iPhone9,4" : @"iPhone 7 Plus",
|
||||
|
||||
@"iPad1,1" : @"iPad 1",
|
||||
@"iPad2,1" : @"iPad 2 (WiFi)",
|
||||
@"iPad2,2" : @"iPad 2 (GSM)",
|
||||
@"iPad2,3" : @"iPad 2 (CDMA)",
|
||||
@"iPad2,4" : @"iPad 2",
|
||||
@"iPad2,5" : @"iPad mini 1",
|
||||
@"iPad2,6" : @"iPad mini 1",
|
||||
@"iPad2,7" : @"iPad mini 1",
|
||||
@"iPad3,1" : @"iPad 3 (WiFi)",
|
||||
@"iPad3,2" : @"iPad 3 (4G)",
|
||||
@"iPad3,3" : @"iPad 3 (4G)",
|
||||
@"iPad3,4" : @"iPad 4",
|
||||
@"iPad3,5" : @"iPad 4",
|
||||
@"iPad3,6" : @"iPad 4",
|
||||
@"iPad4,1" : @"iPad Air",
|
||||
@"iPad4,2" : @"iPad Air",
|
||||
@"iPad4,3" : @"iPad Air",
|
||||
@"iPad4,4" : @"iPad mini 2",
|
||||
@"iPad4,5" : @"iPad mini 2",
|
||||
@"iPad4,6" : @"iPad mini 2",
|
||||
@"iPad4,7" : @"iPad mini 3",
|
||||
@"iPad4,8" : @"iPad mini 3",
|
||||
@"iPad4,9" : @"iPad mini 3",
|
||||
@"iPad5,1" : @"iPad mini 4",
|
||||
@"iPad5,2" : @"iPad mini 4",
|
||||
@"iPad5,3" : @"iPad Air 2",
|
||||
@"iPad5,4" : @"iPad Air 2",
|
||||
@"iPad6,3" : @"iPad Pro (9.7 inch)",
|
||||
@"iPad6,4" : @"iPad Pro (9.7 inch)",
|
||||
@"iPad6,7" : @"iPad Pro (12.9 inch)",
|
||||
@"iPad6,8" : @"iPad Pro (12.9 inch)",
|
||||
|
||||
@"AppleTV2,1" : @"Apple TV 2",
|
||||
@"AppleTV3,1" : @"Apple TV 3",
|
||||
@"AppleTV3,2" : @"Apple TV 3",
|
||||
@"AppleTV5,3" : @"Apple TV 4",
|
||||
|
||||
@"i386" : @"Simulator x86",
|
||||
@"x86_64" : @"Simulator x64",
|
||||
};
|
||||
name = dic[model];
|
||||
if (!name) name = model;
|
||||
});
|
||||
return name;
|
||||
}
|
||||
|
||||
- (NSDate *)systemUptime {
|
||||
NSTimeInterval time = [[NSProcessInfo processInfo] systemUptime];
|
||||
return [[NSDate alloc] initWithTimeIntervalSinceNow:(0 - time)];
|
||||
}
|
||||
|
||||
- (int64_t)diskSpace {
|
||||
NSError *error = nil;
|
||||
NSDictionary *attrs = [[NSFileManager defaultManager] attributesOfFileSystemForPath:NSHomeDirectory() error:&error];
|
||||
if (error) return -1;
|
||||
int64_t space = [[attrs objectForKey:NSFileSystemSize] longLongValue];
|
||||
if (space < 0) space = -1;
|
||||
return space;
|
||||
}
|
||||
|
||||
- (int64_t)diskSpaceFree {
|
||||
NSError *error = nil;
|
||||
NSDictionary *attrs = [[NSFileManager defaultManager] attributesOfFileSystemForPath:NSHomeDirectory() error:&error];
|
||||
if (error) return -1;
|
||||
int64_t space = [[attrs objectForKey:NSFileSystemFreeSize] longLongValue];
|
||||
if (space < 0) space = -1;
|
||||
return space;
|
||||
}
|
||||
|
||||
- (int64_t)diskSpaceUsed {
|
||||
int64_t total = self.diskSpace;
|
||||
int64_t free = self.diskSpaceFree;
|
||||
if (total < 0 || free < 0) return -1;
|
||||
int64_t used = total - free;
|
||||
if (used < 0) used = -1;
|
||||
return used;
|
||||
}
|
||||
|
||||
- (int64_t)memoryTotal {
|
||||
int64_t mem = [[NSProcessInfo processInfo] physicalMemory];
|
||||
if (mem < -1) mem = -1;
|
||||
return mem;
|
||||
}
|
||||
|
||||
- (int64_t)memoryUsed {
|
||||
mach_port_t host_port = mach_host_self();
|
||||
mach_msg_type_number_t host_size = sizeof(vm_statistics_data_t) / sizeof(integer_t);
|
||||
vm_size_t page_size;
|
||||
vm_statistics_data_t vm_stat;
|
||||
kern_return_t kern;
|
||||
|
||||
kern = host_page_size(host_port, &page_size);
|
||||
if (kern != KERN_SUCCESS) return -1;
|
||||
kern = host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vm_stat, &host_size);
|
||||
if (kern != KERN_SUCCESS) return -1;
|
||||
return page_size * (vm_stat.active_count + vm_stat.inactive_count + vm_stat.wire_count);
|
||||
}
|
||||
|
||||
- (int64_t)memoryFree {
|
||||
mach_port_t host_port = mach_host_self();
|
||||
mach_msg_type_number_t host_size = sizeof(vm_statistics_data_t) / sizeof(integer_t);
|
||||
vm_size_t page_size;
|
||||
vm_statistics_data_t vm_stat;
|
||||
kern_return_t kern;
|
||||
|
||||
kern = host_page_size(host_port, &page_size);
|
||||
if (kern != KERN_SUCCESS) return -1;
|
||||
kern = host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vm_stat, &host_size);
|
||||
if (kern != KERN_SUCCESS) return -1;
|
||||
return vm_stat.free_count * page_size;
|
||||
}
|
||||
|
||||
- (int64_t)memoryActive {
|
||||
mach_port_t host_port = mach_host_self();
|
||||
mach_msg_type_number_t host_size = sizeof(vm_statistics_data_t) / sizeof(integer_t);
|
||||
vm_size_t page_size;
|
||||
vm_statistics_data_t vm_stat;
|
||||
kern_return_t kern;
|
||||
|
||||
kern = host_page_size(host_port, &page_size);
|
||||
if (kern != KERN_SUCCESS) return -1;
|
||||
kern = host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vm_stat, &host_size);
|
||||
if (kern != KERN_SUCCESS) return -1;
|
||||
return vm_stat.active_count * page_size;
|
||||
}
|
||||
|
||||
- (int64_t)memoryInactive {
|
||||
mach_port_t host_port = mach_host_self();
|
||||
mach_msg_type_number_t host_size = sizeof(vm_statistics_data_t) / sizeof(integer_t);
|
||||
vm_size_t page_size;
|
||||
vm_statistics_data_t vm_stat;
|
||||
kern_return_t kern;
|
||||
|
||||
kern = host_page_size(host_port, &page_size);
|
||||
if (kern != KERN_SUCCESS) return -1;
|
||||
kern = host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vm_stat, &host_size);
|
||||
if (kern != KERN_SUCCESS) return -1;
|
||||
return vm_stat.inactive_count * page_size;
|
||||
}
|
||||
|
||||
- (int64_t)memoryWired {
|
||||
mach_port_t host_port = mach_host_self();
|
||||
mach_msg_type_number_t host_size = sizeof(vm_statistics_data_t) / sizeof(integer_t);
|
||||
vm_size_t page_size;
|
||||
vm_statistics_data_t vm_stat;
|
||||
kern_return_t kern;
|
||||
|
||||
kern = host_page_size(host_port, &page_size);
|
||||
if (kern != KERN_SUCCESS) return -1;
|
||||
kern = host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vm_stat, &host_size);
|
||||
if (kern != KERN_SUCCESS) return -1;
|
||||
return vm_stat.wire_count * page_size;
|
||||
}
|
||||
|
||||
- (int64_t)memoryPurgable {
|
||||
mach_port_t host_port = mach_host_self();
|
||||
mach_msg_type_number_t host_size = sizeof(vm_statistics_data_t) / sizeof(integer_t);
|
||||
vm_size_t page_size;
|
||||
vm_statistics_data_t vm_stat;
|
||||
kern_return_t kern;
|
||||
|
||||
kern = host_page_size(host_port, &page_size);
|
||||
if (kern != KERN_SUCCESS) return -1;
|
||||
kern = host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vm_stat, &host_size);
|
||||
if (kern != KERN_SUCCESS) return -1;
|
||||
return vm_stat.purgeable_count * page_size;
|
||||
}
|
||||
|
||||
- (NSUInteger)cpuCount {
|
||||
return [NSProcessInfo processInfo].activeProcessorCount;
|
||||
}
|
||||
|
||||
- (float)cpuUsage {
|
||||
float cpu = 0;
|
||||
NSArray *cpus = [self cpuUsagePerProcessor];
|
||||
if (cpus.count == 0) return -1;
|
||||
for (NSNumber *n in cpus) {
|
||||
cpu += n.floatValue;
|
||||
}
|
||||
return cpu;
|
||||
}
|
||||
|
||||
- (NSArray *)cpuUsagePerProcessor {
|
||||
processor_info_array_t _cpuInfo, _prevCPUInfo = nil;
|
||||
mach_msg_type_number_t _numCPUInfo, _numPrevCPUInfo = 0;
|
||||
unsigned _numCPUs;
|
||||
NSLock *_cpuUsageLock;
|
||||
|
||||
int _mib[2U] = { CTL_HW, HW_NCPU };
|
||||
size_t _sizeOfNumCPUs = sizeof(_numCPUs);
|
||||
int _status = sysctl(_mib, 2U, &_numCPUs, &_sizeOfNumCPUs, NULL, 0U);
|
||||
if (_status)
|
||||
_numCPUs = 1;
|
||||
|
||||
_cpuUsageLock = [[NSLock alloc] init];
|
||||
|
||||
natural_t _numCPUsU = 0U;
|
||||
kern_return_t err = host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &_numCPUsU, &_cpuInfo, &_numCPUInfo);
|
||||
if (err == KERN_SUCCESS) {
|
||||
[_cpuUsageLock lock];
|
||||
|
||||
NSMutableArray *cpus = [NSMutableArray new];
|
||||
for (unsigned i = 0U; i < _numCPUs; ++i) {
|
||||
Float32 _inUse, _total;
|
||||
if (_prevCPUInfo) {
|
||||
_inUse = (
|
||||
(_cpuInfo[(CPU_STATE_MAX * i) + CPU_STATE_USER] - _prevCPUInfo[(CPU_STATE_MAX * i) + CPU_STATE_USER])
|
||||
+ (_cpuInfo[(CPU_STATE_MAX * i) + CPU_STATE_SYSTEM] - _prevCPUInfo[(CPU_STATE_MAX * i) + CPU_STATE_SYSTEM])
|
||||
+ (_cpuInfo[(CPU_STATE_MAX * i) + CPU_STATE_NICE] - _prevCPUInfo[(CPU_STATE_MAX * i) + CPU_STATE_NICE])
|
||||
);
|
||||
_total = _inUse + (_cpuInfo[(CPU_STATE_MAX * i) + CPU_STATE_IDLE] - _prevCPUInfo[(CPU_STATE_MAX * i) + CPU_STATE_IDLE]);
|
||||
} else {
|
||||
_inUse = _cpuInfo[(CPU_STATE_MAX * i) + CPU_STATE_USER] + _cpuInfo[(CPU_STATE_MAX * i) + CPU_STATE_SYSTEM] + _cpuInfo[(CPU_STATE_MAX * i) + CPU_STATE_NICE];
|
||||
_total = _inUse + _cpuInfo[(CPU_STATE_MAX * i) + CPU_STATE_IDLE];
|
||||
}
|
||||
[cpus addObject:@(_inUse / _total)];
|
||||
}
|
||||
|
||||
[_cpuUsageLock unlock];
|
||||
if (_prevCPUInfo) {
|
||||
size_t prevCpuInfoSize = sizeof(integer_t) * _numPrevCPUInfo;
|
||||
vm_deallocate(mach_task_self(), (vm_address_t)_prevCPUInfo, prevCpuInfoSize);
|
||||
}
|
||||
return cpus;
|
||||
} else {
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
153
Pods/YYCategories/YYCategories/UIKit/UIFont+YYAdd.h
generated
Normal file
153
Pods/YYCategories/YYCategories/UIKit/UIFont+YYAdd.h
generated
Normal file
@@ -0,0 +1,153 @@
|
||||
//
|
||||
// UIFont+YYAdd.h
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 14/5/11.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <CoreGraphics/CoreGraphics.h>
|
||||
#import <CoreText/CoreText.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
Provides extensions for `UIFont`.
|
||||
*/
|
||||
@interface UIFont (YYAdd) <NSCoding>
|
||||
|
||||
#pragma mark - Font Traits
|
||||
///=============================================================================
|
||||
/// @name Font Traits
|
||||
///=============================================================================
|
||||
|
||||
@property (nonatomic, readonly) BOOL isBold NS_AVAILABLE_IOS(7_0); ///< Whether the font is bold.
|
||||
@property (nonatomic, readonly) BOOL isItalic NS_AVAILABLE_IOS(7_0); ///< Whether the font is italic.
|
||||
@property (nonatomic, readonly) BOOL isMonoSpace NS_AVAILABLE_IOS(7_0); ///< Whether the font is mono space.
|
||||
@property (nonatomic, readonly) BOOL isColorGlyphs NS_AVAILABLE_IOS(7_0); ///< Whether the font is color glyphs (such as Emoji).
|
||||
@property (nonatomic, readonly) CGFloat fontWeight NS_AVAILABLE_IOS(7_0); ///< Font weight from -1.0 to 1.0. Regular weight is 0.0.
|
||||
|
||||
/**
|
||||
Create a bold font from receiver.
|
||||
@return A bold font, or nil if failed.
|
||||
*/
|
||||
- (nullable UIFont *)fontWithBold NS_AVAILABLE_IOS(7_0);
|
||||
|
||||
/**
|
||||
Create a italic font from receiver.
|
||||
@return A italic font, or nil if failed.
|
||||
*/
|
||||
- (nullable UIFont *)fontWithItalic NS_AVAILABLE_IOS(7_0);
|
||||
|
||||
/**
|
||||
Create a bold and italic font from receiver.
|
||||
@return A bold and italic font, or nil if failed.
|
||||
*/
|
||||
- (nullable UIFont *)fontWithBoldItalic NS_AVAILABLE_IOS(7_0);
|
||||
|
||||
/**
|
||||
Create a normal (no bold/italic/...) font from receiver.
|
||||
@return A normal font, or nil if failed.
|
||||
*/
|
||||
- (nullable UIFont *)fontWithNormal NS_AVAILABLE_IOS(7_0);
|
||||
|
||||
#pragma mark - Create font
|
||||
///=============================================================================
|
||||
/// @name Create font
|
||||
///=============================================================================
|
||||
|
||||
/**
|
||||
Creates and returns a font object for the specified CTFontRef.
|
||||
|
||||
@param CTFont CoreText font.
|
||||
*/
|
||||
+ (nullable UIFont *)fontWithCTFont:(CTFontRef)CTFont;
|
||||
|
||||
/**
|
||||
Creates and returns a font object for the specified CGFontRef and size.
|
||||
|
||||
@param CGFont CoreGraphic font.
|
||||
@param size Font size.
|
||||
*/
|
||||
+ (nullable UIFont *)fontWithCGFont:(CGFontRef)CGFont size:(CGFloat)size;
|
||||
|
||||
/**
|
||||
Creates and returns the CTFontRef object. (need call CFRelease() after used)
|
||||
*/
|
||||
- (nullable CTFontRef)CTFontRef CF_RETURNS_RETAINED;
|
||||
|
||||
/**
|
||||
Creates and returns the CGFontRef object. (need call CFRelease() after used)
|
||||
*/
|
||||
- (nullable CGFontRef)CGFontRef CF_RETURNS_RETAINED;
|
||||
|
||||
|
||||
#pragma mark - Load and unload font
|
||||
///=============================================================================
|
||||
/// @name Load and unload font
|
||||
///=============================================================================
|
||||
|
||||
/**
|
||||
Load the font from file path. Support format:TTF,OTF.
|
||||
If return YES, font can be load use it PostScript Name: [UIFont fontWithName:...]
|
||||
|
||||
@param path font file's full path
|
||||
*/
|
||||
+ (BOOL)loadFontFromPath:(NSString *)path;
|
||||
|
||||
/**
|
||||
Unload font from file path.
|
||||
|
||||
@param path font file's full path
|
||||
*/
|
||||
+ (void)unloadFontFromPath:(NSString *)path;
|
||||
|
||||
/**
|
||||
Load the font from data. Support format:TTF,OTF.
|
||||
|
||||
@param data Font data.
|
||||
|
||||
@return UIFont object if load succeed, otherwise nil.
|
||||
*/
|
||||
+ (nullable UIFont *)loadFontFromData:(NSData *)data;
|
||||
|
||||
/**
|
||||
Unload font which is loaded by loadFontFromData: function.
|
||||
|
||||
@param font the font loaded by loadFontFromData: function
|
||||
|
||||
@return YES if succeed, otherwise NO.
|
||||
*/
|
||||
+ (BOOL)unloadFontFromData:(UIFont *)font;
|
||||
|
||||
|
||||
#pragma mark - Dump font data
|
||||
///=============================================================================
|
||||
/// @name Dump font data
|
||||
///=============================================================================
|
||||
|
||||
/**
|
||||
Serialize and return the font data.
|
||||
|
||||
@param font The font.
|
||||
|
||||
@return data in TTF, or nil if an error occurs.
|
||||
*/
|
||||
+ (nullable NSData *)dataFromFont:(UIFont *)font;
|
||||
|
||||
/**
|
||||
Serialize and return the font data.
|
||||
|
||||
@param cgFont The font.
|
||||
|
||||
@return data in TTF, or nil if an error occurs.
|
||||
*/
|
||||
+ (nullable NSData *)dataFromCGFont:(CGFontRef)cgFont;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
269
Pods/YYCategories/YYCategories/UIKit/UIFont+YYAdd.m
generated
Normal file
269
Pods/YYCategories/YYCategories/UIKit/UIFont+YYAdd.m
generated
Normal file
@@ -0,0 +1,269 @@
|
||||
//
|
||||
// UIFont+YYAdd.m
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 14/5/11.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import "UIFont+YYAdd.h"
|
||||
#import "YYCategoriesMacro.h"
|
||||
|
||||
YYSYNTH_DUMMY_CLASS(UIFont_YYAdd)
|
||||
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wprotocol"
|
||||
// Apple has implemented UIFont<NSCoding>, but did not make it public.
|
||||
|
||||
@implementation UIFont (YYAdd)
|
||||
|
||||
- (BOOL)isBold {
|
||||
if (![self respondsToSelector:@selector(fontDescriptor)]) return NO;
|
||||
return (self.fontDescriptor.symbolicTraits & UIFontDescriptorTraitBold) > 0;
|
||||
}
|
||||
|
||||
- (BOOL)isItalic {
|
||||
if (![self respondsToSelector:@selector(fontDescriptor)]) return NO;
|
||||
return (self.fontDescriptor.symbolicTraits & UIFontDescriptorTraitItalic) > 0;
|
||||
}
|
||||
|
||||
- (BOOL)isMonoSpace {
|
||||
if (![self respondsToSelector:@selector(fontDescriptor)]) return NO;
|
||||
return (self.fontDescriptor.symbolicTraits & UIFontDescriptorTraitMonoSpace) > 0;
|
||||
}
|
||||
|
||||
- (BOOL)isColorGlyphs {
|
||||
if (![self respondsToSelector:@selector(fontDescriptor)]) return NO;
|
||||
return (CTFontGetSymbolicTraits((__bridge CTFontRef)self) & kCTFontTraitColorGlyphs) != 0;
|
||||
}
|
||||
|
||||
- (CGFloat)fontWeight {
|
||||
NSDictionary *traits = [self.fontDescriptor objectForKey:UIFontDescriptorTraitsAttribute];
|
||||
return [traits[UIFontWeightTrait] floatValue];
|
||||
}
|
||||
|
||||
- (UIFont *)fontWithBold {
|
||||
if (![self respondsToSelector:@selector(fontDescriptor)]) return nil;
|
||||
return [UIFont fontWithDescriptor:[self.fontDescriptor fontDescriptorWithSymbolicTraits:UIFontDescriptorTraitBold] size:self.pointSize];
|
||||
}
|
||||
|
||||
- (UIFont *)fontWithItalic {
|
||||
if (![self respondsToSelector:@selector(fontDescriptor)]) return nil;
|
||||
return [UIFont fontWithDescriptor:[self.fontDescriptor fontDescriptorWithSymbolicTraits:UIFontDescriptorTraitItalic] size:self.pointSize];
|
||||
}
|
||||
|
||||
- (UIFont *)fontWithBoldItalic {
|
||||
if (![self respondsToSelector:@selector(fontDescriptor)]) return nil;
|
||||
return [UIFont fontWithDescriptor:[self.fontDescriptor fontDescriptorWithSymbolicTraits:UIFontDescriptorTraitBold | UIFontDescriptorTraitItalic] size:self.pointSize];
|
||||
}
|
||||
|
||||
- (UIFont *)fontWithNormal {
|
||||
if (![self respondsToSelector:@selector(fontDescriptor)]) return nil;
|
||||
return [UIFont fontWithDescriptor:[self.fontDescriptor fontDescriptorWithSymbolicTraits:0] size:self.pointSize];
|
||||
}
|
||||
|
||||
+ (UIFont *)fontWithCTFont:(CTFontRef)CTFont {
|
||||
if (!CTFont) return nil;
|
||||
CFStringRef name = CTFontCopyPostScriptName(CTFont);
|
||||
if (!name) return nil;
|
||||
CGFloat size = CTFontGetSize(CTFont);
|
||||
UIFont *font = [self fontWithName:(__bridge NSString *)(name) size:size];
|
||||
CFRelease(name);
|
||||
return font;
|
||||
}
|
||||
|
||||
+ (UIFont *)fontWithCGFont:(CGFontRef)CGFont size:(CGFloat)size {
|
||||
if (!CGFont) return nil;
|
||||
CFStringRef name = CGFontCopyPostScriptName(CGFont);
|
||||
if (!name) return nil;
|
||||
UIFont *font = [self fontWithName:(__bridge NSString *)(name) size:size];
|
||||
CFRelease(name);
|
||||
return font;
|
||||
}
|
||||
|
||||
- (CTFontRef)CTFontRef CF_RETURNS_RETAINED {
|
||||
CTFontRef font = CTFontCreateWithName((__bridge CFStringRef)self.fontName, self.pointSize, NULL);
|
||||
return font;
|
||||
}
|
||||
|
||||
- (CGFontRef)CGFontRef CF_RETURNS_RETAINED {
|
||||
CGFontRef font = CGFontCreateWithFontName((__bridge CFStringRef)self.fontName);
|
||||
return font;
|
||||
}
|
||||
|
||||
+ (BOOL)loadFontFromPath:(NSString *)path {
|
||||
NSURL *url = [NSURL fileURLWithPath:path];
|
||||
CFErrorRef error;
|
||||
BOOL suc = CTFontManagerRegisterFontsForURL((__bridge CFTypeRef)url, kCTFontManagerScopeNone, &error);
|
||||
if (!suc) {
|
||||
NSLog(@"Failed to load font: %@", error);
|
||||
}
|
||||
return suc;
|
||||
}
|
||||
|
||||
+ (void)unloadFontFromPath:(NSString *)path {
|
||||
NSURL *url = [NSURL fileURLWithPath:path];
|
||||
CTFontManagerUnregisterFontsForURL((__bridge CFTypeRef)url, kCTFontManagerScopeNone, NULL);
|
||||
}
|
||||
|
||||
+ (UIFont *)loadFontFromData:(NSData *)data {
|
||||
CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data);
|
||||
if (!provider) return nil;
|
||||
CGFontRef fontRef = CGFontCreateWithDataProvider(provider);
|
||||
CGDataProviderRelease(provider);
|
||||
if (!fontRef) return nil;
|
||||
|
||||
CFErrorRef errorRef;
|
||||
BOOL suc = CTFontManagerRegisterGraphicsFont(fontRef, &errorRef);
|
||||
if (!suc) {
|
||||
CFRelease(fontRef);
|
||||
NSLog(@"%@", errorRef);
|
||||
return nil;
|
||||
} else {
|
||||
CFStringRef fontName = CGFontCopyPostScriptName(fontRef);
|
||||
UIFont *font = [UIFont fontWithName:(__bridge NSString *)(fontName) size:[UIFont systemFontSize]];
|
||||
if (fontName) CFRelease(fontName);
|
||||
CGFontRelease(fontRef);
|
||||
return font;
|
||||
}
|
||||
}
|
||||
|
||||
+ (BOOL)unloadFontFromData:(UIFont *)font {
|
||||
CGFontRef fontRef = CGFontCreateWithFontName((__bridge CFStringRef)font.fontName);
|
||||
if (!fontRef) return NO;
|
||||
CFErrorRef errorRef;
|
||||
BOOL suc = CTFontManagerUnregisterGraphicsFont(fontRef, &errorRef);
|
||||
CFRelease(fontRef);
|
||||
if (!suc) NSLog(@"%@", errorRef);
|
||||
return suc;
|
||||
}
|
||||
|
||||
+ (NSData *)dataFromFont:(UIFont *)font {
|
||||
CGFontRef cgFont = font.CGFontRef;
|
||||
NSData *data = [self dataFromCGFont:cgFont];
|
||||
CGFontRelease(cgFont);
|
||||
return data;
|
||||
}
|
||||
|
||||
typedef struct FontHeader {
|
||||
int32_t fVersion;
|
||||
uint16_t fNumTables;
|
||||
uint16_t fSearchRange;
|
||||
uint16_t fEntrySelector;
|
||||
uint16_t fRangeShift;
|
||||
} FontHeader;
|
||||
|
||||
typedef struct TableEntry {
|
||||
uint32_t fTag;
|
||||
uint32_t fCheckSum;
|
||||
uint32_t fOffset;
|
||||
uint32_t fLength;
|
||||
} TableEntry;
|
||||
|
||||
static uint32_t CalcTableCheckSum(const uint32_t *table, uint32_t numberOfBytesInTable) {
|
||||
uint32_t sum = 0;
|
||||
uint32_t nLongs = (numberOfBytesInTable + 3) / 4;
|
||||
while (nLongs-- > 0) {
|
||||
sum += CFSwapInt32HostToBig(*table++);
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
//Reference:
|
||||
//https://github.com/google/skia/blob/master/src%2Fports%2FSkFontHost_mac.cpp
|
||||
+ (NSData *)dataFromCGFont:(CGFontRef)cgFont {
|
||||
if (!cgFont) return nil;
|
||||
|
||||
CFRetain(cgFont);
|
||||
|
||||
CFArrayRef tags = CGFontCopyTableTags(cgFont);
|
||||
if (!tags) return nil;
|
||||
CFIndex tableCount = CFArrayGetCount(tags);
|
||||
|
||||
size_t *tableSizes = malloc(sizeof(size_t) * tableCount);
|
||||
memset(tableSizes, 0, sizeof(size_t) * tableCount);
|
||||
|
||||
BOOL containsCFFTable = NO;
|
||||
|
||||
size_t totalSize = sizeof(FontHeader) + sizeof(TableEntry) * tableCount;
|
||||
|
||||
for (CFIndex index = 0; index < tableCount; index++) {
|
||||
size_t tableSize = 0;
|
||||
uint32_t aTag = (uint32_t)CFArrayGetValueAtIndex(tags, index);
|
||||
if (aTag == kCTFontTableCFF && !containsCFFTable) {
|
||||
containsCFFTable = YES;
|
||||
}
|
||||
CFDataRef tableDataRef = CGFontCopyTableForTag(cgFont, aTag);
|
||||
if (tableDataRef) {
|
||||
tableSize = CFDataGetLength(tableDataRef);
|
||||
CFRelease(tableDataRef);
|
||||
}
|
||||
totalSize += (tableSize + 3) & ~3;
|
||||
tableSizes[index] = tableSize;
|
||||
}
|
||||
|
||||
unsigned char *stream = malloc(totalSize);
|
||||
memset(stream, 0, totalSize);
|
||||
char *dataStart = (char *)stream;
|
||||
char *dataPtr = dataStart;
|
||||
|
||||
// compute font header entries
|
||||
uint16_t entrySelector = 0;
|
||||
uint16_t searchRange = 1;
|
||||
while (searchRange < tableCount >> 1) {
|
||||
entrySelector++;
|
||||
searchRange <<= 1;
|
||||
}
|
||||
searchRange <<= 4;
|
||||
|
||||
uint16_t rangeShift = (tableCount << 4) - searchRange;
|
||||
|
||||
// write font header (also called sfnt header, offset subtable)
|
||||
FontHeader *offsetTable = (FontHeader *)dataPtr;
|
||||
|
||||
//OpenType Font contains CFF Table use 'OTTO' as version, and with .otf extension
|
||||
//otherwise 0001 0000
|
||||
offsetTable->fVersion = containsCFFTable ? 'OTTO' : CFSwapInt16HostToBig(1);
|
||||
offsetTable->fNumTables = CFSwapInt16HostToBig((uint16_t)tableCount);
|
||||
offsetTable->fSearchRange = CFSwapInt16HostToBig((uint16_t)searchRange);
|
||||
offsetTable->fEntrySelector = CFSwapInt16HostToBig((uint16_t)entrySelector);
|
||||
offsetTable->fRangeShift = CFSwapInt16HostToBig((uint16_t)rangeShift);
|
||||
|
||||
dataPtr += sizeof(FontHeader);
|
||||
|
||||
// write tables
|
||||
TableEntry *entry = (TableEntry *)dataPtr;
|
||||
dataPtr += sizeof(TableEntry) * tableCount;
|
||||
|
||||
for (int index = 0; index < tableCount; ++index) {
|
||||
uint32_t aTag = (uint32_t)CFArrayGetValueAtIndex(tags, index);
|
||||
CFDataRef tableDataRef = CGFontCopyTableForTag(cgFont, aTag);
|
||||
size_t tableSize = CFDataGetLength(tableDataRef);
|
||||
|
||||
memcpy(dataPtr, CFDataGetBytePtr(tableDataRef), tableSize);
|
||||
|
||||
entry->fTag = CFSwapInt32HostToBig((uint32_t)aTag);
|
||||
entry->fCheckSum = CFSwapInt32HostToBig(CalcTableCheckSum((uint32_t *)dataPtr, (uint32_t)tableSize));
|
||||
|
||||
uint32_t offset = (uint32_t)dataPtr - (uint32_t)dataStart;
|
||||
entry->fOffset = CFSwapInt32HostToBig((uint32_t)offset);
|
||||
entry->fLength = CFSwapInt32HostToBig((uint32_t)tableSize);
|
||||
dataPtr += (tableSize + 3) & ~3;
|
||||
++entry;
|
||||
CFRelease(tableDataRef);
|
||||
}
|
||||
|
||||
CFRelease(cgFont);
|
||||
CFRelease(tags);
|
||||
free(tableSizes);
|
||||
NSData *fontData = [NSData dataWithBytesNoCopy:stream length:totalSize freeWhenDone:YES];
|
||||
return fontData;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma clang diagnostic pop
|
||||
47
Pods/YYCategories/YYCategories/UIKit/UIGestureRecognizer+YYAdd.h
generated
Normal file
47
Pods/YYCategories/YYCategories/UIKit/UIGestureRecognizer+YYAdd.h
generated
Normal file
@@ -0,0 +1,47 @@
|
||||
//
|
||||
// UIGestureRecognizer+YYAdd.h
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 13/10/13.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
Provides extensions for `UIGestureRecognizer`.
|
||||
*/
|
||||
@interface UIGestureRecognizer (YYAdd)
|
||||
|
||||
/**
|
||||
Initializes an allocated gesture-recognizer object with a action block.
|
||||
|
||||
@param block An action block that to handle the gesture recognized by the
|
||||
receiver. nil is invalid. It is retained by the gesture.
|
||||
|
||||
@return An initialized instance of a concrete UIGestureRecognizer subclass or
|
||||
nil if an error occurred in the attempt to initialize the object.
|
||||
*/
|
||||
- (instancetype)initWithActionBlock:(void (^)(id sender))block;
|
||||
|
||||
/**
|
||||
Adds an action block to a gesture-recognizer object. It is retained by the
|
||||
gesture.
|
||||
|
||||
@param block A block invoked by the action message. nil is not a valid value.
|
||||
*/
|
||||
- (void)addActionBlock:(void (^)(id sender))block;
|
||||
|
||||
/**
|
||||
Remove all action blocks.
|
||||
*/
|
||||
- (void)removeAllActionBlocks;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
78
Pods/YYCategories/YYCategories/UIKit/UIGestureRecognizer+YYAdd.m
generated
Normal file
78
Pods/YYCategories/YYCategories/UIKit/UIGestureRecognizer+YYAdd.m
generated
Normal file
@@ -0,0 +1,78 @@
|
||||
//
|
||||
// UIGestureRecognizer+YYAdd.m
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 13/10/13.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import "UIGestureRecognizer+YYAdd.h"
|
||||
#import "YYCategoriesMacro.h"
|
||||
#import <objc/runtime.h>
|
||||
|
||||
static const int block_key;
|
||||
|
||||
@interface _YYUIGestureRecognizerBlockTarget : NSObject
|
||||
|
||||
@property (nonatomic, copy) void (^block)(id sender);
|
||||
|
||||
- (id)initWithBlock:(void (^)(id sender))block;
|
||||
- (void)invoke:(id)sender;
|
||||
|
||||
@end
|
||||
|
||||
@implementation _YYUIGestureRecognizerBlockTarget
|
||||
|
||||
- (id)initWithBlock:(void (^)(id sender))block{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_block = [block copy];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)invoke:(id)sender {
|
||||
if (_block) _block(sender);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
|
||||
@implementation UIGestureRecognizer (YYAdd)
|
||||
|
||||
- (instancetype)initWithActionBlock:(void (^)(id sender))block {
|
||||
self = [self init];
|
||||
[self addActionBlock:block];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)addActionBlock:(void (^)(id sender))block {
|
||||
_YYUIGestureRecognizerBlockTarget *target = [[_YYUIGestureRecognizerBlockTarget alloc] initWithBlock:block];
|
||||
[self addTarget:target action:@selector(invoke:)];
|
||||
NSMutableArray *targets = [self _yy_allUIGestureRecognizerBlockTargets];
|
||||
[targets addObject:target];
|
||||
}
|
||||
|
||||
- (void)removeAllActionBlocks{
|
||||
NSMutableArray *targets = [self _yy_allUIGestureRecognizerBlockTargets];
|
||||
[targets enumerateObjectsUsingBlock:^(id target, NSUInteger idx, BOOL *stop) {
|
||||
[self removeTarget:target action:@selector(invoke:)];
|
||||
}];
|
||||
[targets removeAllObjects];
|
||||
}
|
||||
|
||||
- (NSMutableArray *)_yy_allUIGestureRecognizerBlockTargets {
|
||||
NSMutableArray *targets = objc_getAssociatedObject(self, &block_key);
|
||||
if (!targets) {
|
||||
targets = [NSMutableArray array];
|
||||
objc_setAssociatedObject(self, &block_key, targets, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
return targets;
|
||||
}
|
||||
|
||||
@end
|
||||
377
Pods/YYCategories/YYCategories/UIKit/UIImage+YYAdd.h
generated
Normal file
377
Pods/YYCategories/YYCategories/UIKit/UIImage+YYAdd.h
generated
Normal file
@@ -0,0 +1,377 @@
|
||||
//
|
||||
// UIImage+YYAdd.h
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 13/4/4.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
Provide some commen method for `UIImage`.
|
||||
Image process is based on CoreGraphic and vImage.
|
||||
*/
|
||||
@interface UIImage (YYAdd)
|
||||
|
||||
#pragma mark - Create image
|
||||
///=============================================================================
|
||||
/// @name Create image
|
||||
///=============================================================================
|
||||
|
||||
/**
|
||||
Create an animated image with GIF data. After created, you can access
|
||||
the images via property '.images'. If the data is not animated gif, this
|
||||
function is same as [UIImage imageWithData:data scale:scale];
|
||||
|
||||
@discussion It has a better display performance, but costs more memory
|
||||
(width * height * frames Bytes). It only suited to display small
|
||||
gif such as animated emoji. If you want to display large gif,
|
||||
see `YYImage`.
|
||||
|
||||
@param data GIF data.
|
||||
|
||||
@param scale The scale factor
|
||||
|
||||
@return A new image created from GIF, or nil when an error occurs.
|
||||
*/
|
||||
+ (nullable UIImage *)imageWithSmallGIFData:(NSData *)data scale:(CGFloat)scale;
|
||||
|
||||
/**
|
||||
Whether the data is animated GIF.
|
||||
|
||||
@param data Image data
|
||||
|
||||
@return Returns YES only if the data is gif and contains more than one frame,
|
||||
otherwise returns NO.
|
||||
*/
|
||||
+ (BOOL)isAnimatedGIFData:(NSData *)data;
|
||||
|
||||
/**
|
||||
Whether the file in the specified path is GIF.
|
||||
|
||||
@param path An absolute file path.
|
||||
|
||||
@return Returns YES if the file is gif, otherwise returns NO.
|
||||
*/
|
||||
+ (BOOL)isAnimatedGIFFile:(NSString *)path;
|
||||
|
||||
/**
|
||||
Create an image from a PDF file data or path.
|
||||
|
||||
@discussion If the PDF has multiple page, is just return's the first page's
|
||||
content. Image's scale is equal to current screen's scale, size is same as
|
||||
PDF's origin size.
|
||||
|
||||
@param dataOrPath PDF data in `NSData`, or PDF file path in `NSString`.
|
||||
|
||||
@return A new image create from PDF, or nil when an error occurs.
|
||||
*/
|
||||
+ (nullable UIImage *)imageWithPDF:(id)dataOrPath;
|
||||
|
||||
/**
|
||||
Create an image from a PDF file data or path.
|
||||
|
||||
@discussion If the PDF has multiple page, is just return's the first page's
|
||||
content. Image's scale is equal to current screen's scale.
|
||||
|
||||
@param dataOrPath PDF data in `NSData`, or PDF file path in `NSString`.
|
||||
|
||||
@param size The new image's size, PDF's content will be stretched as needed.
|
||||
|
||||
@return A new image create from PDF, or nil when an error occurs.
|
||||
*/
|
||||
+ (nullable UIImage *)imageWithPDF:(id)dataOrPath size:(CGSize)size;
|
||||
|
||||
/**
|
||||
Create a square image from apple emoji.
|
||||
|
||||
@discussion It creates a square image from apple emoji, image's scale is equal
|
||||
to current screen's scale. The original emoji image in `AppleColorEmoji` font
|
||||
is in size 160*160 px.
|
||||
|
||||
@param emoji single emoji, such as @"😄".
|
||||
|
||||
@param size image's size.
|
||||
|
||||
@return Image from emoji, or nil when an error occurs.
|
||||
*/
|
||||
+ (nullable UIImage *)imageWithEmoji:(NSString *)emoji size:(CGFloat)size;
|
||||
|
||||
/**
|
||||
Create and return a 1x1 point size image with the given color.
|
||||
|
||||
@param color The color.
|
||||
*/
|
||||
+ (nullable UIImage *)imageWithColor:(UIColor *)color;
|
||||
|
||||
/**
|
||||
Create and return a pure color image with the given color and size.
|
||||
|
||||
@param color The color.
|
||||
@param size New image's type.
|
||||
*/
|
||||
+ (nullable UIImage *)imageWithColor:(UIColor *)color size:(CGSize)size;
|
||||
|
||||
/**
|
||||
Create and return an image with custom draw code.
|
||||
|
||||
@param size The image size.
|
||||
@param drawBlock The draw block.
|
||||
|
||||
@return The new image.
|
||||
*/
|
||||
+ (nullable UIImage *)imageWithSize:(CGSize)size drawBlock:(void (^)(CGContextRef context))drawBlock;
|
||||
|
||||
#pragma mark - Image Info
|
||||
///=============================================================================
|
||||
/// @name Image Info
|
||||
///=============================================================================
|
||||
|
||||
/**
|
||||
Whether this image has alpha channel.
|
||||
*/
|
||||
- (BOOL)hasAlphaChannel;
|
||||
|
||||
|
||||
#pragma mark - Modify Image
|
||||
///=============================================================================
|
||||
/// @name Modify Image
|
||||
///=============================================================================
|
||||
|
||||
/**
|
||||
Draws the entire image in the specified rectangle, content changed with
|
||||
the contentMode.
|
||||
|
||||
@discussion This method draws the entire image in the current graphics context,
|
||||
respecting the image's orientation setting. In the default coordinate system,
|
||||
images are situated down and to the right of the origin of the specified
|
||||
rectangle. This method respects any transforms applied to the current graphics
|
||||
context, however.
|
||||
|
||||
@param rect The rectangle in which to draw the image.
|
||||
|
||||
@param contentMode Draw content mode
|
||||
|
||||
@param clips A Boolean value that determines whether content are confined to the rect.
|
||||
*/
|
||||
- (void)drawInRect:(CGRect)rect withContentMode:(UIViewContentMode)contentMode clipsToBounds:(BOOL)clips;
|
||||
|
||||
/**
|
||||
Returns a new image which is scaled from this image.
|
||||
The image will be stretched as needed.
|
||||
|
||||
@param size The new size to be scaled, values should be positive.
|
||||
|
||||
@return The new image with the given size.
|
||||
*/
|
||||
- (nullable UIImage *)imageByResizeToSize:(CGSize)size;
|
||||
|
||||
/**
|
||||
Returns a new image which is scaled from this image.
|
||||
The image content will be changed with thencontentMode.
|
||||
|
||||
@param size The new size to be scaled, values should be positive.
|
||||
|
||||
@param contentMode The content mode for image content.
|
||||
|
||||
@return The new image with the given size.
|
||||
*/
|
||||
- (nullable UIImage *)imageByResizeToSize:(CGSize)size contentMode:(UIViewContentMode)contentMode;
|
||||
|
||||
/**
|
||||
Returns a new image which is cropped from this image.
|
||||
|
||||
@param rect Image's inner rect.
|
||||
|
||||
@return The new image, or nil if an error occurs.
|
||||
*/
|
||||
- (nullable UIImage *)imageByCropToRect:(CGRect)rect;
|
||||
|
||||
/**
|
||||
Returns a new image which is edge inset from this image.
|
||||
|
||||
@param insets Inset (positive) for each of the edges, values can be negative to 'outset'.
|
||||
|
||||
@param color Extend edge's fill color, nil means clear color.
|
||||
|
||||
@return The new image, or nil if an error occurs.
|
||||
*/
|
||||
- (nullable UIImage *)imageByInsetEdge:(UIEdgeInsets)insets withColor:(nullable UIColor *)color;
|
||||
|
||||
/**
|
||||
Rounds a new image with a given corner size.
|
||||
|
||||
@param radius The radius of each corner oval. Values larger than half the
|
||||
rectangle's width or height are clamped appropriately to half
|
||||
the width or height.
|
||||
*/
|
||||
- (nullable UIImage *)imageByRoundCornerRadius:(CGFloat)radius;
|
||||
|
||||
/**
|
||||
Rounds a new image with a given corner size.
|
||||
|
||||
@param radius The radius of each corner oval. Values larger than half the
|
||||
rectangle's width or height are clamped appropriately to
|
||||
half the width or height.
|
||||
|
||||
@param borderWidth The inset border line width. Values larger than half the rectangle's
|
||||
width or height are clamped appropriately to half the width
|
||||
or height.
|
||||
|
||||
@param borderColor The border stroke color. nil means clear color.
|
||||
*/
|
||||
- (nullable UIImage *)imageByRoundCornerRadius:(CGFloat)radius
|
||||
borderWidth:(CGFloat)borderWidth
|
||||
borderColor:(nullable UIColor *)borderColor;
|
||||
|
||||
/**
|
||||
Rounds a new image with a given corner size.
|
||||
|
||||
@param radius The radius of each corner oval. Values larger than half the
|
||||
rectangle's width or height are clamped appropriately to
|
||||
half the width or height.
|
||||
|
||||
@param corners A bitmask value that identifies the corners that you want
|
||||
rounded. You can use this parameter to round only a subset
|
||||
of the corners of the rectangle.
|
||||
|
||||
@param borderWidth The inset border line width. Values larger than half the rectangle's
|
||||
width or height are clamped appropriately to half the width
|
||||
or height.
|
||||
|
||||
@param borderColor The border stroke color. nil means clear color.
|
||||
|
||||
@param borderLineJoin The border line join.
|
||||
*/
|
||||
- (nullable UIImage *)imageByRoundCornerRadius:(CGFloat)radius
|
||||
corners:(UIRectCorner)corners
|
||||
borderWidth:(CGFloat)borderWidth
|
||||
borderColor:(nullable UIColor *)borderColor
|
||||
borderLineJoin:(CGLineJoin)borderLineJoin;
|
||||
|
||||
/**
|
||||
Returns a new rotated image (relative to the center).
|
||||
|
||||
@param radians Rotated radians in counterclockwise.⟲
|
||||
|
||||
@param fitSize YES: new image's size is extend to fit all content.
|
||||
NO: image's size will not change, content may be clipped.
|
||||
*/
|
||||
- (nullable UIImage *)imageByRotate:(CGFloat)radians fitSize:(BOOL)fitSize;
|
||||
|
||||
/**
|
||||
Returns a new image rotated counterclockwise by a quarter‑turn (90°). ⤺
|
||||
The width and height will be exchanged.
|
||||
*/
|
||||
- (nullable UIImage *)imageByRotateLeft90;
|
||||
|
||||
/**
|
||||
Returns a new image rotated clockwise by a quarter‑turn (90°). ⤼
|
||||
The width and height will be exchanged.
|
||||
*/
|
||||
- (nullable UIImage *)imageByRotateRight90;
|
||||
|
||||
/**
|
||||
Returns a new image rotated 180° . ↻
|
||||
*/
|
||||
- (nullable UIImage *)imageByRotate180;
|
||||
|
||||
/**
|
||||
Returns a vertically flipped image. ⥯
|
||||
*/
|
||||
- (nullable UIImage *)imageByFlipVertical;
|
||||
|
||||
/**
|
||||
Returns a horizontally flipped image. ⇋
|
||||
*/
|
||||
- (nullable UIImage *)imageByFlipHorizontal;
|
||||
|
||||
|
||||
#pragma mark - Image Effect
|
||||
///=============================================================================
|
||||
/// @name Image Effect
|
||||
///=============================================================================
|
||||
|
||||
/**
|
||||
Tint the image in alpha channel with the given color.
|
||||
|
||||
@param color The color.
|
||||
*/
|
||||
- (nullable UIImage *)imageByTintColor:(UIColor *)color;
|
||||
|
||||
/**
|
||||
Returns a grayscaled image.
|
||||
*/
|
||||
- (nullable UIImage *)imageByGrayscale;
|
||||
|
||||
/**
|
||||
Applies a blur effect to this image. Suitable for blur any content.
|
||||
*/
|
||||
- (nullable UIImage *)imageByBlurSoft;
|
||||
|
||||
/**
|
||||
Applies a blur effect to this image. Suitable for blur any content except pure white.
|
||||
(same as iOS Control Panel)
|
||||
*/
|
||||
- (nullable UIImage *)imageByBlurLight;
|
||||
|
||||
/**
|
||||
Applies a blur effect to this image. Suitable for displaying black text.
|
||||
(same as iOS Navigation Bar White)
|
||||
*/
|
||||
- (nullable UIImage *)imageByBlurExtraLight;
|
||||
|
||||
/**
|
||||
Applies a blur effect to this image. Suitable for displaying white text.
|
||||
(same as iOS Notification Center)
|
||||
*/
|
||||
- (nullable UIImage *)imageByBlurDark;
|
||||
|
||||
/**
|
||||
Applies a blur and tint color to this image.
|
||||
|
||||
@param tintColor The tint color.
|
||||
*/
|
||||
- (nullable UIImage *)imageByBlurWithTint:(UIColor *)tintColor;
|
||||
|
||||
/**
|
||||
Applies a blur, tint color, and saturation adjustment to this image,
|
||||
optionally within the area specified by @a maskImage.
|
||||
|
||||
@param blurRadius The radius of the blur in points, 0 means no blur effect.
|
||||
|
||||
@param tintColor An optional UIColor object that is uniformly blended with
|
||||
the result of the blur and saturation operations. The
|
||||
alpha channel of this color determines how strong the
|
||||
tint is. nil means no tint.
|
||||
|
||||
@param tintBlendMode The @a tintColor blend mode. Default is kCGBlendModeNormal (0).
|
||||
|
||||
@param saturation A value of 1.0 produces no change in the resulting image.
|
||||
Values less than 1.0 will desaturation the resulting image
|
||||
while values greater than 1.0 will have the opposite effect.
|
||||
0 means gray scale.
|
||||
|
||||
@param maskImage If specified, @a inputImage is only modified in the area(s)
|
||||
defined by this mask. This must be an image mask or it
|
||||
must meet the requirements of the mask parameter of
|
||||
CGContextClipToMask.
|
||||
|
||||
@return image with effect, or nil if an error occurs (e.g. no
|
||||
enough memory).
|
||||
*/
|
||||
- (nullable UIImage *)imageByBlurRadius:(CGFloat)blurRadius
|
||||
tintColor:(nullable UIColor *)tintColor
|
||||
tintMode:(CGBlendMode)tintBlendMode
|
||||
saturation:(CGFloat)saturation
|
||||
maskImage:(nullable UIImage *)maskImage;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
752
Pods/YYCategories/YYCategories/UIKit/UIImage+YYAdd.m
generated
Normal file
752
Pods/YYCategories/YYCategories/UIKit/UIImage+YYAdd.m
generated
Normal file
@@ -0,0 +1,752 @@
|
||||
//
|
||||
// UIImage+YYAdd.m
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 13/4/4.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import "UIImage+YYAdd.h"
|
||||
#import "UIDevice+YYAdd.h"
|
||||
#import "NSString+YYAdd.h"
|
||||
#import "YYCategoriesMacro.h"
|
||||
#import "YYCGUtilities.h"
|
||||
#import <ImageIO/ImageIO.h>
|
||||
#import <Accelerate/Accelerate.h>
|
||||
#import <CoreText/CoreText.h>
|
||||
#import <objc/runtime.h>
|
||||
#import "YYCGUtilities.h"
|
||||
|
||||
YYSYNTH_DUMMY_CLASS(UIImage_YYAdd)
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@implementation UIImage (YYAdd)
|
||||
|
||||
+ (UIImage *)imageWithSmallGIFData:(NSData *)data scale:(CGFloat)scale {
|
||||
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];
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
NSMutableArray *array = [NSMutableArray new];
|
||||
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];
|
||||
}
|
||||
}
|
||||
CFRelease(source);
|
||||
UIImage *image = [self.class animatedImageWithImages:array duration:totalTime];
|
||||
return image;
|
||||
}
|
||||
|
||||
+ (BOOL)isAnimatedGIFData:(NSData *)data {
|
||||
if (data.length < 16) return NO;
|
||||
UInt32 magic = *(UInt32 *)data.bytes;
|
||||
// http://www.w3.org/Graphics/GIF/spec-gif89a.txt
|
||||
if ((magic & 0xFFFFFF) != '\0FIG') return NO;
|
||||
CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFTypeRef)data, NULL);
|
||||
if (!source) return NO;
|
||||
size_t count = CGImageSourceGetCount(source);
|
||||
CFRelease(source);
|
||||
return count > 1;
|
||||
}
|
||||
|
||||
+ (BOOL)isAnimatedGIFFile:(NSString *)path {
|
||||
if (path.length == 0) return NO;
|
||||
const char *cpath = path.UTF8String;
|
||||
FILE *fd = fopen(cpath, "rb");
|
||||
if (!fd) return NO;
|
||||
|
||||
BOOL isGIF = NO;
|
||||
UInt32 magic = 0;
|
||||
if (fread(&magic, sizeof(UInt32), 1, fd) == 1) {
|
||||
if ((magic & 0xFFFFFF) == '\0FIG') isGIF = YES;
|
||||
}
|
||||
fclose(fd);
|
||||
return isGIF;
|
||||
}
|
||||
|
||||
+ (UIImage *)imageWithPDF:(id)dataOrPath {
|
||||
return [self _yy_imageWithPDF:dataOrPath resize:NO size:CGSizeZero];
|
||||
}
|
||||
|
||||
+ (UIImage *)imageWithPDF:(id)dataOrPath size:(CGSize)size {
|
||||
return [self _yy_imageWithPDF:dataOrPath resize:YES size:size];
|
||||
}
|
||||
|
||||
+ (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;
|
||||
}
|
||||
|
||||
+ (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;
|
||||
}
|
||||
|
||||
+ (UIImage *)imageWithColor:(UIColor *)color {
|
||||
return [self imageWithColor:color size:CGSizeMake(1, 1)];
|
||||
}
|
||||
|
||||
+ (UIImage *)imageWithColor:(UIColor *)color size:(CGSize)size {
|
||||
if (!color || size.width <= 0 || size.height <= 0) return nil;
|
||||
CGRect rect = CGRectMake(0.0f, 0.0f, size.width, size.height);
|
||||
UIGraphicsBeginImageContextWithOptions(rect.size, NO, 0);
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
CGContextSetFillColorWithColor(context, color.CGColor);
|
||||
CGContextFillRect(context, rect);
|
||||
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
return 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;
|
||||
}
|
||||
|
||||
- (BOOL)hasAlphaChannel {
|
||||
if (self.CGImage == NULL) return NO;
|
||||
CGImageAlphaInfo alpha = CGImageGetAlphaInfo(self.CGImage) & kCGBitmapAlphaInfoMask;
|
||||
return (alpha == kCGImageAlphaFirst ||
|
||||
alpha == kCGImageAlphaLast ||
|
||||
alpha == kCGImageAlphaPremultipliedFirst ||
|
||||
alpha == kCGImageAlphaPremultipliedLast);
|
||||
}
|
||||
|
||||
- (void)drawInRect:(CGRect)rect withContentMode:(UIViewContentMode)contentMode clipsToBounds:(BOOL)clips{
|
||||
CGRect drawRect = YYCGRectFitWithContentMode(rect, self.size, contentMode);
|
||||
if (drawRect.size.width == 0 || drawRect.size.height == 0) return;
|
||||
if (clips) {
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
if (context) {
|
||||
CGContextSaveGState(context);
|
||||
CGContextAddRect(context, rect);
|
||||
CGContextClip(context);
|
||||
[self drawInRect:drawRect];
|
||||
CGContextRestoreGState(context);
|
||||
}
|
||||
} else {
|
||||
[self drawInRect:drawRect];
|
||||
}
|
||||
}
|
||||
|
||||
- (UIImage *)imageByResizeToSize:(CGSize)size {
|
||||
if (size.width <= 0 || size.height <= 0) return nil;
|
||||
UIGraphicsBeginImageContextWithOptions(size, NO, self.scale);
|
||||
[self drawInRect:CGRectMake(0, 0, size.width, size.height)];
|
||||
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
return image;
|
||||
}
|
||||
|
||||
- (UIImage *)imageByResizeToSize:(CGSize)size contentMode:(UIViewContentMode)contentMode {
|
||||
if (size.width <= 0 || size.height <= 0) return nil;
|
||||
UIGraphicsBeginImageContextWithOptions(size, NO, self.scale);
|
||||
[self drawInRect:CGRectMake(0, 0, size.width, size.height) withContentMode:contentMode clipsToBounds:NO];
|
||||
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
return image;
|
||||
}
|
||||
|
||||
- (UIImage *)imageByCropToRect:(CGRect)rect {
|
||||
rect.origin.x *= self.scale;
|
||||
rect.origin.y *= self.scale;
|
||||
rect.size.width *= self.scale;
|
||||
rect.size.height *= self.scale;
|
||||
if (rect.size.width <= 0 || rect.size.height <= 0) return nil;
|
||||
CGImageRef imageRef = CGImageCreateWithImageInRect(self.CGImage, rect);
|
||||
UIImage *image = [UIImage imageWithCGImage:imageRef scale:self.scale orientation:self.imageOrientation];
|
||||
CGImageRelease(imageRef);
|
||||
return image;
|
||||
}
|
||||
|
||||
- (UIImage *)imageByInsetEdge:(UIEdgeInsets)insets withColor:(UIColor *)color {
|
||||
CGSize size = self.size;
|
||||
size.width -= insets.left + insets.right;
|
||||
size.height -= insets.top + insets.bottom;
|
||||
if (size.width <= 0 || size.height <= 0) return nil;
|
||||
CGRect rect = CGRectMake(-insets.left, -insets.top, self.size.width, self.size.height);
|
||||
UIGraphicsBeginImageContextWithOptions(size, NO, self.scale);
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
if (color) {
|
||||
CGContextSetFillColorWithColor(context, color.CGColor);
|
||||
CGMutablePathRef path = CGPathCreateMutable();
|
||||
CGPathAddRect(path, NULL, CGRectMake(0, 0, size.width, size.height));
|
||||
CGPathAddRect(path, NULL, rect);
|
||||
CGContextAddPath(context, path);
|
||||
CGContextEOFillPath(context);
|
||||
CGPathRelease(path);
|
||||
}
|
||||
[self drawInRect:rect];
|
||||
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
return image;
|
||||
}
|
||||
|
||||
- (UIImage *)imageByRoundCornerRadius:(CGFloat)radius {
|
||||
return [self imageByRoundCornerRadius:radius borderWidth:0 borderColor:nil];
|
||||
}
|
||||
|
||||
- (UIImage *)imageByRoundCornerRadius:(CGFloat)radius
|
||||
borderWidth:(CGFloat)borderWidth
|
||||
borderColor:(UIColor *)borderColor {
|
||||
return [self imageByRoundCornerRadius:radius
|
||||
corners:UIRectCornerAllCorners
|
||||
borderWidth:borderWidth
|
||||
borderColor:borderColor
|
||||
borderLineJoin:kCGLineJoinMiter];
|
||||
}
|
||||
|
||||
- (UIImage *)imageByRoundCornerRadius:(CGFloat)radius
|
||||
corners:(UIRectCorner)corners
|
||||
borderWidth:(CGFloat)borderWidth
|
||||
borderColor:(UIColor *)borderColor
|
||||
borderLineJoin:(CGLineJoin)borderLineJoin {
|
||||
|
||||
if (corners != UIRectCornerAllCorners) {
|
||||
UIRectCorner tmp = 0;
|
||||
if (corners & UIRectCornerTopLeft) tmp |= UIRectCornerBottomLeft;
|
||||
if (corners & UIRectCornerTopRight) tmp |= UIRectCornerBottomRight;
|
||||
if (corners & UIRectCornerBottomLeft) tmp |= UIRectCornerTopLeft;
|
||||
if (corners & UIRectCornerBottomRight) tmp |= UIRectCornerTopRight;
|
||||
corners = tmp;
|
||||
}
|
||||
|
||||
UIGraphicsBeginImageContextWithOptions(self.size, NO, self.scale);
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
CGRect rect = CGRectMake(0, 0, self.size.width, self.size.height);
|
||||
CGContextScaleCTM(context, 1, -1);
|
||||
CGContextTranslateCTM(context, 0, -rect.size.height);
|
||||
|
||||
CGFloat minSize = MIN(self.size.width, self.size.height);
|
||||
if (borderWidth < minSize / 2) {
|
||||
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectInset(rect, borderWidth, borderWidth) byRoundingCorners:corners cornerRadii:CGSizeMake(radius, borderWidth)];
|
||||
[path closePath];
|
||||
|
||||
CGContextSaveGState(context);
|
||||
[path addClip];
|
||||
CGContextDrawImage(context, rect, self.CGImage);
|
||||
CGContextRestoreGState(context);
|
||||
}
|
||||
|
||||
if (borderColor && borderWidth < minSize / 2 && borderWidth > 0) {
|
||||
CGFloat strokeInset = (floor(borderWidth * self.scale) + 0.5) / self.scale;
|
||||
CGRect strokeRect = CGRectInset(rect, strokeInset, strokeInset);
|
||||
CGFloat strokeRadius = radius > self.scale / 2 ? radius - self.scale / 2 : 0;
|
||||
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:strokeRect byRoundingCorners:corners cornerRadii:CGSizeMake(strokeRadius, borderWidth)];
|
||||
[path closePath];
|
||||
|
||||
path.lineWidth = borderWidth;
|
||||
path.lineJoinStyle = borderLineJoin;
|
||||
[borderColor setStroke];
|
||||
[path stroke];
|
||||
}
|
||||
|
||||
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
return image;
|
||||
}
|
||||
|
||||
- (UIImage *)imageByRotate:(CGFloat)radians fitSize:(BOOL)fitSize {
|
||||
size_t width = (size_t)CGImageGetWidth(self.CGImage);
|
||||
size_t height = (size_t)CGImageGetHeight(self.CGImage);
|
||||
CGRect newRect = CGRectApplyAffineTransform(CGRectMake(0., 0., width, height),
|
||||
fitSize ? CGAffineTransformMakeRotation(radians) : CGAffineTransformIdentity);
|
||||
|
||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
CGContextRef context = CGBitmapContextCreate(NULL,
|
||||
(size_t)newRect.size.width,
|
||||
(size_t)newRect.size.height,
|
||||
8,
|
||||
(size_t)newRect.size.width * 4,
|
||||
colorSpace,
|
||||
kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedFirst);
|
||||
CGColorSpaceRelease(colorSpace);
|
||||
if (!context) return nil;
|
||||
|
||||
CGContextSetShouldAntialias(context, true);
|
||||
CGContextSetAllowsAntialiasing(context, true);
|
||||
CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
|
||||
|
||||
CGContextTranslateCTM(context, +(newRect.size.width * 0.5), +(newRect.size.height * 0.5));
|
||||
CGContextRotateCTM(context, radians);
|
||||
|
||||
CGContextDrawImage(context, CGRectMake(-(width * 0.5), -(height * 0.5), width, height), self.CGImage);
|
||||
CGImageRef imgRef = CGBitmapContextCreateImage(context);
|
||||
UIImage *img = [UIImage imageWithCGImage:imgRef scale:self.scale orientation:self.imageOrientation];
|
||||
CGImageRelease(imgRef);
|
||||
CGContextRelease(context);
|
||||
return img;
|
||||
}
|
||||
|
||||
- (UIImage *)_yy_flipHorizontal:(BOOL)horizontal vertical:(BOOL)vertical {
|
||||
if (!self.CGImage) return nil;
|
||||
size_t width = (size_t)CGImageGetWidth(self.CGImage);
|
||||
size_t height = (size_t)CGImageGetHeight(self.CGImage);
|
||||
size_t bytesPerRow = width * 4;
|
||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
CGContextRef context = CGBitmapContextCreate(NULL, width, height, 8, bytesPerRow, colorSpace, kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedFirst);
|
||||
CGColorSpaceRelease(colorSpace);
|
||||
if (!context) return nil;
|
||||
|
||||
CGContextDrawImage(context, CGRectMake(0, 0, width, height), self.CGImage);
|
||||
UInt8 *data = (UInt8 *)CGBitmapContextGetData(context);
|
||||
if (!data) {
|
||||
CGContextRelease(context);
|
||||
return nil;
|
||||
}
|
||||
vImage_Buffer src = { data, height, width, bytesPerRow };
|
||||
vImage_Buffer dest = { data, height, width, bytesPerRow };
|
||||
if (vertical) {
|
||||
vImageVerticalReflect_ARGB8888(&src, &dest, kvImageBackgroundColorFill);
|
||||
}
|
||||
if (horizontal) {
|
||||
vImageHorizontalReflect_ARGB8888(&src, &dest, kvImageBackgroundColorFill);
|
||||
}
|
||||
CGImageRef imgRef = CGBitmapContextCreateImage(context);
|
||||
CGContextRelease(context);
|
||||
UIImage *img = [UIImage imageWithCGImage:imgRef scale:self.scale orientation:self.imageOrientation];
|
||||
CGImageRelease(imgRef);
|
||||
return img;
|
||||
}
|
||||
|
||||
- (UIImage *)imageByRotateLeft90 {
|
||||
return [self imageByRotate:DegreesToRadians(90) fitSize:YES];
|
||||
}
|
||||
|
||||
- (UIImage *)imageByRotateRight90 {
|
||||
return [self imageByRotate:DegreesToRadians(-90) fitSize:YES];
|
||||
}
|
||||
|
||||
- (UIImage *)imageByRotate180 {
|
||||
return [self _yy_flipHorizontal:YES vertical:YES];
|
||||
}
|
||||
|
||||
- (UIImage *)imageByFlipVertical {
|
||||
return [self _yy_flipHorizontal:NO vertical:YES];
|
||||
}
|
||||
|
||||
- (UIImage *)imageByFlipHorizontal {
|
||||
return [self _yy_flipHorizontal:YES vertical:NO];
|
||||
}
|
||||
|
||||
- (UIImage *)imageByTintColor:(UIColor *)color {
|
||||
UIGraphicsBeginImageContextWithOptions(self.size, NO, self.scale);
|
||||
CGRect rect = CGRectMake(0, 0, self.size.width, self.size.height);
|
||||
[color set];
|
||||
UIRectFill(rect);
|
||||
[self drawAtPoint:CGPointMake(0, 0) blendMode:kCGBlendModeDestinationIn alpha:1];
|
||||
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
return newImage;
|
||||
}
|
||||
|
||||
- (UIImage *)imageByGrayscale {
|
||||
return [self imageByBlurRadius:0 tintColor:nil tintMode:0 saturation:0 maskImage:nil];
|
||||
}
|
||||
|
||||
- (UIImage *)imageByBlurSoft {
|
||||
return [self imageByBlurRadius:60 tintColor:[UIColor colorWithWhite:0.84 alpha:0.36] tintMode:kCGBlendModeNormal saturation:1.8 maskImage:nil];
|
||||
}
|
||||
|
||||
- (UIImage *)imageByBlurLight {
|
||||
return [self imageByBlurRadius:60 tintColor:[UIColor colorWithWhite:1.0 alpha:0.3] tintMode:kCGBlendModeNormal saturation:1.8 maskImage:nil];
|
||||
}
|
||||
|
||||
- (UIImage *)imageByBlurExtraLight {
|
||||
return [self imageByBlurRadius:40 tintColor:[UIColor colorWithWhite:0.97 alpha:0.82] tintMode:kCGBlendModeNormal saturation:1.8 maskImage:nil];
|
||||
}
|
||||
|
||||
- (UIImage *)imageByBlurDark {
|
||||
return [self imageByBlurRadius:40 tintColor:[UIColor colorWithWhite:0.11 alpha:0.73] tintMode:kCGBlendModeNormal saturation:1.8 maskImage:nil];
|
||||
}
|
||||
|
||||
- (UIImage *)imageByBlurWithTint:(UIColor *)tintColor {
|
||||
const CGFloat EffectColorAlpha = 0.6;
|
||||
UIColor *effectColor = tintColor;
|
||||
size_t componentCount = CGColorGetNumberOfComponents(tintColor.CGColor);
|
||||
if (componentCount == 2) {
|
||||
CGFloat b;
|
||||
if ([tintColor getWhite:&b alpha:NULL]) {
|
||||
effectColor = [UIColor colorWithWhite:b alpha:EffectColorAlpha];
|
||||
}
|
||||
} else {
|
||||
CGFloat r, g, b;
|
||||
if ([tintColor getRed:&r green:&g blue:&b alpha:NULL]) {
|
||||
effectColor = [UIColor colorWithRed:r green:g blue:b alpha:EffectColorAlpha];
|
||||
}
|
||||
}
|
||||
return [self imageByBlurRadius:20 tintColor:effectColor tintMode:kCGBlendModeNormal saturation:-1.0 maskImage:nil];
|
||||
}
|
||||
|
||||
- (UIImage *)imageByBlurRadius:(CGFloat)blurRadius
|
||||
tintColor:(UIColor *)tintColor
|
||||
tintMode:(CGBlendMode)tintBlendMode
|
||||
saturation:(CGFloat)saturation
|
||||
maskImage:(UIImage *)maskImage {
|
||||
if (self.size.width < 1 || self.size.height < 1) {
|
||||
NSLog(@"UIImage+YYAdd error: invalid size: (%.2f x %.2f). Both dimensions must be >= 1: %@", self.size.width, self.size.height, self);
|
||||
return nil;
|
||||
}
|
||||
if (!self.CGImage) {
|
||||
NSLog(@"UIImage+YYAdd error: inputImage must be backed by a CGImage: %@", self);
|
||||
return nil;
|
||||
}
|
||||
if (maskImage && !maskImage.CGImage) {
|
||||
NSLog(@"UIImage+YYAdd error: effectMaskImage must be backed by a CGImage: %@", maskImage);
|
||||
return nil;
|
||||
}
|
||||
|
||||
// iOS7 and above can use new func.
|
||||
BOOL hasNewFunc = (long)vImageBuffer_InitWithCGImage != 0 && (long)vImageCreateCGImageFromBuffer != 0;
|
||||
BOOL hasBlur = blurRadius > __FLT_EPSILON__;
|
||||
BOOL hasSaturation = fabs(saturation - 1.0) > __FLT_EPSILON__;
|
||||
|
||||
CGSize size = self.size;
|
||||
CGRect rect = { CGPointZero, size };
|
||||
CGFloat scale = self.scale;
|
||||
CGImageRef imageRef = self.CGImage;
|
||||
BOOL opaque = NO;
|
||||
|
||||
if (!hasBlur && !hasSaturation) {
|
||||
return [self _yy_mergeImageRef:imageRef tintColor:tintColor tintBlendMode:tintBlendMode maskImage:maskImage opaque:opaque];
|
||||
}
|
||||
|
||||
vImage_Buffer effect = { 0 }, scratch = { 0 };
|
||||
vImage_Buffer *input = NULL, *output = NULL;
|
||||
|
||||
vImage_CGImageFormat format = {
|
||||
.bitsPerComponent = 8,
|
||||
.bitsPerPixel = 32,
|
||||
.colorSpace = NULL,
|
||||
.bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little, //requests a BGRA buffer.
|
||||
.version = 0,
|
||||
.decode = NULL,
|
||||
.renderingIntent = kCGRenderingIntentDefault
|
||||
};
|
||||
|
||||
if (hasNewFunc) {
|
||||
vImage_Error err;
|
||||
err = vImageBuffer_InitWithCGImage(&effect, &format, NULL, imageRef, kvImagePrintDiagnosticsToConsole);
|
||||
if (err != kvImageNoError) {
|
||||
NSLog(@"UIImage+YYAdd error: vImageBuffer_InitWithCGImage returned error code %zi for inputImage: %@", err, self);
|
||||
return nil;
|
||||
}
|
||||
err = vImageBuffer_Init(&scratch, effect.height, effect.width, format.bitsPerPixel, kvImageNoFlags);
|
||||
if (err != kvImageNoError) {
|
||||
NSLog(@"UIImage+YYAdd error: vImageBuffer_Init returned error code %zi for inputImage: %@", err, self);
|
||||
return nil;
|
||||
}
|
||||
} else {
|
||||
UIGraphicsBeginImageContextWithOptions(size, opaque, scale);
|
||||
CGContextRef effectCtx = UIGraphicsGetCurrentContext();
|
||||
CGContextScaleCTM(effectCtx, 1.0, -1.0);
|
||||
CGContextTranslateCTM(effectCtx, 0, -size.height);
|
||||
CGContextDrawImage(effectCtx, rect, imageRef);
|
||||
effect.data = CGBitmapContextGetData(effectCtx);
|
||||
effect.width = CGBitmapContextGetWidth(effectCtx);
|
||||
effect.height = CGBitmapContextGetHeight(effectCtx);
|
||||
effect.rowBytes = CGBitmapContextGetBytesPerRow(effectCtx);
|
||||
|
||||
UIGraphicsBeginImageContextWithOptions(size, opaque, scale);
|
||||
CGContextRef scratchCtx = UIGraphicsGetCurrentContext();
|
||||
scratch.data = CGBitmapContextGetData(scratchCtx);
|
||||
scratch.width = CGBitmapContextGetWidth(scratchCtx);
|
||||
scratch.height = CGBitmapContextGetHeight(scratchCtx);
|
||||
scratch.rowBytes = CGBitmapContextGetBytesPerRow(scratchCtx);
|
||||
}
|
||||
|
||||
input = &effect;
|
||||
output = &scratch;
|
||||
|
||||
if (hasBlur) {
|
||||
// A description of how to compute the box kernel width from the Gaussian
|
||||
// radius (aka standard deviation) appears in the SVG spec:
|
||||
// http://www.w3.org/TR/SVG/filters.html#feGaussianBlurElement
|
||||
//
|
||||
// For larger values of 's' (s >= 2.0), an approximation can be used: Three
|
||||
// successive box-blurs build a piece-wise quadratic convolution kernel, which
|
||||
// approximates the Gaussian kernel to within roughly 3%.
|
||||
//
|
||||
// let d = floor(s * 3*sqrt(2*pi)/4 + 0.5)
|
||||
//
|
||||
// ... if d is odd, use three box-blurs of size 'd', centered on the output pixel.
|
||||
//
|
||||
CGFloat inputRadius = blurRadius * scale;
|
||||
if (inputRadius - 2.0 < __FLT_EPSILON__) inputRadius = 2.0;
|
||||
uint32_t radius = floor((inputRadius * 3.0 * sqrt(2 * M_PI) / 4 + 0.5) / 2);
|
||||
radius |= 1; // force radius to be odd so that the three box-blur methodology works.
|
||||
int iterations;
|
||||
if (blurRadius * scale < 0.5) iterations = 1;
|
||||
else if (blurRadius * scale < 1.5) iterations = 2;
|
||||
else iterations = 3;
|
||||
NSInteger tempSize = vImageBoxConvolve_ARGB8888(input, output, NULL, 0, 0, radius, radius, NULL, kvImageGetTempBufferSize | kvImageEdgeExtend);
|
||||
void *temp = malloc(tempSize);
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
vImageBoxConvolve_ARGB8888(input, output, temp, 0, 0, radius, radius, NULL, kvImageEdgeExtend);
|
||||
YY_SWAP(input, output);
|
||||
}
|
||||
free(temp);
|
||||
}
|
||||
|
||||
|
||||
if (hasSaturation) {
|
||||
// These values appear in the W3C Filter Effects spec:
|
||||
// https://dvcs.w3.org/hg/FXTF/raw-file/default/filters/Publish.html#grayscaleEquivalent
|
||||
CGFloat s = saturation;
|
||||
CGFloat matrixFloat[] = {
|
||||
0.0722 + 0.9278 * s, 0.0722 - 0.0722 * s, 0.0722 - 0.0722 * s, 0,
|
||||
0.7152 - 0.7152 * s, 0.7152 + 0.2848 * s, 0.7152 - 0.7152 * s, 0,
|
||||
0.2126 - 0.2126 * s, 0.2126 - 0.2126 * s, 0.2126 + 0.7873 * s, 0,
|
||||
0, 0, 0, 1,
|
||||
};
|
||||
const int32_t divisor = 256;
|
||||
NSUInteger matrixSize = sizeof(matrixFloat) / sizeof(matrixFloat[0]);
|
||||
int16_t matrix[matrixSize];
|
||||
for (NSUInteger i = 0; i < matrixSize; ++i) {
|
||||
matrix[i] = (int16_t)roundf(matrixFloat[i] * divisor);
|
||||
}
|
||||
vImageMatrixMultiply_ARGB8888(input, output, matrix, divisor, NULL, NULL, kvImageNoFlags);
|
||||
YY_SWAP(input, output);
|
||||
}
|
||||
|
||||
UIImage *outputImage = nil;
|
||||
if (hasNewFunc) {
|
||||
CGImageRef effectCGImage = NULL;
|
||||
effectCGImage = vImageCreateCGImageFromBuffer(input, &format, &_yy_cleanupBuffer, NULL, kvImageNoAllocate, NULL);
|
||||
if (effectCGImage == NULL) {
|
||||
effectCGImage = vImageCreateCGImageFromBuffer(input, &format, NULL, NULL, kvImageNoFlags, NULL);
|
||||
free(input->data);
|
||||
}
|
||||
free(output->data);
|
||||
outputImage = [self _yy_mergeImageRef:effectCGImage tintColor:tintColor tintBlendMode:tintBlendMode maskImage:maskImage opaque:opaque];
|
||||
CGImageRelease(effectCGImage);
|
||||
} else {
|
||||
CGImageRef effectCGImage;
|
||||
UIImage *effectImage;
|
||||
if (input != &effect) effectImage = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
if (input == &effect) effectImage = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
effectCGImage = effectImage.CGImage;
|
||||
outputImage = [self _yy_mergeImageRef:effectCGImage tintColor:tintColor tintBlendMode:tintBlendMode maskImage:maskImage opaque:opaque];
|
||||
}
|
||||
return outputImage;
|
||||
}
|
||||
|
||||
// Helper function to handle deferred cleanup of a buffer.
|
||||
static void _yy_cleanupBuffer(void *userData, void *buf_data) {
|
||||
free(buf_data);
|
||||
}
|
||||
|
||||
// Helper function to add tint and mask.
|
||||
- (UIImage *)_yy_mergeImageRef:(CGImageRef)effectCGImage
|
||||
tintColor:(UIColor *)tintColor
|
||||
tintBlendMode:(CGBlendMode)tintBlendMode
|
||||
maskImage:(UIImage *)maskImage
|
||||
opaque:(BOOL)opaque {
|
||||
BOOL hasTint = tintColor != nil && CGColorGetAlpha(tintColor.CGColor) > __FLT_EPSILON__;
|
||||
BOOL hasMask = maskImage != nil;
|
||||
CGSize size = self.size;
|
||||
CGRect rect = { CGPointZero, size };
|
||||
CGFloat scale = self.scale;
|
||||
|
||||
if (!hasTint && !hasMask) {
|
||||
return [UIImage imageWithCGImage:effectCGImage];
|
||||
}
|
||||
|
||||
UIGraphicsBeginImageContextWithOptions(size, opaque, scale);
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
CGContextScaleCTM(context, 1.0, -1.0);
|
||||
CGContextTranslateCTM(context, 0, -size.height);
|
||||
if (hasMask) {
|
||||
CGContextDrawImage(context, rect, self.CGImage);
|
||||
CGContextSaveGState(context);
|
||||
CGContextClipToMask(context, rect, maskImage.CGImage);
|
||||
}
|
||||
CGContextDrawImage(context, rect, effectCGImage);
|
||||
if (hasTint) {
|
||||
CGContextSaveGState(context);
|
||||
CGContextSetBlendMode(context, tintBlendMode);
|
||||
CGContextSetFillColorWithColor(context, tintColor.CGColor);
|
||||
CGContextFillRect(context, rect);
|
||||
CGContextRestoreGState(context);
|
||||
}
|
||||
if (hasMask) {
|
||||
CGContextRestoreGState(context);
|
||||
}
|
||||
UIImage *outputImage = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
return outputImage;
|
||||
}
|
||||
|
||||
@end
|
||||
63
Pods/YYCategories/YYCategories/UIKit/UIScreen+YYAdd.h
generated
Normal file
63
Pods/YYCategories/YYCategories/UIKit/UIScreen+YYAdd.h
generated
Normal file
@@ -0,0 +1,63 @@
|
||||
//
|
||||
// UIScreen+YYAdd.h
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 13/4/5.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
Provides extensions for `UIScreen`.
|
||||
*/
|
||||
@interface UIScreen (YYAdd)
|
||||
|
||||
/**
|
||||
Main screen's scale
|
||||
|
||||
@return screen's scale
|
||||
*/
|
||||
+ (CGFloat)screenScale;
|
||||
|
||||
/**
|
||||
Returns the bounds of the screen for the current device orientation.
|
||||
|
||||
@return A rect indicating the bounds of the screen.
|
||||
@see boundsForOrientation:
|
||||
*/
|
||||
- (CGRect)currentBounds NS_EXTENSION_UNAVAILABLE_IOS("");
|
||||
|
||||
/**
|
||||
Returns the bounds of the screen for a given device orientation.
|
||||
`UIScreen`'s `bounds` method always returns the bounds of the
|
||||
screen of it in the portrait orientation.
|
||||
|
||||
@param orientation The orientation to get the screen's bounds.
|
||||
@return A rect indicating the bounds of the screen.
|
||||
@see currentBounds
|
||||
*/
|
||||
- (CGRect)boundsForOrientation:(UIInterfaceOrientation)orientation;
|
||||
|
||||
/**
|
||||
The screen's real size in pixel (width is always smaller than height).
|
||||
This value may not be very accurate in an unknown device, or simulator.
|
||||
e.g. (768,1024)
|
||||
*/
|
||||
@property (nonatomic, readonly) CGSize sizeInPixel;
|
||||
|
||||
/**
|
||||
The screen's PPI.
|
||||
This value may not be very accurate in an unknown device, or simulator.
|
||||
Default value is 96.
|
||||
*/
|
||||
@property (nonatomic, readonly) CGFloat pixelsPerInch;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
176
Pods/YYCategories/YYCategories/UIKit/UIScreen+YYAdd.m
generated
Normal file
176
Pods/YYCategories/YYCategories/UIKit/UIScreen+YYAdd.m
generated
Normal file
@@ -0,0 +1,176 @@
|
||||
//
|
||||
// UIScreen+YYAdd.m
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 13/4/5.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import "UIScreen+YYAdd.h"
|
||||
#import "YYCategoriesMacro.h"
|
||||
#import "UIDevice+YYAdd.h"
|
||||
|
||||
YYSYNTH_DUMMY_CLASS(UIScreen_YYAdd);
|
||||
|
||||
|
||||
@implementation UIScreen (YYAdd)
|
||||
|
||||
+ (CGFloat)screenScale {
|
||||
static CGFloat screenScale = 0.0;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
if ([NSThread isMainThread]) {
|
||||
screenScale = [[UIScreen mainScreen] scale];
|
||||
} else {
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
screenScale = [[UIScreen mainScreen] scale];
|
||||
});
|
||||
}
|
||||
});
|
||||
return screenScale;
|
||||
}
|
||||
|
||||
#ifdef __IPHONE_OS_VERSION_MIN_REQUIRED
|
||||
- (CGRect)currentBounds {
|
||||
return [self boundsForOrientation:[[UIApplication sharedApplication] statusBarOrientation]];
|
||||
}
|
||||
#endif
|
||||
|
||||
- (CGRect)boundsForOrientation:(UIInterfaceOrientation)orientation {
|
||||
CGRect bounds = [self bounds];
|
||||
|
||||
if (UIInterfaceOrientationIsLandscape(orientation)) {
|
||||
CGFloat buffer = bounds.size.width;
|
||||
bounds.size.width = bounds.size.height;
|
||||
bounds.size.height = buffer;
|
||||
}
|
||||
return bounds;
|
||||
}
|
||||
|
||||
- (CGSize)sizeInPixel {
|
||||
CGSize size = CGSizeZero;
|
||||
|
||||
if ([[UIScreen mainScreen] isEqual:self]) {
|
||||
NSString *model = [UIDevice currentDevice].machineModel;
|
||||
|
||||
if ([model hasPrefix:@"iPhone"]) {
|
||||
if ([model isEqualToString:@"iPhone7,1"]) return CGSizeMake(1080, 1920);
|
||||
if ([model isEqualToString:@"iPhone8,2"]) return CGSizeMake(1080, 1920);
|
||||
if ([model isEqualToString:@"iPhone9,2"]) return CGSizeMake(1080, 1920);
|
||||
if ([model isEqualToString:@"iPhone9,4"]) return CGSizeMake(1080, 1920);
|
||||
}
|
||||
if ([model hasPrefix:@"iPad"]) {
|
||||
if ([model hasPrefix:@"iPad6,7"]) size = CGSizeMake(2048, 2732);
|
||||
if ([model hasPrefix:@"iPad6,8"]) size = CGSizeMake(2048, 2732);
|
||||
}
|
||||
}
|
||||
|
||||
if (CGSizeEqualToSize(size, CGSizeZero)) {
|
||||
if ([self respondsToSelector:@selector(nativeBounds)]) {
|
||||
size = self.nativeBounds.size;
|
||||
} else {
|
||||
size = self.bounds.size;
|
||||
size.width *= self.scale;
|
||||
size.height *= self.scale;
|
||||
}
|
||||
if (size.height < size.width) {
|
||||
CGFloat tmp = size.height;
|
||||
size.height = size.width;
|
||||
size.width = tmp;
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
- (CGFloat)pixelsPerInch {
|
||||
if (![[UIScreen mainScreen] isEqual:self]) {
|
||||
return 326;
|
||||
}
|
||||
|
||||
static CGFloat ppi = 0;
|
||||
static dispatch_once_t one;
|
||||
static NSString *name;
|
||||
dispatch_once(&one, ^{
|
||||
NSDictionary<NSString*, NSNumber *> *dic = @{
|
||||
@"Watch1,1" : @326, //@"Apple Watch 38mm",
|
||||
@"Watch1,2" : @326, //@"Apple Watch 43mm",
|
||||
@"Watch2,3" : @326, //@"Apple Watch Series 2 38mm",
|
||||
@"Watch2,4" : @326, //@"Apple Watch Series 2 42mm",
|
||||
@"Watch2,6" : @326, //@"Apple Watch Series 1 38mm",
|
||||
@"Watch1,7" : @326, //@"Apple Watch Series 1 42mm",
|
||||
|
||||
@"iPod1,1" : @163, //@"iPod touch 1",
|
||||
@"iPod2,1" : @163, //@"iPod touch 2",
|
||||
@"iPod3,1" : @163, //@"iPod touch 3",
|
||||
@"iPod4,1" : @326, //@"iPod touch 4",
|
||||
@"iPod5,1" : @326, //@"iPod touch 5",
|
||||
@"iPod7,1" : @326, //@"iPod touch 6",
|
||||
|
||||
@"iPhone1,1" : @163, //@"iPhone 1G",
|
||||
@"iPhone1,2" : @163, //@"iPhone 3G",
|
||||
@"iPhone2,1" : @163, //@"iPhone 3GS",
|
||||
@"iPhone3,1" : @326, //@"iPhone 4 (GSM)",
|
||||
@"iPhone3,2" : @326, //@"iPhone 4",
|
||||
@"iPhone3,3" : @326, //@"iPhone 4 (CDMA)",
|
||||
@"iPhone4,1" : @326, //@"iPhone 4S",
|
||||
@"iPhone5,1" : @326, //@"iPhone 5",
|
||||
@"iPhone5,2" : @326, //@"iPhone 5",
|
||||
@"iPhone5,3" : @326, //@"iPhone 5c",
|
||||
@"iPhone5,4" : @326, //@"iPhone 5c",
|
||||
@"iPhone6,1" : @326, //@"iPhone 5s",
|
||||
@"iPhone6,2" : @326, //@"iPhone 5s",
|
||||
@"iPhone7,1" : @401, //@"iPhone 6 Plus",
|
||||
@"iPhone7,2" : @326, //@"iPhone 6",
|
||||
@"iPhone8,1" : @326, //@"iPhone 6s",
|
||||
@"iPhone8,2" : @401, //@"iPhone 6s Plus",
|
||||
@"iPhone8,4" : @326, //@"iPhone SE",
|
||||
@"iPhone9,1" : @326, //@"iPhone 7",
|
||||
@"iPhone9,2" : @401, //@"iPhone 7 Plus",
|
||||
@"iPhone9,3" : @326, //@"iPhone 7",
|
||||
@"iPhone9,4" : @401, //@"iPhone 7 Plus",
|
||||
|
||||
@"iPad1,1" : @132, //@"iPad 1",
|
||||
@"iPad2,1" : @132, //@"iPad 2 (WiFi)",
|
||||
@"iPad2,2" : @132, //@"iPad 2 (GSM)",
|
||||
@"iPad2,3" : @132, //@"iPad 2 (CDMA)",
|
||||
@"iPad2,4" : @132, //@"iPad 2",
|
||||
@"iPad2,5" : @264, //@"iPad mini 1",
|
||||
@"iPad2,6" : @264, //@"iPad mini 1",
|
||||
@"iPad2,7" : @264, //@"iPad mini 1",
|
||||
@"iPad3,1" : @324, //@"iPad 3 (WiFi)",
|
||||
@"iPad3,2" : @324, //@"iPad 3 (4G)",
|
||||
@"iPad3,3" : @324, //@"iPad 3 (4G)",
|
||||
@"iPad3,4" : @324, //@"iPad 4",
|
||||
@"iPad3,5" : @324, //@"iPad 4",
|
||||
@"iPad3,6" : @324, //@"iPad 4",
|
||||
@"iPad4,1" : @324, //@"iPad Air",
|
||||
@"iPad4,2" : @324, //@"iPad Air",
|
||||
@"iPad4,3" : @324, //@"iPad Air",
|
||||
@"iPad4,4" : @264, //@"iPad mini 2",
|
||||
@"iPad4,5" : @264, //@"iPad mini 2",
|
||||
@"iPad4,6" : @264, //@"iPad mini 2",
|
||||
@"iPad4,7" : @264, //@"iPad mini 3",
|
||||
@"iPad4,8" : @264, //@"iPad mini 3",
|
||||
@"iPad4,9" : @264, //@"iPad mini 3",
|
||||
@"iPad5,1" : @264, //@"iPad mini 4",
|
||||
@"iPad5,2" : @264, //@"iPad mini 4",
|
||||
@"iPad5,3" : @324, //@"iPad Air 2",
|
||||
@"iPad5,4" : @324, //@"iPad Air 2",
|
||||
@"iPad6,3" : @324, //@"iPad Pro (9.7 inch)",
|
||||
@"iPad6,4" : @324, //@"iPad Pro (9.7 inch)",
|
||||
@"iPad6,7" : @264, //@"iPad Pro (12.9 inch)",
|
||||
@"iPad6,8" : @264, //@"iPad Pro (12.9 inch)",
|
||||
};
|
||||
NSString *model = [UIDevice currentDevice].machineModel;
|
||||
if (model) {
|
||||
ppi = dic[name].doubleValue;
|
||||
}
|
||||
if (ppi == 0) ppi = 326;
|
||||
});
|
||||
return ppi;
|
||||
}
|
||||
|
||||
@end
|
||||
71
Pods/YYCategories/YYCategories/UIKit/UIScrollView+YYAdd.h
generated
Normal file
71
Pods/YYCategories/YYCategories/UIKit/UIScrollView+YYAdd.h
generated
Normal file
@@ -0,0 +1,71 @@
|
||||
//
|
||||
// UIScrollView+YYAdd.h
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 13/4/5.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
Provides extensions for `UIScrollView`.
|
||||
*/
|
||||
@interface UIScrollView (YYAdd)
|
||||
|
||||
/**
|
||||
Scroll content to top with animation.
|
||||
*/
|
||||
- (void)scrollToTop;
|
||||
|
||||
/**
|
||||
Scroll content to bottom with animation.
|
||||
*/
|
||||
- (void)scrollToBottom;
|
||||
|
||||
/**
|
||||
Scroll content to left with animation.
|
||||
*/
|
||||
- (void)scrollToLeft;
|
||||
|
||||
/**
|
||||
Scroll content to right with animation.
|
||||
*/
|
||||
- (void)scrollToRight;
|
||||
|
||||
/**
|
||||
Scroll content to top.
|
||||
|
||||
@param animated Use animation.
|
||||
*/
|
||||
- (void)scrollToTopAnimated:(BOOL)animated;
|
||||
|
||||
/**
|
||||
Scroll content to bottom.
|
||||
|
||||
@param animated Use animation.
|
||||
*/
|
||||
- (void)scrollToBottomAnimated:(BOOL)animated;
|
||||
|
||||
/**
|
||||
Scroll content to left.
|
||||
|
||||
@param animated Use animation.
|
||||
*/
|
||||
- (void)scrollToLeftAnimated:(BOOL)animated;
|
||||
|
||||
/**
|
||||
Scroll content to right.
|
||||
|
||||
@param animated Use animation.
|
||||
*/
|
||||
- (void)scrollToRightAnimated:(BOOL)animated;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
60
Pods/YYCategories/YYCategories/UIKit/UIScrollView+YYAdd.m
generated
Normal file
60
Pods/YYCategories/YYCategories/UIKit/UIScrollView+YYAdd.m
generated
Normal file
@@ -0,0 +1,60 @@
|
||||
//
|
||||
// UIScrollView+YYAdd.m
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 13/4/5.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import "UIScrollView+YYAdd.h"
|
||||
#import "YYCategoriesMacro.h"
|
||||
|
||||
YYSYNTH_DUMMY_CLASS(UIScrollView_YYAdd)
|
||||
|
||||
|
||||
@implementation UIScrollView (YYAdd)
|
||||
|
||||
- (void)scrollToTop {
|
||||
[self scrollToTopAnimated:YES];
|
||||
}
|
||||
|
||||
- (void)scrollToBottom {
|
||||
[self scrollToBottomAnimated:YES];
|
||||
}
|
||||
|
||||
- (void)scrollToLeft {
|
||||
[self scrollToLeftAnimated:YES];
|
||||
}
|
||||
|
||||
- (void)scrollToRight {
|
||||
[self scrollToRightAnimated:YES];
|
||||
}
|
||||
|
||||
- (void)scrollToTopAnimated:(BOOL)animated {
|
||||
CGPoint off = self.contentOffset;
|
||||
off.y = 0 - self.contentInset.top;
|
||||
[self setContentOffset:off animated:animated];
|
||||
}
|
||||
|
||||
- (void)scrollToBottomAnimated:(BOOL)animated {
|
||||
CGPoint off = self.contentOffset;
|
||||
off.y = self.contentSize.height - self.bounds.size.height + self.contentInset.bottom;
|
||||
[self setContentOffset:off animated:animated];
|
||||
}
|
||||
|
||||
- (void)scrollToLeftAnimated:(BOOL)animated {
|
||||
CGPoint off = self.contentOffset;
|
||||
off.x = 0 - self.contentInset.left;
|
||||
[self setContentOffset:off animated:animated];
|
||||
}
|
||||
|
||||
- (void)scrollToRightAnimated:(BOOL)animated {
|
||||
CGPoint off = self.contentOffset;
|
||||
off.x = self.contentSize.width - self.bounds.size.width + self.contentInset.right;
|
||||
[self setContentOffset:off animated:animated];
|
||||
}
|
||||
|
||||
@end
|
||||
188
Pods/YYCategories/YYCategories/UIKit/UITableView+YYAdd.h
generated
Normal file
188
Pods/YYCategories/YYCategories/UIKit/UITableView+YYAdd.h
generated
Normal file
@@ -0,0 +1,188 @@
|
||||
//
|
||||
// UITableView+YYAdd.h
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 14/5/12.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
Provides extensions for `UITableView`.
|
||||
*/
|
||||
@interface UITableView (YYAdd)
|
||||
|
||||
/**
|
||||
Perform a series of method calls that insert, delete, or select rows and
|
||||
sections of the receiver.
|
||||
|
||||
@discussion Perform a series of method calls that insert, delete, or select
|
||||
rows and sections of the table. Call this method if you want
|
||||
subsequent insertions, deletion, and selection operations (for
|
||||
example, cellForRowAtIndexPath: and indexPathsForVisibleRows)
|
||||
to be animated simultaneously.
|
||||
|
||||
@discussion If you do not make the insertion, deletion, and selection calls
|
||||
inside this block, table attributes such as row count might become
|
||||
invalid. You should not call reloadData within the block; if you
|
||||
call this method within the group, you will need to perform any
|
||||
animations yourself.
|
||||
|
||||
@param block A block combine a series of method calls.
|
||||
*/
|
||||
- (void)updateWithBlock:(void (^)(UITableView *tableView))block;
|
||||
|
||||
/**
|
||||
Scrolls the receiver until a row or section location on the screen.
|
||||
|
||||
@discussion Invoking this method does not cause the delegate to
|
||||
receive a scrollViewDidScroll: message, as is normal for
|
||||
programmatically-invoked user interface operations.
|
||||
|
||||
@param row Row index in section. NSNotFound is a valid value for
|
||||
scrolling to a section with zero rows.
|
||||
|
||||
@param section Section index in table.
|
||||
|
||||
@param scrollPosition A constant that identifies a relative position in the
|
||||
receiving table view (top, middle, bottom) for row when
|
||||
scrolling concludes.
|
||||
|
||||
@param animated YES if you want to animate the change in position,
|
||||
NO if it should be immediate.
|
||||
*/
|
||||
- (void)scrollToRow:(NSUInteger)row inSection:(NSUInteger)section atScrollPosition:(UITableViewScrollPosition)scrollPosition animated:(BOOL)animated;
|
||||
|
||||
/**
|
||||
Inserts a row in the receiver with an option to animate the insertion.
|
||||
|
||||
@param row Row index in section.
|
||||
|
||||
@param section Section index in table.
|
||||
|
||||
@param animation A constant that either specifies the kind of animation to
|
||||
perform when inserting the cell or requests no animation.
|
||||
*/
|
||||
- (void)insertRow:(NSUInteger)row inSection:(NSUInteger)section withRowAnimation:(UITableViewRowAnimation)animation;
|
||||
|
||||
/**
|
||||
Reloads the specified row using a certain animation effect.
|
||||
|
||||
@param row Row index in section.
|
||||
|
||||
@param section Section index in table.
|
||||
|
||||
@param animation A constant that indicates how the reloading is to be animated,
|
||||
for example, fade out or slide out from the bottom. The animation
|
||||
constant affects the direction in which both the old and the
|
||||
new rows slide. For example, if the animation constant is
|
||||
UITableViewRowAnimationRight, the old rows slide out to the
|
||||
right and the new cells slide in from the right.
|
||||
*/
|
||||
- (void)reloadRow:(NSUInteger)row inSection:(NSUInteger)section withRowAnimation:(UITableViewRowAnimation)animation;
|
||||
|
||||
/**
|
||||
Deletes the row with an option to animate the deletion.
|
||||
|
||||
@param row Row index in section.
|
||||
|
||||
@param section Section index in table.
|
||||
|
||||
@param animation A constant that indicates how the deletion is to be animated,
|
||||
for example, fade out or slide out from the bottom.
|
||||
*/
|
||||
- (void)deleteRow:(NSUInteger)row inSection:(NSUInteger)section withRowAnimation:(UITableViewRowAnimation)animation;
|
||||
|
||||
/**
|
||||
Inserts the row in the receiver at the locations identified by the indexPath,
|
||||
with an option to animate the insertion.
|
||||
|
||||
@param indexPath An NSIndexPath object representing a row index and section
|
||||
index that together identify a row in the table view.
|
||||
|
||||
@param animation A constant that either specifies the kind of animation to
|
||||
perform when inserting the cell or requests no animation.
|
||||
*/
|
||||
- (void)insertRowAtIndexPath:(NSIndexPath *)indexPath withRowAnimation:(UITableViewRowAnimation)animation;
|
||||
|
||||
/**
|
||||
Reloads the specified row using a certain animation effect.
|
||||
|
||||
@param indexPath An NSIndexPath object representing a row index and section
|
||||
index that together identify a row in the table view.
|
||||
|
||||
@param animation A constant that indicates how the reloading is to be animated,
|
||||
for example, fade out or slide out from the bottom. The animation
|
||||
constant affects the direction in which both the old and the
|
||||
new rows slide. For example, if the animation constant is
|
||||
UITableViewRowAnimationRight, the old rows slide out to the
|
||||
right and the new cells slide in from the right.
|
||||
*/
|
||||
- (void)reloadRowAtIndexPath:(NSIndexPath *)indexPath withRowAnimation:(UITableViewRowAnimation)animation;
|
||||
|
||||
/**
|
||||
Deletes the row specified by an array of index paths,
|
||||
with an option to animate the deletion.
|
||||
|
||||
@param indexPath An NSIndexPath object representing a row index and section
|
||||
index that together identify a row in the table view.
|
||||
|
||||
@param animation A constant that indicates how the deletion is to be animated,
|
||||
for example, fade out or slide out from the bottom.
|
||||
*/
|
||||
- (void)deleteRowAtIndexPath:(NSIndexPath *)indexPath withRowAnimation:(UITableViewRowAnimation)animation;
|
||||
|
||||
/**
|
||||
Inserts a section in the receiver, with an option to animate the insertion.
|
||||
|
||||
@param section An index specifies the section to insert in the receiving
|
||||
table view. If a section already exists at the specified
|
||||
index location, it is moved down one index location.
|
||||
|
||||
@param animation A constant that indicates how the insertion is to be animated,
|
||||
for example, fade in or slide in from the left.
|
||||
*/
|
||||
- (void)insertSection:(NSUInteger)section withRowAnimation:(UITableViewRowAnimation)animation;
|
||||
|
||||
/**
|
||||
Deletes a section in the receiver, with an option to animate the deletion.
|
||||
|
||||
@param section An index that specifies the sections to delete from the
|
||||
receiving table view. If a section exists after the specified
|
||||
index location, it is moved up one index location.
|
||||
|
||||
@param animation A constant that either specifies the kind of animation to
|
||||
perform when deleting the section or requests no animation.
|
||||
*/
|
||||
- (void)deleteSection:(NSUInteger)section withRowAnimation:(UITableViewRowAnimation)animation;
|
||||
|
||||
/**
|
||||
Reloads the specified section using a given animation effect.
|
||||
|
||||
@param section An index identifying the section to reload.
|
||||
|
||||
@param animation A constant that indicates how the reloading is to be animated,
|
||||
for example, fade out or slide out from the bottom. The
|
||||
animation constant affects the direction in which both the
|
||||
old and the new section rows slide. For example, if the
|
||||
animation constant is UITableViewRowAnimationRight, the old
|
||||
rows slide out to the right and the new cells slide in from the right.
|
||||
*/
|
||||
- (void)reloadSection:(NSUInteger)section withRowAnimation:(UITableViewRowAnimation)animation;
|
||||
|
||||
/**
|
||||
Unselect all rows in tableView.
|
||||
|
||||
@param animated YES to animate the transition, NO to make the transition immediate.
|
||||
*/
|
||||
- (void)clearSelectedRowsAnimated:(BOOL)animated;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
80
Pods/YYCategories/YYCategories/UIKit/UITableView+YYAdd.m
generated
Normal file
80
Pods/YYCategories/YYCategories/UIKit/UITableView+YYAdd.m
generated
Normal file
@@ -0,0 +1,80 @@
|
||||
//
|
||||
// UITableView+YYAdd.m
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 14/5/12.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import "UITableView+YYAdd.h"
|
||||
#import "YYCategoriesMacro.h"
|
||||
|
||||
YYSYNTH_DUMMY_CLASS(UITableView_YYAdd)
|
||||
|
||||
|
||||
@implementation UITableView (YYAdd)
|
||||
|
||||
- (void)updateWithBlock:(void (^)(UITableView *tableView))block {
|
||||
[self beginUpdates];
|
||||
block(self);
|
||||
[self endUpdates];
|
||||
}
|
||||
|
||||
- (void)scrollToRow:(NSUInteger)row inSection:(NSUInteger)section atScrollPosition:(UITableViewScrollPosition)scrollPosition animated:(BOOL)animated {
|
||||
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:section];
|
||||
[self scrollToRowAtIndexPath:indexPath atScrollPosition:scrollPosition animated:animated];
|
||||
}
|
||||
|
||||
- (void)insertRowAtIndexPath:(NSIndexPath *)indexPath withRowAnimation:(UITableViewRowAnimation)animation {
|
||||
[self insertRowsAtIndexPaths:@[indexPath] withRowAnimation:animation];
|
||||
}
|
||||
|
||||
- (void)insertRow:(NSUInteger)row inSection:(NSUInteger)section withRowAnimation:(UITableViewRowAnimation)animation {
|
||||
NSIndexPath *toInsert = [NSIndexPath indexPathForRow:row inSection:section];
|
||||
[self insertRowAtIndexPath:toInsert withRowAnimation:animation];
|
||||
}
|
||||
|
||||
- (void)reloadRowAtIndexPath:(NSIndexPath *)indexPath withRowAnimation:(UITableViewRowAnimation)animation {
|
||||
[self reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:animation];
|
||||
}
|
||||
|
||||
- (void)reloadRow:(NSUInteger)row inSection:(NSUInteger)section withRowAnimation:(UITableViewRowAnimation)animation {
|
||||
NSIndexPath *toReload = [NSIndexPath indexPathForRow:row inSection:section];
|
||||
[self reloadRowAtIndexPath:toReload withRowAnimation:animation];
|
||||
}
|
||||
|
||||
- (void)deleteRowAtIndexPath:(NSIndexPath *)indexPath withRowAnimation:(UITableViewRowAnimation)animation {
|
||||
[self deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:animation];
|
||||
}
|
||||
|
||||
- (void)deleteRow:(NSUInteger)row inSection:(NSUInteger)section withRowAnimation:(UITableViewRowAnimation)animation {
|
||||
NSIndexPath *toDelete = [NSIndexPath indexPathForRow:row inSection:section];
|
||||
[self deleteRowAtIndexPath:toDelete withRowAnimation:animation];
|
||||
}
|
||||
|
||||
- (void)insertSection:(NSUInteger)section withRowAnimation:(UITableViewRowAnimation)animation {
|
||||
NSIndexSet *sections = [NSIndexSet indexSetWithIndex:section];
|
||||
[self insertSections:sections withRowAnimation:animation];
|
||||
}
|
||||
|
||||
- (void)deleteSection:(NSUInteger)section withRowAnimation:(UITableViewRowAnimation)animation {
|
||||
NSIndexSet *sections = [NSIndexSet indexSetWithIndex:section];
|
||||
[self deleteSections:sections withRowAnimation:animation];
|
||||
}
|
||||
|
||||
- (void)reloadSection:(NSUInteger)section withRowAnimation:(UITableViewRowAnimation)animation {
|
||||
NSIndexSet *indexSet = [NSIndexSet indexSetWithIndex:section];
|
||||
[self reloadSections:indexSet withRowAnimation:animation];
|
||||
}
|
||||
|
||||
- (void)clearSelectedRowsAnimated:(BOOL)animated {
|
||||
NSArray *indexs = [self indexPathsForSelectedRows];
|
||||
[indexs enumerateObjectsUsingBlock:^(NSIndexPath* path, NSUInteger idx, BOOL *stop) {
|
||||
[self deselectRowAtIndexPath:path animated:animated];
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
||||
35
Pods/YYCategories/YYCategories/UIKit/UITextField+YYAdd.h
generated
Normal file
35
Pods/YYCategories/YYCategories/UIKit/UITextField+YYAdd.h
generated
Normal file
@@ -0,0 +1,35 @@
|
||||
//
|
||||
// UITextField+YYAdd.h
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 14/5/12.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
Provides extensions for `UITextField`.
|
||||
*/
|
||||
@interface UITextField (YYAdd)
|
||||
|
||||
/**
|
||||
Set all text selected.
|
||||
*/
|
||||
- (void)selectAllText;
|
||||
|
||||
/**
|
||||
Set text in range selected.
|
||||
|
||||
@param range The range of selected text in a document.
|
||||
*/
|
||||
- (void)setSelectedRange:(NSRange)range;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
33
Pods/YYCategories/YYCategories/UIKit/UITextField+YYAdd.m
generated
Normal file
33
Pods/YYCategories/YYCategories/UIKit/UITextField+YYAdd.m
generated
Normal file
@@ -0,0 +1,33 @@
|
||||
//
|
||||
// UITextField+YYAdd.m
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 14/5/12.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import "UITextField+YYAdd.h"
|
||||
#import "YYCategoriesMacro.h"
|
||||
|
||||
YYSYNTH_DUMMY_CLASS(UITextField_YYAdd)
|
||||
|
||||
|
||||
@implementation UITextField (YYAdd)
|
||||
|
||||
- (void)selectAllText {
|
||||
UITextRange *range = [self textRangeFromPosition:self.beginningOfDocument toPosition:self.endOfDocument];
|
||||
[self setSelectedTextRange:range];
|
||||
}
|
||||
|
||||
- (void)setSelectedRange:(NSRange)range {
|
||||
UITextPosition *beginning = self.beginningOfDocument;
|
||||
UITextPosition *startPosition = [self positionFromPosition:beginning offset:range.location];
|
||||
UITextPosition *endPosition = [self positionFromPosition:beginning offset:NSMaxRange(range)];
|
||||
UITextRange *selectionRange = [self textRangeFromPosition:startPosition toPosition:endPosition];
|
||||
[self setSelectedTextRange:selectionRange];
|
||||
}
|
||||
|
||||
@end
|
||||
117
Pods/YYCategories/YYCategories/UIKit/UIView+YYAdd.h
generated
Normal file
117
Pods/YYCategories/YYCategories/UIKit/UIView+YYAdd.h
generated
Normal file
@@ -0,0 +1,117 @@
|
||||
//
|
||||
// UIView+YYAdd.h
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 13/4/3.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
Provides extensions for `UIView`.
|
||||
*/
|
||||
@interface UIView (YYAdd)
|
||||
|
||||
/**
|
||||
Create a snapshot image of the complete view hierarchy.
|
||||
*/
|
||||
- (nullable UIImage *)snapshotImage;
|
||||
|
||||
/**
|
||||
Create a snapshot image of the complete view hierarchy.
|
||||
@discussion It's faster than "snapshotImage", but may cause screen updates.
|
||||
See -[UIView drawViewHierarchyInRect:afterScreenUpdates:] for more information.
|
||||
*/
|
||||
- (nullable UIImage *)snapshotImageAfterScreenUpdates:(BOOL)afterUpdates;
|
||||
|
||||
/**
|
||||
Create a snapshot PDF of the complete view hierarchy.
|
||||
*/
|
||||
- (nullable NSData *)snapshotPDF;
|
||||
|
||||
/**
|
||||
Shortcut to set the view.layer's shadow
|
||||
|
||||
@param color Shadow Color
|
||||
@param offset Shadow offset
|
||||
@param radius Shadow radius
|
||||
*/
|
||||
- (void)setLayerShadow:(nullable UIColor*)color offset:(CGSize)offset radius:(CGFloat)radius;
|
||||
|
||||
/**
|
||||
Remove all subviews.
|
||||
|
||||
@warning Never call this method inside your view's drawRect: method.
|
||||
*/
|
||||
- (void)removeAllSubviews;
|
||||
|
||||
/**
|
||||
Returns the view's view controller (may be nil).
|
||||
*/
|
||||
@property (nullable, nonatomic, readonly) UIViewController *viewController;
|
||||
|
||||
/**
|
||||
Returns the visible alpha on screen, taking into account superview and window.
|
||||
*/
|
||||
@property (nonatomic, readonly) CGFloat visibleAlpha;
|
||||
|
||||
/**
|
||||
Converts a point from the receiver's coordinate system to that of the specified view or window.
|
||||
|
||||
@param point A point specified in the local coordinate system (bounds) of the receiver.
|
||||
@param view The view or window into whose coordinate system point is to be converted.
|
||||
If view is nil, this method instead converts to window base coordinates.
|
||||
@return The point converted to the coordinate system of view.
|
||||
*/
|
||||
- (CGPoint)convertPoint:(CGPoint)point toViewOrWindow:(nullable UIView *)view;
|
||||
|
||||
/**
|
||||
Converts a point from the coordinate system of a given view or window to that of the receiver.
|
||||
|
||||
@param point A point specified in the local coordinate system (bounds) of view.
|
||||
@param view The view or window with point in its coordinate system.
|
||||
If view is nil, this method instead converts from window base coordinates.
|
||||
@return The point converted to the local coordinate system (bounds) of the receiver.
|
||||
*/
|
||||
- (CGPoint)convertPoint:(CGPoint)point fromViewOrWindow:(nullable UIView *)view;
|
||||
|
||||
/**
|
||||
Converts a rectangle from the receiver's coordinate system to that of another view or window.
|
||||
|
||||
@param rect A rectangle specified in the local coordinate system (bounds) of the receiver.
|
||||
@param view The view or window that is the target of the conversion operation. If view is nil, this method instead converts to window base coordinates.
|
||||
@return The converted rectangle.
|
||||
*/
|
||||
- (CGRect)convertRect:(CGRect)rect toViewOrWindow:(nullable UIView *)view;
|
||||
|
||||
/**
|
||||
Converts a rectangle from the coordinate system of another view or window to that of the receiver.
|
||||
|
||||
@param rect A rectangle specified in the local coordinate system (bounds) of view.
|
||||
@param view The view or window with rect in its coordinate system.
|
||||
If view is nil, this method instead converts from window base coordinates.
|
||||
@return The converted rectangle.
|
||||
*/
|
||||
- (CGRect)convertRect:(CGRect)rect fromViewOrWindow:(nullable UIView *)view;
|
||||
|
||||
|
||||
@property (nonatomic) CGFloat left; ///< Shortcut for frame.origin.x.
|
||||
@property (nonatomic) CGFloat top; ///< Shortcut for frame.origin.y
|
||||
@property (nonatomic) CGFloat right; ///< Shortcut for frame.origin.x + frame.size.width
|
||||
@property (nonatomic) CGFloat bottom; ///< Shortcut for frame.origin.y + frame.size.height
|
||||
@property (nonatomic) CGFloat width; ///< Shortcut for frame.size.width.
|
||||
@property (nonatomic) CGFloat height; ///< Shortcut for frame.size.height.
|
||||
@property (nonatomic) CGFloat centerX; ///< Shortcut for center.x
|
||||
@property (nonatomic) CGFloat centerY; ///< Shortcut for center.y
|
||||
@property (nonatomic) CGPoint origin; ///< Shortcut for frame.origin.
|
||||
@property (nonatomic) CGSize size; ///< Shortcut for frame.size.
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
272
Pods/YYCategories/YYCategories/UIKit/UIView+YYAdd.m
generated
Normal file
272
Pods/YYCategories/YYCategories/UIKit/UIView+YYAdd.m
generated
Normal file
@@ -0,0 +1,272 @@
|
||||
//
|
||||
// UIView+YYAdd.m
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 13/4/3.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import "UIView+YYAdd.h"
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
#import "YYCategoriesMacro.h"
|
||||
|
||||
YYSYNTH_DUMMY_CLASS(UIView_YYAdd)
|
||||
|
||||
|
||||
@implementation UIView (YYAdd)
|
||||
|
||||
- (UIImage *)snapshotImage {
|
||||
UIGraphicsBeginImageContextWithOptions(self.bounds.size, self.opaque, 0);
|
||||
[self.layer renderInContext:UIGraphicsGetCurrentContext()];
|
||||
UIImage *snap = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
return snap;
|
||||
}
|
||||
|
||||
- (UIImage *)snapshotImageAfterScreenUpdates:(BOOL)afterUpdates {
|
||||
if (![self respondsToSelector:@selector(drawViewHierarchyInRect:afterScreenUpdates:)]) {
|
||||
return [self snapshotImage];
|
||||
}
|
||||
UIGraphicsBeginImageContextWithOptions(self.bounds.size, self.opaque, 0);
|
||||
[self drawViewHierarchyInRect:self.bounds afterScreenUpdates:afterUpdates];
|
||||
UIImage *snap = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
return snap;
|
||||
}
|
||||
|
||||
- (NSData *)snapshotPDF {
|
||||
CGRect bounds = self.bounds;
|
||||
NSMutableData* data = [NSMutableData data];
|
||||
CGDataConsumerRef consumer = CGDataConsumerCreateWithCFData((__bridge CFMutableDataRef)data);
|
||||
CGContextRef context = CGPDFContextCreate(consumer, &bounds, NULL);
|
||||
CGDataConsumerRelease(consumer);
|
||||
if (!context) return nil;
|
||||
CGPDFContextBeginPage(context, NULL);
|
||||
CGContextTranslateCTM(context, 0, bounds.size.height);
|
||||
CGContextScaleCTM(context, 1.0, -1.0);
|
||||
[self.layer renderInContext:context];
|
||||
CGPDFContextEndPage(context);
|
||||
CGPDFContextClose(context);
|
||||
CGContextRelease(context);
|
||||
return data;
|
||||
}
|
||||
|
||||
- (void)setLayerShadow:(UIColor*)color offset:(CGSize)offset radius:(CGFloat)radius {
|
||||
self.layer.shadowColor = color.CGColor;
|
||||
self.layer.shadowOffset = offset;
|
||||
self.layer.shadowRadius = radius;
|
||||
self.layer.shadowOpacity = 1;
|
||||
self.layer.shouldRasterize = YES;
|
||||
self.layer.rasterizationScale = [UIScreen mainScreen].scale;
|
||||
}
|
||||
|
||||
- (void)removeAllSubviews {
|
||||
//[self.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
|
||||
while (self.subviews.count) {
|
||||
[self.subviews.lastObject removeFromSuperview];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (UIViewController *)viewController {
|
||||
for (UIView *view = self; view; view = view.superview) {
|
||||
UIResponder *nextResponder = [view nextResponder];
|
||||
if ([nextResponder isKindOfClass:[UIViewController class]]) {
|
||||
return (UIViewController *)nextResponder;
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (CGFloat)visibleAlpha {
|
||||
if ([self isKindOfClass:[UIWindow class]]) {
|
||||
if (self.hidden) return 0;
|
||||
return self.alpha;
|
||||
}
|
||||
if (!self.window) return 0;
|
||||
CGFloat alpha = 1;
|
||||
UIView *v = self;
|
||||
while (v) {
|
||||
if (v.hidden) {
|
||||
alpha = 0;
|
||||
break;
|
||||
}
|
||||
alpha *= v.alpha;
|
||||
v = v.superview;
|
||||
}
|
||||
return alpha;
|
||||
}
|
||||
|
||||
- (CGPoint)convertPoint:(CGPoint)point toViewOrWindow:(UIView *)view {
|
||||
if (!view) {
|
||||
if ([self isKindOfClass:[UIWindow class]]) {
|
||||
return [((UIWindow *)self) convertPoint:point toWindow:nil];
|
||||
} else {
|
||||
return [self convertPoint:point toView:nil];
|
||||
}
|
||||
}
|
||||
|
||||
UIWindow *from = [self isKindOfClass:[UIWindow class]] ? (id)self : self.window;
|
||||
UIWindow *to = [view isKindOfClass:[UIWindow class]] ? (id)view : view.window;
|
||||
if ((!from || !to) || (from == to)) return [self convertPoint:point toView:view];
|
||||
point = [self convertPoint:point toView:from];
|
||||
point = [to convertPoint:point fromWindow:from];
|
||||
point = [view convertPoint:point fromView:to];
|
||||
return point;
|
||||
}
|
||||
|
||||
- (CGPoint)convertPoint:(CGPoint)point fromViewOrWindow:(UIView *)view {
|
||||
if (!view) {
|
||||
if ([self isKindOfClass:[UIWindow class]]) {
|
||||
return [((UIWindow *)self) convertPoint:point fromWindow:nil];
|
||||
} else {
|
||||
return [self convertPoint:point fromView:nil];
|
||||
}
|
||||
}
|
||||
|
||||
UIWindow *from = [view isKindOfClass:[UIWindow class]] ? (id)view : view.window;
|
||||
UIWindow *to = [self isKindOfClass:[UIWindow class]] ? (id)self : self.window;
|
||||
if ((!from || !to) || (from == to)) return [self convertPoint:point fromView:view];
|
||||
point = [from convertPoint:point fromView:view];
|
||||
point = [to convertPoint:point fromWindow:from];
|
||||
point = [self convertPoint:point fromView:to];
|
||||
return point;
|
||||
}
|
||||
|
||||
- (CGRect)convertRect:(CGRect)rect toViewOrWindow:(UIView *)view {
|
||||
if (!view) {
|
||||
if ([self isKindOfClass:[UIWindow class]]) {
|
||||
return [((UIWindow *)self) convertRect:rect toWindow:nil];
|
||||
} else {
|
||||
return [self convertRect:rect toView:nil];
|
||||
}
|
||||
}
|
||||
|
||||
UIWindow *from = [self isKindOfClass:[UIWindow class]] ? (id)self : self.window;
|
||||
UIWindow *to = [view isKindOfClass:[UIWindow class]] ? (id)view : view.window;
|
||||
if (!from || !to) return [self convertRect:rect toView:view];
|
||||
if (from == to) return [self convertRect:rect toView:view];
|
||||
rect = [self convertRect:rect toView:from];
|
||||
rect = [to convertRect:rect fromWindow:from];
|
||||
rect = [view convertRect:rect fromView:to];
|
||||
return rect;
|
||||
}
|
||||
|
||||
- (CGRect)convertRect:(CGRect)rect fromViewOrWindow:(UIView *)view {
|
||||
if (!view) {
|
||||
if ([self isKindOfClass:[UIWindow class]]) {
|
||||
return [((UIWindow *)self) convertRect:rect fromWindow:nil];
|
||||
} else {
|
||||
return [self convertRect:rect fromView:nil];
|
||||
}
|
||||
}
|
||||
|
||||
UIWindow *from = [view isKindOfClass:[UIWindow class]] ? (id)view : view.window;
|
||||
UIWindow *to = [self isKindOfClass:[UIWindow class]] ? (id)self : self.window;
|
||||
if ((!from || !to) || (from == to)) return [self convertRect:rect fromView:view];
|
||||
rect = [from convertRect:rect fromView:view];
|
||||
rect = [to convertRect:rect fromWindow:from];
|
||||
rect = [self convertRect:rect fromView:to];
|
||||
return rect;
|
||||
}
|
||||
|
||||
- (CGFloat)left {
|
||||
return self.frame.origin.x;
|
||||
}
|
||||
|
||||
- (void)setLeft:(CGFloat)x {
|
||||
CGRect frame = self.frame;
|
||||
frame.origin.x = x;
|
||||
self.frame = frame;
|
||||
}
|
||||
|
||||
- (CGFloat)top {
|
||||
return self.frame.origin.y;
|
||||
}
|
||||
|
||||
- (void)setTop:(CGFloat)y {
|
||||
CGRect frame = self.frame;
|
||||
frame.origin.y = y;
|
||||
self.frame = frame;
|
||||
}
|
||||
|
||||
- (CGFloat)right {
|
||||
return self.frame.origin.x + self.frame.size.width;
|
||||
}
|
||||
|
||||
- (void)setRight:(CGFloat)right {
|
||||
CGRect frame = self.frame;
|
||||
frame.origin.x = right - frame.size.width;
|
||||
self.frame = frame;
|
||||
}
|
||||
|
||||
- (CGFloat)bottom {
|
||||
return self.frame.origin.y + self.frame.size.height;
|
||||
}
|
||||
|
||||
- (void)setBottom:(CGFloat)bottom {
|
||||
CGRect frame = self.frame;
|
||||
frame.origin.y = bottom - frame.size.height;
|
||||
self.frame = frame;
|
||||
}
|
||||
|
||||
- (CGFloat)width {
|
||||
return self.frame.size.width;
|
||||
}
|
||||
|
||||
- (void)setWidth:(CGFloat)width {
|
||||
CGRect frame = self.frame;
|
||||
frame.size.width = width;
|
||||
self.frame = frame;
|
||||
}
|
||||
|
||||
- (CGFloat)height {
|
||||
return self.frame.size.height;
|
||||
}
|
||||
|
||||
- (void)setHeight:(CGFloat)height {
|
||||
CGRect frame = self.frame;
|
||||
frame.size.height = height;
|
||||
self.frame = frame;
|
||||
}
|
||||
|
||||
- (CGFloat)centerX {
|
||||
return self.center.x;
|
||||
}
|
||||
|
||||
- (void)setCenterX:(CGFloat)centerX {
|
||||
self.center = CGPointMake(centerX, self.center.y);
|
||||
}
|
||||
|
||||
- (CGFloat)centerY {
|
||||
return self.center.y;
|
||||
}
|
||||
|
||||
- (void)setCenterY:(CGFloat)centerY {
|
||||
self.center = CGPointMake(self.center.x, centerY);
|
||||
}
|
||||
|
||||
- (CGPoint)origin {
|
||||
return self.frame.origin;
|
||||
}
|
||||
|
||||
- (void)setOrigin:(CGPoint)origin {
|
||||
CGRect frame = self.frame;
|
||||
frame.origin = origin;
|
||||
self.frame = frame;
|
||||
}
|
||||
|
||||
- (CGSize)size {
|
||||
return self.frame.size;
|
||||
}
|
||||
|
||||
- (void)setSize:(CGSize)size {
|
||||
CGRect frame = self.frame;
|
||||
frame.size = size;
|
||||
self.frame = frame;
|
||||
}
|
||||
|
||||
@end
|
||||
81
Pods/YYCategories/YYCategories/YYCategories.h
generated
Normal file
81
Pods/YYCategories/YYCategories/YYCategories.h
generated
Normal file
@@ -0,0 +1,81 @@
|
||||
//
|
||||
// YYCategories.h
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 13/3/29.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#if __has_include(<YYCategories/YYCategories.h>)
|
||||
FOUNDATION_EXPORT double YYCategoriesVersionNumber;
|
||||
FOUNDATION_EXPORT const unsigned char YYCategoriesVersionString[];
|
||||
#import <YYCategories/YYCategoriesMacro.h>
|
||||
#import <YYCategories/NSObject+YYAdd.h>
|
||||
#import <YYCategories/NSObject+YYAddForKVO.h>
|
||||
#import <YYCategories/NSObject+YYAddForARC.h>
|
||||
#import <YYCategories/NSData+YYAdd.h>
|
||||
#import <YYCategories/NSString+YYAdd.h>
|
||||
#import <YYCategories/NSArray+YYAdd.h>
|
||||
#import <YYCategories/NSDictionary+YYAdd.h>
|
||||
#import <YYCategories/NSDate+YYAdd.h>
|
||||
#import <YYCategories/NSNumber+YYAdd.h>
|
||||
#import <YYCategories/NSNotificationCenter+YYAdd.h>
|
||||
#import <YYCategories/NSKeyedUnarchiver+YYAdd.h>
|
||||
#import <YYCategories/NSTimer+YYAdd.h>
|
||||
#import <YYCategories/NSBundle+YYAdd.h>
|
||||
#import <YYCategories/NSThread+YYAdd.h>
|
||||
#import <YYCategories/UIColor+YYAdd.h>
|
||||
#import <YYCategories/UIImage+YYAdd.h>
|
||||
#import <YYCategories/UIControl+YYAdd.h>
|
||||
#import <YYCategories/UIBarButtonItem+YYAdd.h>
|
||||
#import <YYCategories/UIGestureRecognizer+YYAdd.h>
|
||||
#import <YYCategories/UIView+YYAdd.h>
|
||||
#import <YYCategories/UIScrollView+YYAdd.h>
|
||||
#import <YYCategories/UITableView+YYAdd.h>
|
||||
#import <YYCategories/UITextField+YYAdd.h>
|
||||
#import <YYCategories/UIScreen+YYAdd.h>
|
||||
#import <YYCategories/UIDevice+YYAdd.h>
|
||||
#import <YYCategories/UIApplication+YYAdd.h>
|
||||
#import <YYCategories/UIFont+YYAdd.h>
|
||||
#import <YYCategories/UIBezierPath+YYAdd.h>
|
||||
#import <YYCategories/CALayer+YYAdd.h>
|
||||
#import <YYCategories/YYCGUtilities.h>
|
||||
#else
|
||||
#import "YYCategoriesMacro.h"
|
||||
#import "NSObject+YYAdd.h"
|
||||
#import "NSObject+YYAddForKVO.h"
|
||||
#import "NSObject+YYAddForARC.h"
|
||||
#import "NSData+YYAdd.h"
|
||||
#import "NSString+YYAdd.h"
|
||||
#import "NSArray+YYAdd.h"
|
||||
#import "NSDictionary+YYAdd.h"
|
||||
#import "NSDate+YYAdd.h"
|
||||
#import "NSNumber+YYAdd.h"
|
||||
#import "NSNotificationCenter+YYAdd.h"
|
||||
#import "NSKeyedUnarchiver+YYAdd.h"
|
||||
#import "NSTimer+YYAdd.h"
|
||||
#import "NSBundle+YYAdd.h"
|
||||
#import "NSThread+YYAdd.h"
|
||||
#import "UIColor+YYAdd.h"
|
||||
#import "UIImage+YYAdd.h"
|
||||
#import "UIControl+YYAdd.h"
|
||||
#import "UIBarButtonItem+YYAdd.h"
|
||||
#import "UIGestureRecognizer+YYAdd.h"
|
||||
#import "UIView+YYAdd.h"
|
||||
#import "UIScrollView+YYAdd.h"
|
||||
#import "UITableView+YYAdd.h"
|
||||
#import "UITextField+YYAdd.h"
|
||||
#import "UIScreen+YYAdd.h"
|
||||
#import "UIDevice+YYAdd.h"
|
||||
#import "UIApplication+YYAdd.h"
|
||||
#import "UIFont+YYAdd.h"
|
||||
#import "UIBezierPath+YYAdd.h"
|
||||
#import "CALayer+YYAdd.h"
|
||||
#import "YYCGUtilities.h"
|
||||
#endif
|
||||
|
||||
337
Pods/YYCategories/YYCategories/YYCategoriesMacro.h
generated
Normal file
337
Pods/YYCategories/YYCategories/YYCategoriesMacro.h
generated
Normal file
@@ -0,0 +1,337 @@
|
||||
//
|
||||
// YYCategoriesMacro.h
|
||||
// YYCategories <https://github.com/ibireme/YYCategories>
|
||||
//
|
||||
// Created by ibireme on 13/3/29.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <sys/time.h>
|
||||
#import <pthread.h>
|
||||
|
||||
#ifndef YYCategoriesMacro_h
|
||||
#define YYCategoriesMacro_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define YY_EXTERN_C_BEGIN extern "C" {
|
||||
#define YY_EXTERN_C_END }
|
||||
#else
|
||||
#define YY_EXTERN_C_BEGIN
|
||||
#define YY_EXTERN_C_END
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
YY_EXTERN_C_BEGIN
|
||||
|
||||
#ifndef YY_CLAMP // return the clamped value
|
||||
#define YY_CLAMP(_x_, _low_, _high_) (((_x_) > (_high_)) ? (_high_) : (((_x_) < (_low_)) ? (_low_) : (_x_)))
|
||||
#endif
|
||||
|
||||
#ifndef YY_SWAP // swap two value
|
||||
#define YY_SWAP(_a_, _b_) do { __typeof__(_a_) _tmp_ = (_a_); (_a_) = (_b_); (_b_) = _tmp_; } while (0)
|
||||
#endif
|
||||
|
||||
|
||||
#define YYAssertNil(condition, description, ...) NSAssert(!(condition), (description), ##__VA_ARGS__)
|
||||
#define YYCAssertNil(condition, description, ...) NSCAssert(!(condition), (description), ##__VA_ARGS__)
|
||||
|
||||
#define YYAssertNotNil(condition, description, ...) NSAssert((condition), (description), ##__VA_ARGS__)
|
||||
#define YYCAssertNotNil(condition, description, ...) NSCAssert((condition), (description), ##__VA_ARGS__)
|
||||
|
||||
#define YYAssertMainThread() NSAssert([NSThread isMainThread], @"This method must be called on the main thread")
|
||||
#define YYCAssertMainThread() NSCAssert([NSThread isMainThread], @"This method must be called on the main thread")
|
||||
|
||||
|
||||
/**
|
||||
Add this macro before each category implementation, so we don't have to use
|
||||
-all_load or -force_load to load object files from static libraries that only
|
||||
contain categories and no classes.
|
||||
More info: http://developer.apple.com/library/mac/#qa/qa2006/qa1490.html .
|
||||
*******************************************************************************
|
||||
Example:
|
||||
YYSYNTH_DUMMY_CLASS(NSString_YYAdd)
|
||||
*/
|
||||
#ifndef YYSYNTH_DUMMY_CLASS
|
||||
#define YYSYNTH_DUMMY_CLASS(_name_) \
|
||||
@interface YYSYNTH_DUMMY_CLASS_ ## _name_ : NSObject @end \
|
||||
@implementation YYSYNTH_DUMMY_CLASS_ ## _name_ @end
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
Synthsize a dynamic object property in @implementation scope.
|
||||
It allows us to add custom properties to existing classes in categories.
|
||||
|
||||
@param association ASSIGN / RETAIN / COPY / RETAIN_NONATOMIC / COPY_NONATOMIC
|
||||
@warning #import <objc/runtime.h>
|
||||
*******************************************************************************
|
||||
Example:
|
||||
@interface NSObject (MyAdd)
|
||||
@property (nonatomic, retain) UIColor *myColor;
|
||||
@end
|
||||
|
||||
#import <objc/runtime.h>
|
||||
@implementation NSObject (MyAdd)
|
||||
YYSYNTH_DYNAMIC_PROPERTY_OBJECT(myColor, setMyColor, RETAIN, UIColor *)
|
||||
@end
|
||||
*/
|
||||
#ifndef YYSYNTH_DYNAMIC_PROPERTY_OBJECT
|
||||
#define YYSYNTH_DYNAMIC_PROPERTY_OBJECT(_getter_, _setter_, _association_, _type_) \
|
||||
- (void)_setter_ : (_type_)object { \
|
||||
[self willChangeValueForKey:@#_getter_]; \
|
||||
objc_setAssociatedObject(self, _cmd, object, OBJC_ASSOCIATION_ ## _association_); \
|
||||
[self didChangeValueForKey:@#_getter_]; \
|
||||
} \
|
||||
- (_type_)_getter_ { \
|
||||
return objc_getAssociatedObject(self, @selector(_setter_:)); \
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
Synthsize a dynamic c type property in @implementation scope.
|
||||
It allows us to add custom properties to existing classes in categories.
|
||||
|
||||
@warning #import <objc/runtime.h>
|
||||
*******************************************************************************
|
||||
Example:
|
||||
@interface NSObject (MyAdd)
|
||||
@property (nonatomic, retain) CGPoint myPoint;
|
||||
@end
|
||||
|
||||
#import <objc/runtime.h>
|
||||
@implementation NSObject (MyAdd)
|
||||
YYSYNTH_DYNAMIC_PROPERTY_CTYPE(myPoint, setMyPoint, CGPoint)
|
||||
@end
|
||||
*/
|
||||
#ifndef YYSYNTH_DYNAMIC_PROPERTY_CTYPE
|
||||
#define YYSYNTH_DYNAMIC_PROPERTY_CTYPE(_getter_, _setter_, _type_) \
|
||||
- (void)_setter_ : (_type_)object { \
|
||||
[self willChangeValueForKey:@#_getter_]; \
|
||||
NSValue *value = [NSValue value:&object withObjCType:@encode(_type_)]; \
|
||||
objc_setAssociatedObject(self, _cmd, value, OBJC_ASSOCIATION_RETAIN); \
|
||||
[self didChangeValueForKey:@#_getter_]; \
|
||||
} \
|
||||
- (type)_getter_ { \
|
||||
_type_ cValue = { 0 }; \
|
||||
NSValue *value = objc_getAssociatedObject(self, @selector(_setter_:)); \
|
||||
[value getValue:&cValue]; \
|
||||
return cValue; \
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
Synthsize a weak or strong reference.
|
||||
|
||||
Example:
|
||||
@weakify(self)
|
||||
[self doSomething^{
|
||||
@strongify(self)
|
||||
if (!self) return;
|
||||
...
|
||||
}];
|
||||
|
||||
*/
|
||||
#ifndef weakify
|
||||
#if DEBUG
|
||||
#if __has_feature(objc_arc)
|
||||
#define weakify(object) autoreleasepool{} __weak __typeof__(object) weak##_##object = object;
|
||||
#else
|
||||
#define weakify(object) autoreleasepool{} __block __typeof__(object) block##_##object = object;
|
||||
#endif
|
||||
#else
|
||||
#if __has_feature(objc_arc)
|
||||
#define weakify(object) try{} @finally{} {} __weak __typeof__(object) weak##_##object = object;
|
||||
#else
|
||||
#define weakify(object) try{} @finally{} {} __block __typeof__(object) block##_##object = object;
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef strongify
|
||||
#if DEBUG
|
||||
#if __has_feature(objc_arc)
|
||||
#define strongify(object) autoreleasepool{} __typeof__(object) object = weak##_##object;
|
||||
#else
|
||||
#define strongify(object) autoreleasepool{} __typeof__(object) object = block##_##object;
|
||||
#endif
|
||||
#else
|
||||
#if __has_feature(objc_arc)
|
||||
#define strongify(object) try{} @finally{} __typeof__(object) object = weak##_##object;
|
||||
#else
|
||||
#define strongify(object) try{} @finally{} __typeof__(object) object = block##_##object;
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
Convert CFRange to NSRange
|
||||
@param range CFRange @return NSRange
|
||||
*/
|
||||
static inline NSRange YYNSRangeFromCFRange(CFRange range) {
|
||||
return NSMakeRange(range.location, range.length);
|
||||
}
|
||||
|
||||
/**
|
||||
Convert NSRange to CFRange
|
||||
@param range NSRange @return CFRange
|
||||
*/
|
||||
static inline CFRange YYCFRangeFromNSRange(NSRange range) {
|
||||
return CFRangeMake(range.location, range.length);
|
||||
}
|
||||
|
||||
/**
|
||||
Same as CFAutorelease(), compatible for iOS6
|
||||
@param arg CFObject @return same as input
|
||||
*/
|
||||
static inline CFTypeRef YYCFAutorelease(CFTypeRef CF_RELEASES_ARGUMENT arg) {
|
||||
if (((long)CFAutorelease + 1) != 1) {
|
||||
return CFAutorelease(arg);
|
||||
} else {
|
||||
id __autoreleasing obj = CFBridgingRelease(arg);
|
||||
return (__bridge CFTypeRef)obj;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Profile time cost.
|
||||
@param ^block code to benchmark
|
||||
@param ^complete code time cost (millisecond)
|
||||
|
||||
Usage:
|
||||
YYBenchmark(^{
|
||||
// code
|
||||
}, ^(double ms) {
|
||||
NSLog("time cost: %.2f ms",ms);
|
||||
});
|
||||
|
||||
*/
|
||||
static inline void YYBenchmark(void (^block)(void), void (^complete)(double ms)) {
|
||||
// <QuartzCore/QuartzCore.h> version
|
||||
/*
|
||||
extern double CACurrentMediaTime (void);
|
||||
double begin, end, ms;
|
||||
begin = CACurrentMediaTime();
|
||||
block();
|
||||
end = CACurrentMediaTime();
|
||||
ms = (end - begin) * 1000.0;
|
||||
complete(ms);
|
||||
*/
|
||||
|
||||
// <sys/time.h> version
|
||||
struct timeval t0, t1;
|
||||
gettimeofday(&t0, NULL);
|
||||
block();
|
||||
gettimeofday(&t1, NULL);
|
||||
double ms = (double)(t1.tv_sec - t0.tv_sec) * 1e3 + (double)(t1.tv_usec - t0.tv_usec) * 1e-3;
|
||||
complete(ms);
|
||||
}
|
||||
|
||||
static inline NSDate *_YYCompileTime(const char *data, const char *time) {
|
||||
NSString *timeStr = [NSString stringWithFormat:@"%s %s",data,time];
|
||||
NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];
|
||||
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
|
||||
[formatter setDateFormat:@"MMM dd yyyy HH:mm:ss"];
|
||||
[formatter setLocale:locale];
|
||||
return [formatter dateFromString:timeStr];
|
||||
}
|
||||
|
||||
/**
|
||||
Get compile timestamp.
|
||||
@return A new date object set to the compile date and time.
|
||||
*/
|
||||
#ifndef YYCompileTime
|
||||
// use macro to avoid compile warning when use pch file
|
||||
#define YYCompileTime() _YYCompileTime(__DATE__, __TIME__)
|
||||
#endif
|
||||
|
||||
/**
|
||||
Returns a dispatch_time delay from now.
|
||||
*/
|
||||
static inline dispatch_time_t dispatch_time_delay(NSTimeInterval second) {
|
||||
return dispatch_time(DISPATCH_TIME_NOW, (int64_t)(second * NSEC_PER_SEC));
|
||||
}
|
||||
|
||||
/**
|
||||
Returns a dispatch_wall_time delay from now.
|
||||
*/
|
||||
static inline dispatch_time_t dispatch_walltime_delay(NSTimeInterval second) {
|
||||
return dispatch_walltime(DISPATCH_TIME_NOW, (int64_t)(second * NSEC_PER_SEC));
|
||||
}
|
||||
|
||||
/**
|
||||
Returns a dispatch_wall_time from NSDate.
|
||||
*/
|
||||
static inline dispatch_time_t dispatch_walltime_date(NSDate *date) {
|
||||
NSTimeInterval interval;
|
||||
double second, subsecond;
|
||||
struct timespec time;
|
||||
dispatch_time_t milestone;
|
||||
|
||||
interval = [date timeIntervalSince1970];
|
||||
subsecond = modf(interval, &second);
|
||||
time.tv_sec = second;
|
||||
time.tv_nsec = subsecond * NSEC_PER_SEC;
|
||||
milestone = dispatch_walltime(&time, 0);
|
||||
return milestone;
|
||||
}
|
||||
|
||||
/**
|
||||
Whether in main queue/thread.
|
||||
*/
|
||||
static inline bool dispatch_is_main_queue() {
|
||||
return pthread_main_np() != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
Submits a block for asynchronous execution on a main queue and returns immediately.
|
||||
*/
|
||||
static inline void dispatch_async_on_main_queue(void (^block)()) {
|
||||
if (pthread_main_np()) {
|
||||
block();
|
||||
} else {
|
||||
dispatch_async(dispatch_get_main_queue(), block);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Submits a block for execution on a main queue and waits until the block completes.
|
||||
*/
|
||||
static inline void dispatch_sync_on_main_queue(void (^block)()) {
|
||||
if (pthread_main_np()) {
|
||||
block();
|
||||
} else {
|
||||
dispatch_sync(dispatch_get_main_queue(), block);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Initialize a pthread mutex.
|
||||
*/
|
||||
static inline void pthread_mutex_init_recursive(pthread_mutex_t *mutex, bool recursive) {
|
||||
#define YYMUTEX_ASSERT_ON_ERROR(x_) do { \
|
||||
__unused volatile int res = (x_); \
|
||||
assert(res == 0); \
|
||||
} while (0)
|
||||
assert(mutex != NULL);
|
||||
if (!recursive) {
|
||||
YYMUTEX_ASSERT_ON_ERROR(pthread_mutex_init(mutex, NULL));
|
||||
} else {
|
||||
pthread_mutexattr_t attr;
|
||||
YYMUTEX_ASSERT_ON_ERROR(pthread_mutexattr_init (&attr));
|
||||
YYMUTEX_ASSERT_ON_ERROR(pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE));
|
||||
YYMUTEX_ASSERT_ON_ERROR(pthread_mutex_init (mutex, &attr));
|
||||
YYMUTEX_ASSERT_ON_ERROR(pthread_mutexattr_destroy (&attr));
|
||||
}
|
||||
#undef YYMUTEX_ASSERT_ON_ERROR
|
||||
}
|
||||
|
||||
|
||||
YY_EXTERN_C_END
|
||||
#endif
|
||||
Reference in New Issue
Block a user