Commit 5b013e70 authored by 汪洋's avatar 汪洋

Merge branch 'lz/master'

parents 6e648f03 c43e2c05
......@@ -35,4 +35,4 @@ Carthage/Build
# Note: if you ignore the Pods directory, make sure to uncomment
# `pod install` in .travis.yml
#
# Pods/
Pods/
......@@ -540,12 +540,13 @@
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "GMShareSDK/GMShareSDK-Prefix.pch";
INFOPLIST_FILE = "GMShareSDK/GMShareSDK-Info.plist";
LD_MAP_FILE_PATH = "$(TARGET_TEMP_DIR)/$(PRODUCT_NAME)-LinkMap-$(CURRENT_VARIANT)-$(CURRENT_ARCH).txt";
MODULE_NAME = ExampleApp;
PODS_ROOT = "$(inherited)";
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.0;
VALID_ARCHS = "armv7s armv7 arm64e arm64";
VALID_ARCHS = "arm64 arm64e armv7 armv7s";
WRAPPER_EXTENSION = app;
};
name = Debug;
......@@ -564,7 +565,7 @@
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.0;
VALID_ARCHS = "armv7s armv7 arm64e arm64";
VALID_ARCHS = "arm64 arm64e armv7 armv7s";
WRAPPER_EXTENSION = app;
};
name = Release;
......
use_frameworks!
inhibit_all_warnings!
platform :ios, '8.0'
#require 'pry'
......
......@@ -50,7 +50,7 @@ PODS:
- GMPhobos (1.3.5):
- GMCache
- GMKit
- GMShareSDK (0.1.9):
- GMShareSDK (0.2.0):
- DouyinOpenSDK
- GMFoundation
- GMJSONModel
......@@ -104,7 +104,7 @@ SPEC CHECKSUMS:
GMJSONModel: 5e81a98de668e9f93cf6ff77869f77b0d1a806be
GMKit: 09fe863069d9750c89fae2939770b08fc74b9027
GMPhobos: 1e2d68c456b69bf156276d7242877498107474db
GMShareSDK: 16b9de277b1d14e017a7e344b17d04cdb0f0d037
GMShareSDK: 58229b5de5736f0ae8d5a07f7e28e02448f1d7c0
Masonry: 678fab65091a9290e40e2832a55e7ab731aad201
MBProgressHUD: 1569cf7ace17a8bac47aabfbb8580a49690386d1
SDWebImage: 4d5c027c935438f341ed33dbac53ff9f479922ca
......@@ -113,6 +113,6 @@ SPEC CHECKSUMS:
WechatOpenSDK: 368ae03b72ee3ea1328c4f11326fbb5d2721d118
WeiboSDK: acb067053668102cf07d01aa7604350162c2e466
PODFILE CHECKSUM: 7d810478599596071b1f4191c35ed3266ebed840
PODFILE CHECKSUM: ba7f4c5e498b68f2251e4a080f9df903ccc82b1f
COCOAPODS: 1.8.4
COCOAPODS: 1.9.0
//
// DouyinOpenSDKApi.h
// 所有Api接口
//
// Created by 抖音短视频 on 18/9/2017.
// Copyright (c) 2018年 抖音短视频. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "DouyinOpenSDKApiObject.h"
NS_ASSUME_NONNULL_BEGIN
@protocol DouyinOpenSDKApiDelegate <NSObject>
@optional
/**
接收并处理来自抖音短视频的请求消息
@param req 抖音短视频主动发送的具体请求内容
*/
- (void)didReceiveRequest:(DouyinOpenSDKBaseReq * _Nonnull)req;
/**
第三方应用程序通过sendReq向抖音短视频发送请求后,收到来自抖音短视频的响应
@param resp 抖音短视频回应的具体内容
*/
- (void)didReceiveResponse:(DouyinOpenSDKBaseResp * _Nonnull)resp;
@end
@protocol DouyinOpenSDKLogDelegate <NSObject>
/**
接收来自抖音短视频的日志,可供调试用
@param log 日志内容
*/
- (void)onLog:(NSString *)log;
@end
@interface DouyinOpenSDKApi : NSObject
/**
设置SDK日志代理,可供调试
同时仅允许存在一个日志代理,每次调用将覆盖之前的delegate
SDK会弱引用这个logDelegate
@param logDelegate 日志代理
*/
+ (void)registerLogDelegate:(id<DouyinOpenSDKLogDelegate>)logDelegate;
/**
清除SDK日志代理,停止调试
会清除之前设置的日志代理
*/
+ (void)unregisterLogDelegate;
/**
向抖音短视频注册第三方应用
需要在每次启动第三方应用程序时调用。第一次调用后,将添加到头条的可用应用列表中
@attention 必须在主线程执行
@param appId 第三方应用在抖音短视频开放平台申请的appId(appId也称ClientKey)
@return 成功返回YES,否则返回NO
*/
+ (BOOL)registerAppId:(NSString * _Nonnull)appId;
/**
处理抖音短视频通过URL启动第三方应用时传递的数据,需在[application:openURL:sourceApplication:annotation:]或者[application:handleOpenURL:]中调用
@attention 必须在主线程执行
@param url 启动第三方应用的URL
@param delegate DouyinOpenSDKApiDelegate对象,用来接收抖音短视频触发的消息
@return 成功处理返回YES,否则返回NO
*/
+ (BOOL)handleOpenURL:(NSURL * _Nonnull)url
delegate:(id<DouyinOpenSDKApiDelegate> _Nullable)delegate;
/**
获取当前SDK的版本
@return 返回SDK当前版本号
*/
+ (nonnull NSString *)currentVersion;
/**
判断用户是否安装了抖音短视频
@return 安装返回YES,否则返回NO
*/
+ (BOOL)isAppInstalled;
/**
判断当前抖音短视频版本是否支持授权登录
@return 支持返回YES,否则返回NO
*/
+ (BOOL)isAppSupportAuthorization;
/**
判断当前TOREPLACEPRODUCTNAME版本是否支持分享
@return 支持返回YES,否则返回NO
*/
+ (BOOL)isAppSupportShare;
/**
获取抖音短视频在iTunes上的下载地址
@return 返回抖音短视频的安装地址
*/
+ (nonnull NSString *)getAppiTunesUrl;
/**
由第三方APP给抖音短视频发送请求,抖音短视频处理完成后通过didReceiveResponse:回调
@attention 必须运行在主线程
@param req 发送给抖音短视频的请求
@return 发送请求成功返回YES,否则返回NO并终止流程
*/
+ (BOOL)sendReq:(DouyinOpenSDKBaseReq * _Nonnull)req;
/*! @brief 发送Auth请求,唤起抖音短视频客户端,若用户没安装抖音短视频则唤起web授权页,等待抖音短视频返回response
*
* 函数调用后,会切换到抖音短视频的界面。第三方应用程序等待抖音短视频返回response
* @param req 具体的发送请求,在调用函数后,请自己释放。
* @param viewController 当前界面对象,用于展示抖音短视频的web授权页。
* @param delegate DouyinOpenSDKApiDelegate对象,用来接收抖音短视频触发的消息。
* @return 成功返回YES,失败返回NO。
*/
+ (BOOL)sendAuthReq:(DouyinOpenSDKSendAuthReq*)req viewController:(UIViewController*)viewController delegate:(id<DouyinOpenSDKApiDelegate>)delegate;
/**
进行web授权页预加载缓存,针对web页展示慢做的优化,使授权请求中展示web页更快
若无需求可以不调用
@param req 预加载的授权请求
*/
+ (void)preloadWebAuthWithReq:(DouyinOpenSDKSendAuthReq *)req;
/**
清理web授权页预加载缓存
若无需求可以不调用
*/
+ (void)clearPreloadWebAuthCache;
/**
抖音短视频给第三方APP发送请求后,第三方APP通过didReceiveRequest:接收到请求后,第三方APP使用SendResp:给抖音短视频回送响应
@attention 必须运行在主线程
@param resp 回送给抖音短视频的响应
@return 发送请求成功返回YES,否则返回NO并终止流程
*/
+ (BOOL)sendResp:(DouyinOpenSDKBaseResp * _Nonnull)resp;
@end
NS_ASSUME_NONNULL_END
//
// DouyinOpenSDKApiObject.h
// Api对象,包含所有接口和对象数据定义
//
// Created by 抖音短视频 on 18/9/2017.
// Copyright (c) 2018年 抖音短视频. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
typedef NS_ENUM(NSInteger, DouyinOpenSDKErrorCode) {
DouyinOpenSDKSuccess = 0, /** 成功 */
DouyinOpenSDKErrorCodeCommon = -1, /** 通用错误类型 <包括网络错误> */
DouyinOpenSDKErrorCodeUserCanceled = -2, /** 用户手动取消 */
DouyinOpenSDKErrorCodeSendFailed = -3, /** 发送失败 */
DouyinOpenSDKErrorCodeAuthDenied = -4, /** 权限错误 */
DouyinOpenSDKErrorCodeUnsupported = -5, /** 不支持 */
};
#pragma mark - DouyinOpenSDKBaseReq
@interface DouyinOpenSDKBaseReq : NSObject
@end
#pragma mark - DouyinOpenSDKSendAuthReq
/**
第三方程序向抖音短视频请求认证授权的消息结构
第三方程序向抖音短视频发送认证用户的某些权限的请求,抖音短视频处理完成后会向第三方回送一个处理结果。
*/
@interface DouyinOpenSDKSendAuthReq : DouyinOpenSDKBaseReq
/**
第三方应用程序向抖音短视频申请的必需权限类型,最终在抖音短视频App授权完成后根据实际授权结果返回给第三方应用;
例如 [NSOrderedSet orderedSetWithObjects:@"user_info", ..., nil]
*/
@property (nonatomic, strong, nullable) NSOrderedSet<NSString *> *permissions;
/**
第三方应用程序向抖音短视频申请的附加权限类型,用户可以勾选是否给予这部分权限,最终在抖音短视频App授权完成后根据实际授权结果返回给第三方应用;
@key permission 权限
@key defaultChecked 初始勾选状态,@"1"表示勾选,@"0"表示未勾选
例如 [NSOrderedSet orderedSetWithObjects:@{@"permission":@"user_info",@"defaultChecked":@"0"}, ..., nil]
*/
@property (nonatomic, strong, nullable) NSOrderedSet<NSDictionary<NSString *,NSString *> *> *additionalPermissions;
/**
第三方应用程序用来标识请求的唯一性,最后跳转回第三方程序时由抖音短视频App回传
*/
@property (nonatomic, copy, nullable) NSString *state;
@end
#pragma mark - DouyinOpenSDKBaseResp
@interface DouyinOpenSDKBaseResp : NSObject
/**
错误码
*/
@property (nonatomic, assign) DouyinOpenSDKErrorCode errCode;
/**
错误描述
*/
@property (nonatomic, copy, nullable) NSString *errString;
@end
#pragma mark - DouyinOpenSDKSendAuthResp
/**
抖音短视频处理完成第三方应用的认证与权限申请后,回送给第三方应用的处理结果。
第三方程序向抖音短视频申请权限认证,需要调用DouyinOpenSDKApi的[sendAuthReq:viewController:delegate:]函数,向抖音短视频发送DouyinOpenSDKSendAuthReq的请求,抖音短视频处理完成后会向第三方回送一个DouyinOpenSDKSendAuthResp对象的响应。
*/
@interface DouyinOpenSDKSendAuthResp : DouyinOpenSDKBaseResp
/**
第三方应用向抖音短视频申请某些权限,最终在抖音短视频App授权完成后根据实际授权结果返回给第三方应用
*/
@property (nonatomic, copy, readonly, nullable) NSString *code;
/**
第三方应用程序用来标识请求的唯一性,最后跳转回第三方程序时由抖音短视频回传
*/
@property (nonatomic, copy, readonly, nullable) NSString *state;
/**
抖音短视频用户同意给予第三方应用程序的权限,若授权成功则包括全部必需权限和用户勾选的附加权限;
*/
@property (nonatomic, strong, nullable) NSOrderedSet<NSString *> *grantedPermissions;
@end
#pragma mark - DouyinOpenSDKShareReq
/**
分享捆绑抖音小程序相关信息数据结构
*/
@interface DouyinOpenSDKMPInfo : NSObject
@property (nonatomic, copy) NSString *identifier;
@property (nonatomic, copy, nullable) NSString *title;
@property (nonatomic, copy, nullable) NSString *desc;
@property (nonatomic, copy, nullable) NSString *startPageURL;
+ (DouyinOpenSDKMPInfo *)mpInfoWithIdentifier:(NSString *)identifier
title:(nullable NSString *)title
desc:(nullable NSString *)desc
startPageURL:(nullable NSString *)startPageURL;
@end
typedef NS_ENUM(NSUInteger, DouyinOpenSDKShareMediaType) {
DouyinOpenSDKShareMediaTypeImage = 0, // 对应 PHAssetMediaTypeImage
DouyinOpenSDKShareMediaTypeVideo, // 对应 PHAssetMediaTypeVideo
};
@interface DouyinOpenSDKShareReq : DouyinOpenSDKBaseReq
/**
第三方应用程序向抖音短视频分享的视频或图片在 **相册** 中的中的local identifier,上限为12个,内容须全部为图片,或者全部为视频。
若内容为视频,视频总时长应该大于3s;
图片的宽高比应满足:1/2.2<=宽高比<=2.2;
视频分辨率应满足:1/2.2<=宽高像素比<=2.2;
请三方应用程序自行检查分享的内容是否满足要求;
此处需注意,带品牌logo或品牌水印的视频,会命中抖音的审核逻辑,有比较大的概率导致分享视频推荐降权处理/分享视频下架处理/分享账号被封禁处理,请予以重视;
强烈建议第三方应用自行处理好分享内容中的不合规水印。
*/
@property (nonatomic, strong) NSArray *localIdentifiers;
/**
urlPaths在相册中对应的Media类型,urlPaths里面的必须都是同一种类型
*/
@property (nonatomic, assign) DouyinOpenSDKShareMediaType mediaType;
/**
第三方应用程序用来标识请求的唯一性,最后跳转回第三方程序时由抖音短视频App回传
*/
@property (nonatomic, copy, nullable) NSString *state;
/**
对应视频的 #话题 功能,需要额外申请权限,字符长度不能超过 35
*/
@property (nonatomic, copy, nullable) NSString *hashtag;
/**
对应的小程序信息
*/
@property (nonatomic, strong, nullable) DouyinOpenSDKMPInfo *mpInfo;
@end
#pragma mark - DouyinOpenSDKShareResp
/**
抖音短视频完成视频分享处理后,给第三方应用的处理结果。
*/
@interface DouyinOpenSDKShareResp : DouyinOpenSDKBaseResp
/**
第三方应用程序用来标识请求的唯一性,最后跳转回第三方程序时由抖音短视频回传
*/
@property (nonatomic, copy, readonly, nullable) NSString *state;
@end
NS_ASSUME_NONNULL_END
//
// GMCache.h
// Gengmei
//
// Created by Thierry on 1/5/15.
// Copyright (c) 2015 Wanmeichuangyi. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <TMCache/TMCache.h>
@interface GMCache : NSObject
#pragma mark - 异步磁盘读写操作
/*** @brief 由对应的键获取对应的缓存数据*/
+ (void)storeObjectAtDiskWithkey:(NSString *)key
object:(id <NSCoding>)object
block:(TMDiskCacheObjectBlock)block;
/*** @brief 给特定的键,标记缓存数据并缓存*/
+ (void)fetchObjectAtDiskWithkey:(NSString *)key
block:(TMDiskCacheObjectBlock)block;
/*** @brief 删除特定的键,对应的缓存数据*/
+ (void)removeObjectAtDiskWithkey:(NSString *)key
block:(TMDiskCacheObjectBlock)block;
/*** @brief 清空所有的缓存数据*/
+ (void)removeAllObjectsAtDiskWithBlock:(TMDiskCacheBlock)block;
#pragma mark - 同步磁盘读写操作
/*** @brief 由对应的键获取对应的缓存数据*/
+ (void)storeObjectAtDiskWithkey:(NSString *)key
object:(id <NSCoding>)object;
/*** @brief 给特定的键,标记缓存数据并缓存*/
+ (id)fetchObjectAtDiskWithkey:(NSString *)key;
/*** @brief 删除特定的键,对应的缓存数据*/
+ (void)removeObjectAtDiskWithkey:(NSString *)key;
/*** @brief 清空所有的缓存数据*/
+ (void)removeAllObjectsAtDisk;
#pragma mark - 异步内存读写操作
/*** @brief 由对应的键获取对应的缓存数据*/
+ (void)storeObjectAtMemoryWithkey:(NSString *)key
object:(id <NSCoding>)object
block:(TMMemoryCacheObjectBlock)block;
/*** @brief 给特定的键,标记缓存数据并缓存*/
+ (void)fetchObjectAtMemoryWithkey:(NSString *)key
block:(TMMemoryCacheObjectBlock)block;
/*** @brief 删除特定的键,对应的缓存数据*/
+ (void)removeObjectAtMemoryWithkey:(NSString *)key
block:(TMMemoryCacheObjectBlock)block;
/*** @brief 清空所有的缓存数据*/
+ (void)removeAllObjectsAtMemoryWithBlock:(TMMemoryCacheBlock)block;
#pragma mark - 同步内存读写操作
/*** @brief 由对应的键获取对应的缓存数据*/
+ (void)storeObjectAtMemoryWithkey:(NSString *)key
object:(id)object;
/*** @brief 给特定的键,标记缓存数据并缓存*/
+ (id)fetchObjectAtMemoryWithkey:(NSString *)key;
/*** @brief 删除特定的键,对应的缓存数据*/
+ (void)removeObjectAtMemoryWithkey:(NSString *)key;
/*** @brief 清空所有的缓存数据*/
+ (void)removeAllObjectsAtMemory;
#pragma mark - 这里将数据缓存到Ducument目录下。异步
+ (void)storeObjectAtDocumentPathWithkey:(NSString *)key
object:(id <NSCoding>)object
block:(TMDiskCacheObjectBlock)block;
+ (void)fetchObjectAtDocumentPathWithkey:(NSString *)key
block:(TMDiskCacheObjectBlock)block;
+ (void)removeObjectAtDocumentPathWithkey:(NSString *)key
block:(TMDiskCacheObjectBlock)block;
+ (void)removeAllObjectsAtDocumentPathWithBlock:(TMDiskCacheBlock)block;
#pragma mark - 这里将数据缓存到Ducument目录下。同步内存读写操作
+ (void)storeObjectAtDocumentPathWithkey:(NSString *)key
object:(id <NSCoding>)object;
+ (id)fetchObjectAtDocumentPathWithkey:(NSString *)key;
+ (void)removeObjectAtDocumentPathWithkey:(NSString *)key;
+ (void)removeAllObjectsAtDocumentPath;
@end
//
// GMCache.m
// Gengmei
//
// Created by Thierry on 1/5/15.
// Copyright (c) 2015 Wanmeichuangyi. All rights reserved.
//
#import "GMCache.h"
@interface WMDocumentCache : TMCache
@end
@implementation GMCache
+ (void)storeObjectAtDiskWithkey:(NSString *)key object:(id <NSCoding>)object block:(TMDiskCacheObjectBlock)block{
NSAssert([GMCache gmCache_isNonEmpty:key], @"key不能为空");
if (![GMCache gmCache_isNonEmpty:key]) {
return;
}
[[TMCache sharedCache].diskCache setObject:object forKey:key block:block];
}
+ (void)fetchObjectAtDiskWithkey:(NSString *)key block:(TMDiskCacheObjectBlock)block{
NSAssert([GMCache gmCache_isNonEmpty:key], @"key不能为空");
if (![GMCache gmCache_isNonEmpty:key]) {
return;
}
[[TMCache sharedCache].diskCache objectForKey:key block:block];
}
+ (void)removeObjectAtDiskWithkey:(NSString *)key block:(TMDiskCacheObjectBlock)block{
NSAssert([GMCache gmCache_isNonEmpty:key], @"key不能为空");
if (![GMCache gmCache_isNonEmpty:key]) {
return;
}
[[TMCache sharedCache].diskCache removeObjectForKey:key block:block];
}
+ (void)removeAllObjectsAtDiskWithBlock:(TMDiskCacheBlock)block{
[[TMCache sharedCache].diskCache removeAllObjects:block];
}
+ (void)storeObjectAtDiskWithkey:(NSString *)key object:(id <NSCoding>)object{
NSAssert([GMCache gmCache_isNonEmpty:key], @"key不能为空");
if (![GMCache gmCache_isNonEmpty:key]) {
return;
}
[[TMCache sharedCache].diskCache setObject:object forKey:key];
}
+ (id)fetchObjectAtDiskWithkey:(NSString *)key{
NSAssert([GMCache gmCache_isNonEmpty:key], @"key不能为空");
if (![GMCache gmCache_isNonEmpty:key]) {
return nil;
}
return [[TMCache sharedCache].diskCache objectForKey:key];
}
+ (void)removeObjectAtDiskWithkey:(NSString *)key{
NSAssert([GMCache gmCache_isNonEmpty:key], @"key不能为空");
if (![GMCache gmCache_isNonEmpty:key]) {
return;
}
[[TMCache sharedCache].diskCache removeObjectForKey:key];
}
+ (void)removeAllObjectsAtDisk{
[[TMCache sharedCache].diskCache removeAllObjects];
}
+ (void)storeObjectAtMemoryWithkey:(NSString *)key object:(id <NSCoding>)object block:(TMMemoryCacheObjectBlock)block{
NSAssert([GMCache gmCache_isNonEmpty:key], @"key不能为空");
if (![GMCache gmCache_isNonEmpty:key]) {
return;
}
[[TMCache sharedCache].memoryCache setObject:object forKey:key block:block];
}
+ (void)fetchObjectAtMemoryWithkey:(NSString *)key block:(TMMemoryCacheObjectBlock)block{
NSAssert([GMCache gmCache_isNonEmpty:key], @"key不能为空");
if (![GMCache gmCache_isNonEmpty:key]) {
return;
}
[[TMCache sharedCache].memoryCache objectForKey:key block:block];
}
+ (void)removeObjectAtMemoryWithkey:(NSString *)key block:(TMMemoryCacheObjectBlock)block{
NSAssert([GMCache gmCache_isNonEmpty:key], @"key不能为空");
if (![GMCache gmCache_isNonEmpty:key]) {
return;
}
[[TMCache sharedCache].memoryCache removeObjectForKey:key block:block];
}
+ (void)removeAllObjectsAtMemoryWithBlock:(TMMemoryCacheBlock)block{
[[TMCache sharedCache].memoryCache removeAllObjects:block];
}
+ (void)storeObjectAtMemoryWithkey:(NSString *)key object:(id)object{
NSAssert([GMCache gmCache_isNonEmpty:key], @"key不能为空");
if (![GMCache gmCache_isNonEmpty:key]) {
return;
}
[[TMCache sharedCache].memoryCache setObject:object forKey:key];
}
+ (id)fetchObjectAtMemoryWithkey:(NSString *)key{
NSAssert([GMCache gmCache_isNonEmpty:key], @"key不能为空");
if (![GMCache gmCache_isNonEmpty:key]) {
return nil;
}
return [[TMCache sharedCache].memoryCache objectForKey:key];
}
+ (void)removeObjectAtMemoryWithkey:(NSString *)key{
NSAssert([GMCache gmCache_isNonEmpty:key], @"key不能为空");
if (![GMCache gmCache_isNonEmpty:key]) {
return;
}
[[TMCache sharedCache].memoryCache removeObjectForKey:key];
}
+ (void)removeAllObjectsAtMemory{
[[TMCache sharedCache].memoryCache removeAllObjects];
}
+ (void)storeObjectAtDocumentPathWithkey:(NSString *)key
object:(id <NSCoding>)object
block:(TMDiskCacheObjectBlock)block{
NSAssert([GMCache gmCache_isNonEmpty:key], @"key不能为空");
if (![GMCache gmCache_isNonEmpty:key]) {
return;
}
[[WMDocumentCache sharedCache].diskCache setObject:object forKey:key block:block];
}
+ (void)fetchObjectAtDocumentPathWithkey:(NSString *)key
block:(TMDiskCacheObjectBlock)block{
NSAssert([GMCache gmCache_isNonEmpty:key], @"key不能为空");
if (![GMCache gmCache_isNonEmpty:key]) {
return;
}
[[WMDocumentCache sharedCache].diskCache objectForKey:key block:block];
}
+ (void)removeObjectAtDocumentPathWithkey:(NSString *)key
block:(TMDiskCacheObjectBlock)block{
NSAssert([GMCache gmCache_isNonEmpty:key], @"key不能为空");
if (![GMCache gmCache_isNonEmpty:key]) {
return;
}
[[WMDocumentCache sharedCache].diskCache removeObjectForKey:key block:block];
}
+ (void)removeAllObjectsAtDocumentPathWithBlock:(TMDiskCacheBlock)block{
[[WMDocumentCache sharedCache].diskCache removeAllObjects:block];
}
+ (void)storeObjectAtDocumentPathWithkey:(NSString *)key
object:(id <NSCoding>)object{
NSAssert([GMCache gmCache_isNonEmpty:key], @"key不能为空");
if (![GMCache gmCache_isNonEmpty:key]) {
return;
}
[[WMDocumentCache sharedCache].diskCache setObject:object forKey:key];
}
+ (id)fetchObjectAtDocumentPathWithkey:(NSString *)key{
NSAssert([GMCache gmCache_isNonEmpty:key], @"key不能为空");
if (![GMCache gmCache_isNonEmpty:key]) {
return nil;
}
return [[WMDocumentCache sharedCache].diskCache objectForKey:key];
}
+ (void)removeObjectAtDocumentPathWithkey:(NSString *)key{
NSAssert([GMCache gmCache_isNonEmpty:key], @"key不能为空");
if (![GMCache gmCache_isNonEmpty:key]) {
return;
}
[[WMDocumentCache sharedCache].diskCache removeObjectForKey:key];
}
+ (void)removeAllObjectsAtDocumentPath{
[[WMDocumentCache sharedCache].diskCache removeAllObjects];
}
+ (BOOL)gmCache_isNonEmpty:(NSString *)key {
NSMutableCharacterSet *emptyStringSet = [[NSMutableCharacterSet alloc] init];
[emptyStringSet formUnionWithCharacterSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]];
[emptyStringSet formUnionWithCharacterSet: [NSCharacterSet characterSetWithCharactersInString: @" "]];
if ([key length] == 0) {
return NO;
}
NSString* str = [key stringByTrimmingCharactersInSet:emptyStringSet];
return [str length] > 0;
}
@end
NSString * const WMCacheSharedName = @"WMCacheShared";
@implementation WMDocumentCache
+ (instancetype)sharedCache{
static id cache;
static dispatch_once_t predicate;
dispatch_once(&predicate, ^{
cache = [[self alloc] initWithName:WMCacheSharedName rootPath:[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]];
});
return cache;
}
@end
Copyright (c) 2016 wangyang <wangyang@wanmeizhensuo.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.
# GMCache
[![CI Status](http://img.shields.io/travis/wangyang/GMCache.svg?style=flat)](https://travis-ci.org/wangyang/GMCache)
[![Version](https://img.shields.io/cocoapods/v/GMCache.svg?style=flat)](http://cocoapods.org/pods/GMCache)
[![License](https://img.shields.io/cocoapods/l/GMCache.svg?style=flat)](http://cocoapods.org/pods/GMCache)
[![Platform](https://img.shields.io/cocoapods/p/GMCache.svg?style=flat)](http://cocoapods.org/pods/GMCache)
## Usage
To run the example project, clone the repo, and run `pod install` from the Example directory first.
## Requirements
## Installation
GMCache is available through [CocoaPods](http://cocoapods.org). To install
it, simply add the following line to your Podfile:
```ruby
pod "GMCache"
```
## Author
wangyang, wangyang@wanmeizhensuo.com
## License
GMCache is available under the MIT license. See the LICENSE file for more info.
//
// NSAttributedString+GMSize.h
// Gengmei
//
// Created by wangyang on 7/22/15.
// Copyright (c) 2015 Wanmeichuangyi. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface NSAttributedString (GMSize)
+ (NSMutableAttributedString *)string:(NSString *)string font:(UIFont *)font color:(UIColor *)color shadow:(BOOL)needShadow;
/**
实际调用 [self attributedStringWithString:string trimBothEndSpace:YES trimInnerReturn:YES font:font color:color lineSpacing:0];
*/
+ (NSMutableAttributedString *)attributedStringWithString:(NSString *)string font:(UIFont *)font color:(UIColor *)color;
+ (NSMutableAttributedString *)attributedStringWithString:(NSString *)string font:(UIFont *)font color:(UIColor *)color paragraphStyle:(NSMutableParagraphStyle *)paragraphStyle;
/**
* @brief 适用于为整个 string 添加属性,其中的 paragraphStyle 为 mutable 的,可以取出来再次修改
@note 最佳使用方法: 用该方法创建 attributedString,再使用 sizeForBoundingRectSize: 方法来计算大小.
@note 默认为 TruncatingTail
*/
+ (NSMutableAttributedString *)attributedStringWithString:(NSString *)string trimBothEndSpace:(BOOL)tripSpace trimInnerReturn:(BOOL)trimReturn font:(UIFont *)font color:(UIColor *)color lineSpacing:(CGFloat)spacing;
/**
* @brief 使用该方法返回 attributedString 的大小。比如指定{320, 99},那么就会返回一个不超过该大小的 size,且宽高都经过 ceilf 处理
*
* @param maxSize 指定的最大的 string 大小。
*
* @return 经过 ceilf 处理的最大 size
*/
- (CGSize)sizeForBoundingRectSize:(CGSize)maxSize;
@end
@interface NSMutableAttributedString (GM)
- (void)addJustifiedAligment;
@end
@interface NSMutableAttributedString (Attributed)
- (NSMutableAttributedString *)addColor:(UIColor *)color;
- (NSMutableAttributedString *)addLineSpace:(NSInteger)space;
- (NSMutableAttributedString *)addShadow:(CGFloat)blur;
@end
//
// NSAttributedString+GMSize.m
// Gengmei
//
// Created by wangyang on 7/22/15.
// Copyright (c) 2015 Wanmeichuangyi. All rights reserved.
//
#import "NSAttributedString+GMSize.h"
#import "NSNull+Empty.h"
#import "NSString+GM.h"
@implementation NSAttributedString (GMSize)
+ (NSMutableAttributedString *)string:(NSString *)string font:(UIFont *)font color:(UIColor *)color shadow:(BOOL)needShadow{
if (!font) {
NSAssert(0, @"请传递一个正常的字体参数");
}
if (!color) {
NSAssert(0, @"请传递一个正常的字体参数");
}
if (![string isNonEmpty]) {
return [[NSMutableAttributedString alloc] initWithString:@"" attributes:nil];;
}
NSMutableDictionary *stringAttribute = [@{NSForegroundColorAttributeName:color,
NSFontAttributeName:font} mutableCopy];
if (needShadow) {
NSShadow *shadow = [NSShadow new];
shadow.shadowOffset = CGSizeZero;
shadow.shadowBlurRadius = 5;
stringAttribute[NSShadowAttributeName] = shadow;
}
NSMutableAttributedString *attriString = [[NSMutableAttributedString alloc] initWithString:string attributes:stringAttribute];
return attriString;
}
+ (NSMutableAttributedString *)attributedStringWithString:(NSString *)string font:(UIFont *)font color:(UIColor *)color {
return [self attributedStringWithString:string trimBothEndSpace:YES trimInnerReturn:YES font:font color:color lineSpacing:0];
}
+ (NSMutableAttributedString *)attributedStringWithString:(NSString *)string font:(UIFont *)font color:(UIColor *)color paragraphStyle:(NSMutableParagraphStyle *)paragraphStyle{
NSString *trimString = string;
trimString = [string trimBothEnd];
trimString = [trimString trimInnerReturn];
if (!trimString) {
trimString = @"";
}
NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString:trimString attributes:@{NSFontAttributeName:font, NSForegroundColorAttributeName:color, NSParagraphStyleAttributeName:paragraphStyle}];
return [attributedString mutableCopy];
}
+ (NSMutableAttributedString *)attributedStringWithString:(NSString *)string trimBothEndSpace:(BOOL)tripSpace trimInnerReturn:(BOOL)trimReturn font:(UIFont *)font color:(UIColor *)color lineSpacing:(CGFloat)spacing {
NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init];
style.lineSpacing = spacing;
style.lineBreakMode = NSLineBreakByTruncatingTail;
style.alignment = NSTextAlignmentLeft;
NSString *trimString = string;
if (tripSpace) {
trimString = [string trimBothEnd];
}
if (trimReturn) {
trimString = [trimString trimInnerReturn];
}
if (!trimString) {
trimString = @"";
}
NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString:trimString attributes:@{NSFontAttributeName:font, NSForegroundColorAttributeName:color, NSParagraphStyleAttributeName:style}];
return [attributedString mutableCopy];
}
- (CGSize)sizeForBoundingRectSize:(CGSize)maxSize{
// mutableCopy 以防修复原来的 string
NSMutableAttributedString *string = [self mutableCopy];
if (![string.string isNonEmpty]) {
return CGSizeZero;
}
// 修改 lineBreakMode 为 NSLineBreakByWordWrapping,因为 Truncate tail 会在 boundingRectWithSize 中指定,在这里指定了,反而会导致 boundingRectWithSize 方法计算不准确
NSMutableParagraphStyle *originStyle = [self attribute:NSParagraphStyleAttributeName atIndex:0 effectiveRange:NULL];
originStyle.lineBreakMode = NSLineBreakByWordWrapping;
CGSize size = [string boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingTruncatesLastVisibleLine context:[[NSStringDrawingContext alloc] init]].size;
// 修改 lineBreakMode 为 NSLineBreakByTruncatingTail,不然不显示...
originStyle.lineBreakMode = NSLineBreakByTruncatingTail;
return CGSizeMake(ceilf(size.width), ceilf(size.height));
}
@end
@implementation NSMutableAttributedString (GM)
- (void)addJustifiedAligment {
if (self.length == 0) {
return;
}
NSRange range = NSMakeRange(0, self.length);
NSDictionary *dic = [self attributesAtIndex:0 effectiveRange:&range];
NSMutableParagraphStyle *style = dic[NSParagraphStyleAttributeName];
if (!style) {
style = [[NSMutableParagraphStyle alloc] init];
}
style.alignment = NSTextAlignmentJustified;
style.firstLineHeadIndent = 0.001; // important: must have a value to make alignment work
[self addAttribute:NSBaselineOffsetAttributeName value:@0 range:range];
}
@end
@implementation NSMutableAttributedString (Attributed)
- (NSMutableAttributedString *)addColor:(UIColor *)color {
[self addAttributes:@{NSForegroundColorAttributeName: color} range:NSMakeRange(0, self.length)];
return self;
}
- (NSMutableAttributedString *)addLineSpace:(NSInteger)space {
NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init];
style.lineSpacing = space;
style.lineBreakMode = NSLineBreakByTruncatingTail;
[self addAttributes:@{NSParagraphStyleAttributeName: style} range:NSMakeRange(0, self.length)];
return self;
}
- (NSMutableAttributedString *)addShadow:(CGFloat)blur {
NSShadow *shadow = [NSShadow new];
shadow.shadowOffset = CGSizeZero;
shadow.shadowBlurRadius = blur;
[self addAttributes:@{NSShadowAttributeName: shadow} range:NSMakeRange(0, self.length)];
return self;
}
@end
//
// NSDate+DateFormat.h
// Gengmei
//
// Created by Sean Lee on 4/14/15.
// Copyright (c) 2015 Wanmeichuangyi. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface NSDate (DateFormat)
/**
* @author licong, 16-12-29 16:12:03
*
* 日期格式化成年月日型的字符串(eg:2015-4-14)
*
* @return 返回格式化后的字符串
*
* @since 5.8
*/
-(NSString *)dateFormatToString;
@end
//
// NSDate+DateFormat.m
// Gengmei
//
// Created by Sean Lee on 4/14/15.
// Copyright (c) 2015 Wanmeichuangyi. All rights reserved.
//
#import "NSDate+DateFormat.h"
@implementation NSDate (DateFormat)
-(NSString *)dateFormatToString {
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"yyyy-MM-dd"];
return [formatter stringFromDate:self];
}
@end
//
// NSFileManager+FolderSize.h
// ZhengXing
//
// Created by wangyang on 3/19/15.
// Copyright (c) 2015 Wanmei Creative. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface NSFileManager (FolderSize)
- (BOOL)getAllocatedSize:(unsigned long long *)size ofDirectoryAtURL:(NSURL *)directoryURL error:(NSError * __autoreleasing *)error;
@end
//
// NRFileManager.m
// NRFoundation
//
// Created by Nikolai Ruhe on 2015-02-22.
// Copyright (c) 2015 Nikolai Ruhe. All rights reserved.
//
#import "NSFileManager+FolderSize.h"
@implementation NSFileManager (FolderSize)
// This method calculates the accumulated size of a directory on the volume in bytes.
//
// As there's no simple way to get this information from the file system it has to crawl the entire hierarchy,
// accumulating the overall sum on the way. The resulting value is roughly equivalent with the amount of bytes
// that would become available on the volume if the directory would be deleted.
//
// Caveat: There are a couple of oddities that are not taken into account (like symbolic links, meta data of
// directories, hard links, ...).
- (BOOL)getAllocatedSize:(unsigned long long *)size ofDirectoryAtURL:(NSURL *)directoryURL error:(NSError * __autoreleasing *)error
{
NSParameterAssert(size != NULL);
NSParameterAssert(directoryURL != nil);
// We'll sum up content size here:
unsigned long long accumulatedSize = 0;
// prefetching some properties during traversal will speed up things a bit.
NSArray *prefetchedProperties = @[
NSURLIsRegularFileKey,
NSURLFileAllocatedSizeKey,
NSURLTotalFileAllocatedSizeKey,
];
// The error handler simply signals errors to outside code.
__block BOOL errorDidOccur = NO;
BOOL (^errorHandler)(NSURL *, NSError *) = ^(NSURL *url, NSError *localError) {
if (error != NULL)
*error = localError;
errorDidOccur = YES;
return NO;
};
// We have to enumerate all directory contents, including subdirectories.
NSDirectoryEnumerator *enumerator = [[NSFileManager defaultManager] enumeratorAtURL:directoryURL
includingPropertiesForKeys:prefetchedProperties
options:(NSDirectoryEnumerationOptions)0
errorHandler:errorHandler];
// Start the traversal:
for (NSURL *contentItemURL in enumerator) {
// Bail out on errors from the errorHandler.
if (errorDidOccur)
return NO;
// Get the type of this item, making sure we only sum up sizes of regular files.
NSNumber *isRegularFile;
if (! [contentItemURL getResourceValue:&isRegularFile forKey:NSURLIsRegularFileKey error:error])
return NO;
if (! [isRegularFile boolValue])
continue; // Ignore anything except regular files.
// To get the file's size we first try the most comprehensive value in terms of what the file may use on disk.
// This includes metadata, compression (on file system level) and block size.
NSNumber *fileSize;
if (! [contentItemURL getResourceValue:&fileSize forKey:NSURLTotalFileAllocatedSizeKey error:error])
return NO;
// In case the value is unavailable we use the fallback value (excluding meta data and compression)
// This value should always be available.
if (fileSize == nil) {
if (! [contentItemURL getResourceValue:&fileSize forKey:NSURLFileAllocatedSizeKey error:error])
return NO;
NSAssert(fileSize != nil, @"huh? NSURLFileAllocatedSizeKey should always return a value");
}
// We're good, add up the value.
accumulatedSize += [fileSize unsignedLongLongValue];
}
// Bail out on errors from the errorHandler.
if (errorDidOccur)
return NO;
// We finally got it.
*size = accumulatedSize;
return YES;
}
@end
//
// NSNull+Empty.h
// Gengmei
//
// Created by licong on 12/28/15.
// Copyright © 2015 Wanmeichuangyi. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface NSNull (Empty)
- (BOOL)isNonEmpty;
/**
* @brief 我们极力避免使用 string.length 的方式来判断空字符串。但是 string.length 除了用来判断,可能还会用在其它非判断的功能上。为了避免 [NSNull length] 而引起的 crash,还是给 NSNull 添加一个 length 方法比较安全。并且在 debug 情况下打印 log,以提示使用了 length 方法
*
* @return 0
*/
- (NSUInteger)length;
@end
//
// NSNull+Empty.m
// Gengmei
//
// Created by licong on 12/28/15.
// Copyright © 2015 Wanmeichuangyi. All rights reserved.
//
#import "NSNull+Empty.h"
@implementation NSNull (Empty)
- (BOOL) isNonEmpty {
return NO;
}
- (NSUInteger)length{
NSAssert(0, @"注意:向 NSNull 发送了 length 消息");
return 0;
}
@end
//
// UIViewController+KeyboardAnimation.h
// yingshibaokaoyan
//
// Created by wangyang on 7/17/14.
// Copyright (c) 2014 com.zkyj.yingshibao.kaoyao. All rights reserved.
//
#import <UIKit/UIKit.h>
/**
* 当键盘弹出或者收起时,会执行的block。在这个block里实现需要的UI变动
*
* @param keyboardFrame 将键盘转换为视图所在坐标第后,整个键盘View的Frame
* @param duration 动画时间
* @param curve 动画效果
* @param notifcation 通知
*/
typedef void(^ShowKeyboardAnimation)(CGRect keyboardFrame, CGFloat duration, NSInteger curve, NSNotification *notifcation);
typedef void(^HideKeyboardAnimation)(CGFloat duration, NSInteger curve, NSNotification *notifcation);
/**
* 使用该类别,以方便的控制键盘事件
*/
@interface NSObject (KeyboardAnimation)
- (void)observeKeyboardForView:(UIView *)view showKeyboardAnimation:(ShowKeyboardAnimation)animation1 hideKeyboardAnimation:(HideKeyboardAnimation)animation2;
- (void)removeObservKeyboard;
@end
//
// UIViewController+KeyboardAnimation.m
// yingshibaokaoyan
//
// Created by wangyang on 7/17/14.
// Copyright (c) 2014 com.zkyj.yingshibao.kaoyao. All rights reserved.
//
#import "NSObject+KeyboardAnimation.h"
#import <objc/runtime.h>
static const char kwy_targetView;
static const char kwy_showAnimationblock;
static const char kwy_hideAnimationblock;
@interface NSObject ()
@property (nonatomic, weak) UIView *wy_targetView;
@property (nonatomic, copy) ShowKeyboardAnimation wy_showAnimationblock;
@property (nonatomic, copy) HideKeyboardAnimation wy_hideAnimationblock;
@end
@implementation NSObject (KeyboardAnimation)
#pragma mark - 属性get、set
- (ShowKeyboardAnimation)wy_showAnimationblock
{
return objc_getAssociatedObject(self, &kwy_showAnimationblock);
}
- (void)setWy_showAnimationblock:(ShowKeyboardAnimation)wy_showAnimationblock
{
objc_setAssociatedObject(self, &kwy_showAnimationblock, wy_showAnimationblock, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (HideKeyboardAnimation)wy_hideAnimationblock
{
return objc_getAssociatedObject(self, &kwy_hideAnimationblock);
}
- (void)setWy_hideAnimationblock:(HideKeyboardAnimation)wy_hideAnimationblock
{
objc_setAssociatedObject(self, &kwy_hideAnimationblock, wy_hideAnimationblock, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (UIView *)wy_targetView
{
return objc_getAssociatedObject(self, &kwy_targetView);
}
- (void)setWy_targetView:(UIView *)wy_targetView
{
objc_setAssociatedObject(self, &kwy_targetView, wy_targetView, OBJC_ASSOCIATION_ASSIGN);
}
#pragma mark - 监听
- (void)observeKeyboardForView:(UIView *)view showKeyboardAnimation:(ShowKeyboardAnimation)animation1 hideKeyboardAnimation:(HideKeyboardAnimation)animation2
{
self.wy_showAnimationblock = animation1;
self.wy_targetView = view;
self.wy_hideAnimationblock = animation2;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
}
- (void)removeObservKeyboard
{
self.wy_showAnimationblock = nil;
self.wy_targetView = nil;
self.wy_hideAnimationblock = nil;
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
#pragma mark - 监听响应
- (void)keyboardWillShow:(NSNotification *)note{
// get keyboard size and loctaion
CGRect keyboardFrame;
[[note.userInfo valueForKey:UIKeyboardFrameEndUserInfoKey] getValue: &keyboardFrame];
// Need to translate the bounds to account for rotation.
keyboardFrame = [[UIApplication sharedApplication].keyWindow convertRect:keyboardFrame toView:self.wy_targetView.superview];
NSNumber *duration = [note.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey];
NSNumber *curve = [note.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey];
self.wy_showAnimationblock(keyboardFrame, [duration doubleValue], [curve integerValue], note);
}
- (void)keyboardWillHide:(NSNotification *)note{
NSNumber *duration = [note.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey];
NSNumber *curve = [note.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey];
self.wy_hideAnimationblock([duration doubleValue], [curve integerValue], note);
}
@end
//
// NSString+DateFormat.h
// Gengmei
//
// Created by Sean Lee on 4/15/15.
// Copyright (c) 2015 Wanmeichuangyi. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface NSString (DateFormat)
/**
* @author licong, 16-12-29 16:12:14
*
* String类型的日期转为冒号式的NSDate
*
* @return 返回一个NSDate对象
*
* @since 5.8
*/
-(NSDate *)stringFormatToColonDate;
/**
* @author licong, 16-12-29 16:12:59
*
* String类型的日期转为破折号式的NSDate
*
* @return 返回一个NSDate对象
*
* @since 5.8
*/
-(NSDate *)stringformatToDashDate;
@end
//
// NSString+DateFormat.m
// Gengmei
//
// Created by Sean Lee on 4/15/15.
// Copyright (c) 2015 Wanmeichuangyi. All rights reserved.
//
#import "NSString+DateFormat.h"
@implementation NSString (DateFormat)
-(NSDate *)stringFormatToColonDate{
NSDateFormatter* formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"yyyy-MM-dd"];
return [formatter dateFromString:self];
}
- (NSDate *)stringformatToDashDate{
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"yyyy:MM:dd"];
return [dateFormatter dateFromString:self];
}
@end
//
// NSString+Encrypt.h
// Gengmei
//
// Created by licong on 12/28/15.
// Copyright © 2015 Wanmeichuangyi. All rights reserved.
//
#import <Foundation/Foundation.h>
/**
* @brief
AES块长度 128 byte
加密模式CBC,cipher block chaining
数据长度不到128byte时需要填充(即no padding自定义填充)
填充方法s + (128 - len(s) % 128) * chr(128 - len(s) % 128) 将数字转成char字符拼接尾部
加密密钥 Up[K+ub%pliOnsO5UavFBd)cw5VcyHSX
初始向量需要附加在加密后的auth_user_id中 传给服务器,final auth_user_id = base64(iv+encrypted(user_id_auth))
*/
@interface NSString (Encrypt)
/**
* @brief AES256加密
*
* @param key 32位的密钥
*
* @return 返回加密后的密文
*/
- (NSString *)AES256EncryptedStringForKey:(NSString *)key;
/**
* @brief AES256解密
*
* @param key 32位的密钥
*
* @return 返回解密后的明文
*/
- (NSString *)AES256DecryptedStringForKey:(NSString *)key;
/**
* @brief MD5加密
*
* @return MD5加密后的String
*/
- (NSString *) stringFromMD5;
@end
//
// NSString+Encrypt.m
// Gengmei
//
// Created by licong on 12/28/15.
// Copyright © 2015 Wanmeichuangyi. All rights reserved.
//
#import "NSString+Encrypt.h"
#import <CommonCrypto/CommonDigest.h>
#import <CommonCrypto/CommonCryptor.h>
#import "NSString+GM.h"
@implementation NSString (Encrypt)
- (NSString *)AES256EncryptedStringForKey:(NSString *)key
{
//密钥
NSData *keyData = [key dataUsingEncoding:NSUTF8StringEncoding];
//明文数据
NSData *data = [self dataUsingEncoding:NSUTF8StringEncoding];
// Init cryptor
CCCryptorRef cryptor = NULL;
//IV:初始化16字节的随机向量
char iv[16];
for (int i = 0; i<16; i++) {
iv[i] = arc4random()%255;//一个字节长的随机数
}
//Create Cryptor
CCCryptorStatus create = CCCryptorCreateWithMode(kCCEncrypt,
kCCModeCBC, //CBC模式
kCCAlgorithmAES128, //分组密码块长度
ccNoPadding, //无填充模式
iv, // can be NULL, because null is full of zeros
keyData.bytes, //密钥
keyData.length, //密钥长度
NULL,
0,
0,
0, //这里参数只在CTR下有用,本初填0即可
&cryptor);
if (create == kCCSuccess){
size_t numBytesCrypted;
//自定义填充明文算法
NSUInteger dataLength = [data length];
int diff = 128 - (dataLength % 128);
unsigned long newSize = 0;
if(diff > 0)
newSize = dataLength + diff;
char dataPtr[newSize];
memcpy(dataPtr, [data bytes], [data length]);
for(int i = 0; i < diff; i++){
char character = diff;
dataPtr[i + dataLength] = character;
}
/*初始化加密后的data,并开辟好空间长度,查阅相关文档:对于分组密码,加密后的数据长度总是小于或者等于 加密前数据长度+单个分组密码块长度之和*/
NSMutableData *cipherData= [NSMutableData dataWithLength: sizeof(dataPtr)+kCCBlockSizeAES128];
/*Update Cryptor,得到加密后data以及我们需要的数据长度,这里可以看到cipherData的长度是小于或者等于outLength的
*/
CCCryptorStatus update = CCCryptorUpdate(cryptor,
dataPtr,
sizeof(dataPtr),
cipherData.mutableBytes,
cipherData.length,
&numBytesCrypted);
if (update == kCCSuccess){
//通过outLength截图我们需要的数据长度
cipherData.length = numBytesCrypted;
//Final Cryptor,最终生成最终的密文,装载给cipherData
CCCryptorStatus final = CCCryptorFinal(cryptor, //CCCryptorRef cryptorRef,
cipherData.mutableBytes, //void *dataOut,
cipherData.length, //size_t dataOutAvailable,
&numBytesCrypted); //size_t *dataOutMoved)
if (final == kCCSuccess){
//Release Cryptor
CCCryptorRelease(cryptor);
}
//最终结果= 初始向量+密文,这样服务器才可以拿到初始向量,用密钥解码
NSMutableData *resultData= [NSMutableData dataWithLength:0];
[resultData appendBytes:iv length:sizeof(iv)];
[resultData appendBytes:cipherData.bytes length:cipherData.length];
//最终结果再base64转码
NSString * resultStr = [resultData base64EncodedString];//[GTMBase64 stringByEncodingData:resultData];
return resultStr;
}
}
else{
NSLog(@"加密失败");
}
return nil;
}
- (NSString *)AES256DecryptedStringForKey:(NSString *)key {
//Key to Data
NSData *keyData = [key dataUsingEncoding:NSUTF8StringEncoding];
// Init cryptor
CCCryptorRef cryptor = NULL;
//IV:获取密文里的随机向量
NSData *data = [self base64DecodedData];
NSMutableData * iv = [NSMutableData dataWithBytes:data.bytes length:kCCKeySizeAES256];
// Create Cryptor
CCCryptorStatus createDecrypt = CCCryptorCreateWithMode(kCCDecrypt, // operation
kCCModeCBC, // mode CTR
kCCAlgorithmAES, // Algorithm
ccNoPadding, // padding
iv.bytes, // can be NULL, because null is full of zeros
keyData.bytes, // key
keyData.length, // keylength
NULL, //const void *tweak
0, //size_t tweakLength,
0, //int numRounds,
0, //CCModeOptions options,
&cryptor); //CCCryptorRef *cryptorRef
if (createDecrypt == kCCSuccess)
{
// Alloc Data Out
NSMutableData * realData = [NSMutableData dataWithBytes:data.bytes + 16 length:data.length - 16];
NSMutableData *cipherDataDecrypt = [NSMutableData dataWithLength:realData.length + kCCBlockSizeAES128];
//alloc number of bytes written to data Out
size_t outLengthDecrypt;
//Update Cryptor
CCCryptorStatus updateDecrypt = CCCryptorUpdate(cryptor,
realData.bytes, //const void *dataIn,
realData.length, //size_t dataInLength,
cipherDataDecrypt.mutableBytes, //void *dataOut,
cipherDataDecrypt.length, // size_t dataOutAvailable,
&outLengthDecrypt); // size_t *dataOutMoved)
if (updateDecrypt == kCCSuccess)
{
//Cut Data Out with nedded length
cipherDataDecrypt.length = outLengthDecrypt;
//Final Cryptor
CCCryptorStatus final = CCCryptorFinal(cryptor, //CCCryptorRef cryptorRef,
cipherDataDecrypt.mutableBytes, //void *dataOut,
cipherDataDecrypt.length, // size_t dataOutAvailable,
&outLengthDecrypt); // size_t *dataOutMoved)
if (final == kCCSuccess){
CCCryptorRelease(cryptor); //CCCryptorRef cryptorRef
}
// Data to String
NSMutableString* cipherFinalDecrypt = [[NSMutableString alloc] initWithData:cipherDataDecrypt encoding:NSUTF8StringEncoding];
int diff = [cipherFinalDecrypt characterAtIndex:cipherDataDecrypt.length - 1]; // 128字节的明文(填充字符)中填充字符的个数
[cipherFinalDecrypt deleteCharactersInRange:NSMakeRange(cipherFinalDecrypt.length - diff, diff)];
return cipherFinalDecrypt;
}
}
else{
NSLog(@"解密密失败");
}
return nil;
}
- (NSString *)stringFromMD5
{
if(self == nil || [self length] == 0)
return nil;
const char *value = [self UTF8String];
unsigned char outputBuffer[CC_MD5_DIGEST_LENGTH];
CC_MD5(value, (uint32_t)strlen(value), outputBuffer);
NSMutableString *outputString = [[NSMutableString alloc] initWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
for(NSInteger count = 0; count < CC_MD5_DIGEST_LENGTH; count++){
[outputString appendFormat:@"%02x",outputBuffer[count]];
}
return outputString;
}
+ (BOOL)validKey:(NSString*)key
{
if(key == nil || key.length != kCCKeySizeAES256){
return NO;
}
return YES;
}
@end
//
// NSString+GM.h
// Gengmei
//
// Created by licong on 12/28/15.
// Copyright © 2015 Wanmeichuangyi. All rights reserved.
//
#import <Foundation/Foundation.h>
/**
*引用base64 库 因不更新所以先拿过来
*
*/
@interface NSData (Base64)
+ (NSData *)dataWithBase64EncodedString:(NSString *)string;
- (NSString *)base64EncodedStringWithWrapWidth:(NSUInteger)wrapWidth;
- (NSString *)base64EncodedString;
@end
/**
* 常用且按功能块比较难划分的扩展方法
*/
@interface NSString (GM)
/**
* @author licong, 16-12-28 12:12:13
*
* 判断一个字符串是否为空(包括nil/@""/nil)
*
* @return 布尔值,YES表示字符串不为空,NO表示字符串为空
*
* @since 5.8
*/
- (BOOL)isNonEmpty;
/*!
* @author zhaiguojun, 16-04-21
*
* @brief 把字典和数组转成string
*
* 相当于调用 [NSJSONSerialization dataWithJSONObject:object options:0 error:&error];
* @return 转换后的string
*
* @since 5.9.3
*/
+ (NSString*)convertToPrettyPrintedJsonString:(id)object;
/**
把字典和数组转成简短的json string
相当于调用 [NSJSONSerialization dataWithJSONObject:object options:0 error:&error];
*/
+ (NSString *)convertToBriefJsonString:(id)object;
/**
* @author licong, 16-12-28 12:12:16
*
* 得到非空string
*
* @return 返回一个非空的字符串
*
* @since 5.8
*/
+ (NSString *)safeStringWithString:(NSString *)string;
/**
* @brief 是否为纯数字
*
* @param string 要检查的字符串
*
*/
+ (BOOL)isPureInt:(NSString *)string;
/**
* @brief 是否为手机号
*
* @param mobileNum 0~9 11位即可
*
*/
+ (BOOL)isMobileNumber:(NSString *)mobileNum;
/**
* 问题来自于服务器返回Str 我们当做int来解析会crash 古做一下兼容(目前来看 7.3.0 之前不会发生crash 7.3.0之后必crash)
*/
- (unsigned long long)unsignedLongLongValue;
/**
* @brief 是否为邮箱格式
*
* @param string 要检查的字符串
*
*/
+ (BOOL)isValidateEmail:(NSString *)email;
@end
/**
*
* 将类似URL的query参数解析成字典
*
*/
@interface NSString (paresQuery)
/**
* @author licong, 16-12-28 18:12:14
*
* 解析url中的query,转成字典格式
*
* @return 解析好的字典
*
* @since 5.8
*/
- (NSDictionary*)urlQueryToDictionary;
/**
* @author licong, 16-12-28 18:12:11
*
* 解析query字符串为字典比如:a=b&c=d
*
* @return 解析好的字典
*
* @since 5.8
*/
- (NSDictionary*)queryToDictionary;
@end
/**
*
* 根据String的Font计算String的size
*
*/
@interface NSString (calculatorSize)
/**
* @author licong, 16-12-28 18:12:38
*
* 计算String当行间距为0的时候的高度和宽度
*
* @param font String的font
* @param size String限定的size
*
* @return String实际(如果是多行,则经过折行后)的size
*
* @since 5.8
*/
- (CGSize)sizeWithFont:(UIFont *)font boundSize:(CGSize)size;
/**
* @author licong, 16-12-28 18:12:05
*
* 计算String在某个行间距下,高度和宽度
*
* @param font String的font
* @param size String限定的size
* @param lineSpacing 设定的行间距
*
* @return String在设定的行间距下,实际(如果是多行,则经过折行后)的size
*
* @since 5.8
*/
- (CGSize)sizeWithFont:(UIFont *)font boundSize:(CGSize)size lineSpacing:(CGFloat)lineSpacing;
@end
@interface NSString (URLEncoding)
/**
* @author licong, 16-12-29 16:12:45
*
* URL编码
*
* @return 编码后的URL
*
* @since 5.8
*/
- (NSString*) URLEncodedString;
/**
* @author licong, 16-12-29 16:12:08
*
* URL解码
*
* @return 解码URL
*
* @since 5.8
*/
- (NSString*) URLDecodedString;
/**
URL编码
@return 编码后的URL
*/
- (NSString *)URLEncodeString;
@end
@interface NSString (Trim)
/**
* @author licong, 16-12-28 18:12:04
*
* 去除字符串两头的空白(空格及换行)
*
* @return 无空格的字符串
*
* @since 5.8
*/
- (NSString *)trimBothEnd;
- (NSString *)trimSpace;
- (NSString *)trimInnerReturn;
- (NSString *)trimNewlinesToOne;
/**
*引用base64 库 因不更新所以先拿过来
*
*/
+ (NSString *)stringWithBase64EncodedString:(NSString *)string;
- (NSString *)base64EncodedStringWithWrapWidth:(NSUInteger)wrapWidth;
- (NSString *)base64EncodedString;
- (NSString *)base64DecodedString;
- (NSData *)base64DecodedData;
@end
Copyright (c) 2016 licong <1240690490@qq.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.
# GMFoundation
[![CI Status](http://img.shields.io/travis/licong/GMFoundation.svg?style=flat)](https://travis-ci.org/licong/GMFoundation)
[![Version](https://img.shields.io/cocoapods/v/GMFoundation.svg?style=flat)](http://cocoapods.org/pods/GMFoundation)
[![License](https://img.shields.io/cocoapods/l/GMFoundation.svg?style=flat)](http://cocoapods.org/pods/GMFoundation)
[![Platform](https://img.shields.io/cocoapods/p/GMFoundation.svg?style=flat)](http://cocoapods.org/pods/GMFoundation)
## Example
To run the example project, clone the repo, and run `pod install` from the Example directory first.
## Requirements
## Installation
GMFoundation is available through [CocoaPods](http://cocoapods.org). To install
it, simply add the following line to your Podfile:
```ruby
pod "GMFoundation"
```
## Author
licong, 1240690490@qq.com
## License
GMFoundation is available under the MIT license. See the LICENSE file for more info.
//
// JSONModelClassProperty.h
// JSONModel
//
#import <Foundation/Foundation.h>
/**
* **You do not need to instantiate this class yourself.** This class is used internally by JSONModel
* to inspect the declared properties of your model class.
*
* Class to contain the information, representing a class property
* It features the property's name, type, whether it's a required property,
* and (optionally) the class protocol
*/
@interface JSONModelClassProperty : NSObject
// deprecated
@property (assign, nonatomic) BOOL isIndex DEPRECATED_ATTRIBUTE;
/** The name of the declared property (not the ivar name) */
@property (copy, nonatomic) NSString *name;
/** A property class type */
@property (assign, nonatomic) Class type;
/** Struct name if a struct */
@property (strong, nonatomic) NSString *structName;
/** The name of the protocol the property conforms to (or nil) */
@property (copy, nonatomic) NSString *protocol;
/** If YES, it can be missing in the input data, and the input would be still valid */
@property (assign, nonatomic) BOOL isOptional;
/** If YES - don't call any transformers on this property's value */
@property (assign, nonatomic) BOOL isStandardJSONType;
/** If YES - create a mutable object for the value of the property */
@property (assign, nonatomic) BOOL isMutable;
/** a custom getter for this property, found in the owning model */
@property (assign, nonatomic) SEL customGetter;
/** custom setters for this property, found in the owning model */
@property (strong, nonatomic) NSMutableDictionary *customSetters;
@end
//
// JSONModelClassProperty.m
// JSONModel
//
#import "JSONModelClassProperty.h"
@implementation JSONModelClassProperty
-(NSString*)description
{
//build the properties string for the current class property
NSMutableArray* properties = [NSMutableArray arrayWithCapacity:8];
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
if (self.isIndex) [properties addObject:@"Index"];
#pragma GCC diagnostic pop
if (self.isOptional) [properties addObject:@"Optional"];
if (self.isMutable) [properties addObject:@"Mutable"];
if (self.isStandardJSONType) [properties addObject:@"Standard JSON type"];
if (self.customGetter) [properties addObject:[NSString stringWithFormat: @"Getter = %@", NSStringFromSelector(self.customGetter)]];
if (self.customSetters)
{
NSMutableArray *setters = [NSMutableArray array];
for (id obj in self.customSetters.allValues)
{
SEL selector;
[obj getValue:&selector];
[setters addObject:NSStringFromSelector(selector)];
}
[properties addObject:[NSString stringWithFormat: @"Setters = [%@]", [setters componentsJoinedByString:@", "]]];
}
NSString* propertiesString = @"";
if (properties.count>0) {
propertiesString = [NSString stringWithFormat:@"(%@)", [properties componentsJoinedByString:@", "]];
}
//return the name, type and additional properties
return [NSString stringWithFormat:@"@property %@%@ %@ %@",
self.type?[NSString stringWithFormat:@"%@*",self.type]:(self.structName?self.structName:@"primitive"),
self.protocol?[NSString stringWithFormat:@"<%@>", self.protocol]:@"",
self.name,
propertiesString
];
}
@end
//
// JSONModelError.h
// JSONModel
//
#import <Foundation/Foundation.h>
/////////////////////////////////////////////////////////////////////////////////////////////
typedef NS_ENUM(int, kJSONModelErrorTypes)
{
kJSONModelErrorInvalidData = 1,
kJSONModelErrorBadResponse = 2,
kJSONModelErrorBadJSON = 3,
kJSONModelErrorModelIsInvalid = 4,
kJSONModelErrorNilInput = 5,
kJSONModelErrorModelSoft = 6,
};
/////////////////////////////////////////////////////////////////////////////////////////////
/** The domain name used for the JSONModelError instances */
extern NSString *const JSONModelErrorDomain;
/**
* If the model JSON input misses keys that are required, check the
* userInfo dictionary of the JSONModelError instance you get back -
* under the kJSONModelMissingKeys key you will find a list of the
* names of the missing keys.
*/
extern NSString *const kJSONModelMissingKeys;
/**
* If JSON input has a different type than expected by the model, check the
* userInfo dictionary of the JSONModelError instance you get back -
* under the kJSONModelTypeMismatch key you will find a description
* of the mismatched types.
*/
extern NSString *const kJSONModelTypeMismatch;
/**
* If an error occurs in a nested model, check the userInfo dictionary of
* the JSONModelError instance you get back - under the kJSONModelKeyPath
* key you will find key-path at which the error occurred.
*/
extern NSString *const kJSONModelKeyPath;
extern NSString* const kJSONModelSoftKeyPath;
/////////////////////////////////////////////////////////////////////////////////////////////
/**
* Custom NSError subclass with shortcut methods for creating
* the common JSONModel errors
*/
@interface JSONModelError : NSError
@property (strong, nonatomic) NSHTTPURLResponse *httpResponse;
@property (strong, nonatomic) NSData *responseData;
/**
* Creates a JSONModelError instance with code kJSONModelErrorInvalidData = 1
*/
+ (id)errorInvalidDataWithMessage:(NSString *)message;
/**
* Creates a JSONModelError instance with code kJSONModelErrorInvalidData = 1
* @param keys a set of field names that were required, but not found in the input
*/
+ (id)errorInvalidDataWithMissingKeys:(NSSet *)keys;
/**
* Creates a JSONModelError instance with code kJSONModelErrorInvalidData = 1
* @param mismatchDescription description of the type mismatch that was encountered.
*/
+ (id)errorInvalidDataWithTypeMismatch:(NSString *)mismatchDescription;
/**
* Creates a JSONModelError instance with code kJSONModelErrorBadResponse = 2
*/
+ (id)errorBadResponse;
/**
* Creates a JSONModelError instance with code kJSONModelErrorBadJSON = 3
*/
+ (id)errorBadJSON;
/**
* Creates a JSONModelError instance with code kJSONModelErrorModelIsInvalid = 4
*/
+ (id)errorModelIsInvalid;
/**
* Creates a JSONModelError instance with code kJSONModelErrorNilInput = 5
*/
+ (id)errorInputIsNil;
/**
* Creates a new JSONModelError with the same values plus information about the key-path of the error.
* Properties in the new error object are the same as those from the receiver,
* except that a new key kJSONModelKeyPath is added to the userInfo dictionary.
* This key contains the component string parameter. If the key is already present
* then the new error object has the component string prepended to the existing value.
*/
- (instancetype)errorByPrependingKeyPathComponent:(NSString *)component;
/////////////////////////////////////////////////////////////////////////////////////////////
// 以下三种方法用来处理 kJSONModelErrorModelSoft
/**
生成新的 kJSONModelErrorModelSoft。msg通常格式为:{当前keyPath}应该是aaa,但是返回了bbb
*/
+ (id)errorSoftMsg:(NSString *)msg class:(Class)cls;
- (instancetype)errorByAppendingSoftMsg:(NSString *)msg class:(Class)cls;
- (instancetype)errorByAppendingSubPropertyMsg:(NSString *)msg class:(Class)cls;
@end
//
// JSONModelError.m
// JSONModel
//
#import "JSONModelError.h"
NSString* const JSONModelErrorDomain = @"JSONModelErrorDomain";
NSString* const kJSONModelMissingKeys = @"kJSONModelMissingKeys";
NSString* const kJSONModelTypeMismatch = @"kJSONModelTypeMismatch";
NSString* const kJSONModelKeyPath = @"kJSONModelKeyPath";
NSString* const kJSONModelSoftKeyPath = @"kJSONModelSoftKeyPath";
@implementation JSONModelError
+(id)errorInvalidDataWithMessage:(NSString*)message
{
message = [NSString stringWithFormat:@"Invalid JSON data: %@", message];
return [JSONModelError errorWithDomain:JSONModelErrorDomain
code:kJSONModelErrorInvalidData
userInfo:@{NSLocalizedDescriptionKey:message}];
}
+(id)errorInvalidDataWithMissingKeys:(NSSet *)keys
{
return [JSONModelError errorWithDomain:JSONModelErrorDomain
code:kJSONModelErrorInvalidData
userInfo:@{NSLocalizedDescriptionKey:@"Invalid JSON data. Required JSON keys are missing from the input. Check the error user information.",kJSONModelMissingKeys:[keys allObjects]}];
}
+(id)errorInvalidDataWithTypeMismatch:(NSString*)mismatchDescription
{
return [JSONModelError errorWithDomain:JSONModelErrorDomain
code:kJSONModelErrorInvalidData
userInfo:@{NSLocalizedDescriptionKey:@"Invalid JSON data. The JSON type mismatches the expected type. Check the error user information.",kJSONModelTypeMismatch:mismatchDescription}];
}
+(id)errorBadResponse
{
return [JSONModelError errorWithDomain:JSONModelErrorDomain
code:kJSONModelErrorBadResponse
userInfo:@{NSLocalizedDescriptionKey:@"Bad network response. Probably the JSON URL is unreachable."}];
}
+(id)errorBadJSON
{
return [JSONModelError errorWithDomain:JSONModelErrorDomain
code:kJSONModelErrorBadJSON
userInfo:@{NSLocalizedDescriptionKey:@"Malformed JSON. Check the JSONModel data input."}];
}
+(id)errorModelIsInvalid
{
return [JSONModelError errorWithDomain:JSONModelErrorDomain
code:kJSONModelErrorModelIsInvalid
userInfo:@{NSLocalizedDescriptionKey:@"Model does not validate. The custom validation for the input data failed."}];
}
+(id)errorInputIsNil
{
return [JSONModelError errorWithDomain:JSONModelErrorDomain
code:kJSONModelErrorNilInput
userInfo:@{NSLocalizedDescriptionKey:@"Initializing model with nil input object."}];
}
- (instancetype)errorByPrependingKeyPathComponent:(NSString*)component
{
// Create a mutable copy of the user info so that we can add to it and update it
NSMutableDictionary* userInfo = [self.userInfo mutableCopy];
// Create or update the key-path
NSString* existingPath = userInfo[kJSONModelKeyPath];
NSString* separator = [existingPath hasPrefix:@"["] ? @"" : @".";
NSString* updatedPath = (existingPath == nil) ? component : [component stringByAppendingFormat:@"%@%@", separator, existingPath];
userInfo[kJSONModelKeyPath] = updatedPath;
// Create the new error
return [JSONModelError errorWithDomain:self.domain
code:self.code
userInfo:[NSDictionary dictionaryWithDictionary:userInfo]];
}
- (instancetype)errorByAppendingSoftMsg:(NSString *)msg class:(Class)cls {
/*
softError: 特指kJSONModelErrorModelSoft错误
criticalError: 非kJSONModelErrorModelSoft错误
在userInfo中追加新的key-value。只会发生在softError中。
如果第一次产生的是softError,再发生criticalError,将只返回criticalError,softError将会被丢弃
*/
NSMutableDictionary* userInfo = [self.userInfo mutableCopy];
NSString *existMsg = userInfo[kJSONModelSoftKeyPath] ?: @"";
userInfo[kJSONModelSoftKeyPath] = [NSString stringWithFormat:@"%@.%@/%@", NSStringFromClass(cls), msg, existMsg];
return [JSONModelError errorWithDomain:JSONModelErrorDomain
code:kJSONModelErrorModelSoft
userInfo:[userInfo copy]];
}
- (instancetype)errorByAppendingSubPropertyMsg:(NSString *)msg class:(Class)cls {
/*
softError: 特指kJSONModelErrorModelSoft错误
criticalError: 非kJSONModelErrorModelSoft错误
在userInfo中追加新的key-value。只会发生在softError中。
如果第一次产生的是softError,再发生criticalError,将只返回criticalError,softError将会被丢弃
*/
NSMutableDictionary* userInfo = [self.userInfo mutableCopy];
NSString *existMsg = userInfo[kJSONModelSoftKeyPath] ?: @"";
userInfo[kJSONModelSoftKeyPath] = [NSString stringWithFormat:@"%@.%@->%@", NSStringFromClass(cls), msg, existMsg];
return [JSONModelError errorWithDomain:JSONModelErrorDomain
code:kJSONModelErrorModelSoft
userInfo:[userInfo copy]];
}
+(id)errorSoftMsg:(NSString *)msg class:(Class)cls {
NSDictionary *dic = @{NSLocalizedDescriptionKey:@"Some json value typee is wrong, but not critical.",
kJSONModelSoftKeyPath: [NSString stringWithFormat:@"%@.%@", NSStringFromClass(cls), msg]};
return [JSONModelError errorWithDomain:JSONModelErrorDomain
code:kJSONModelErrorModelSoft
userInfo:dic];
}
@end
//
// JSONModelLib.h
// JSONModel
//
#import <Foundation/Foundation.h>
// core
#import "JSONModel.h"
#import "JSONModelError.h"
// transformations
#import "JSONValueTransformer.h"
#import "JSONKeyMapper.h"
// networking (deprecated)
#import "JSONHTTPClient.h"
#import "JSONModel+networking.h"
#import "JSONAPI.h"
//
// JSONAPI.h
// JSONModel
//
#import <Foundation/Foundation.h>
#import "JSONHTTPClient.h"
DEPRECATED_ATTRIBUTE
@interface JSONAPI : NSObject
+ (void)setAPIBaseURLWithString:(NSString *)base DEPRECATED_ATTRIBUTE;
+ (void)setContentType:(NSString *)ctype DEPRECATED_ATTRIBUTE;
+ (void)getWithPath:(NSString *)path andParams:(NSDictionary *)params completion:(JSONObjectBlock)completeBlock DEPRECATED_ATTRIBUTE;
+ (void)postWithPath:(NSString *)path andParams:(NSDictionary *)params completion:(JSONObjectBlock)completeBlock DEPRECATED_ATTRIBUTE;
+ (void)rpcWithMethodName:(NSString *)method andArguments:(NSArray *)args completion:(JSONObjectBlock)completeBlock DEPRECATED_ATTRIBUTE;
+ (void)rpc2WithMethodName:(NSString *)method andParams:(id)params completion:(JSONObjectBlock)completeBlock DEPRECATED_ATTRIBUTE;
@end
//
// JSONAPI.m
// JSONModel
//
#import "JSONAPI.h"
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#pragma GCC diagnostic ignored "-Wdeprecated-implementations"
#pragma mark - helper error model class
@interface JSONAPIRPCErrorModel: JSONModel
@property (assign, nonatomic) int code;
@property (strong, nonatomic) NSString* message;
@property (strong, nonatomic) id<Optional> data;
@end
#pragma mark - static variables
static JSONAPI* sharedInstance = nil;
static long jsonRpcId = 0;
#pragma mark - JSONAPI() private interface
@interface JSONAPI ()
@property (strong, nonatomic) NSString* baseURLString;
@end
#pragma mark - JSONAPI implementation
@implementation JSONAPI
#pragma mark - initialize
+(void)initialize
{
static dispatch_once_t once;
dispatch_once(&once, ^{
sharedInstance = [[JSONAPI alloc] init];
});
}
#pragma mark - api config methods
+(void)setAPIBaseURLWithString:(NSString*)base
{
sharedInstance.baseURLString = base;
}
+(void)setContentType:(NSString*)ctype
{
[JSONHTTPClient setRequestContentType: ctype];
}
#pragma mark - GET methods
+(void)getWithPath:(NSString*)path andParams:(NSDictionary*)params completion:(JSONObjectBlock)completeBlock
{
NSString* fullURL = [NSString stringWithFormat:@"%@%@", sharedInstance.baseURLString, path];
[JSONHTTPClient getJSONFromURLWithString: fullURL params:params completion:^(NSDictionary *json, JSONModelError *e) {
completeBlock(json, e);
}];
}
#pragma mark - POST methods
+(void)postWithPath:(NSString*)path andParams:(NSDictionary*)params completion:(JSONObjectBlock)completeBlock
{
NSString* fullURL = [NSString stringWithFormat:@"%@%@", sharedInstance.baseURLString, path];
[JSONHTTPClient postJSONFromURLWithString: fullURL params:params completion:^(NSDictionary *json, JSONModelError *e) {
completeBlock(json, e);
}];
}
#pragma mark - RPC methods
+(void)__rpcRequestWithObject:(id)jsonObject completion:(JSONObjectBlock)completeBlock
{
NSData* jsonRequestData = [NSJSONSerialization dataWithJSONObject:jsonObject
options:kNilOptions
error:nil];
NSString* jsonRequestString = [[NSString alloc] initWithData:jsonRequestData encoding: NSUTF8StringEncoding];
NSAssert(sharedInstance.baseURLString, @"API base URL not set");
[JSONHTTPClient postJSONFromURLWithString: sharedInstance.baseURLString
bodyString: jsonRequestString
completion:^(NSDictionary *json, JSONModelError* e) {
if (completeBlock) {
//handle the rpc response
NSDictionary* result = json[@"result"];
if (!result) {
JSONAPIRPCErrorModel* error = [[JSONAPIRPCErrorModel alloc] initWithDictionary:json[@"error"] error:nil];
if (error) {
//custom server error
if (!error.message) error.message = @"Generic json rpc error";
e = [JSONModelError errorWithDomain:JSONModelErrorDomain
code:error.code
userInfo: @{ NSLocalizedDescriptionKey : error.message}];
} else {
//generic error
e = [JSONModelError errorBadResponse];
}
}
//invoke the callback
completeBlock(result, e);
}
}];
}
+(void)rpcWithMethodName:(NSString*)method andArguments:(NSArray*)args completion:(JSONObjectBlock)completeBlock
{
NSAssert(method, @"No method specified");
if (!args) args = @[];
[self __rpcRequestWithObject:@{
//rpc 1.0
@"id": @(++jsonRpcId),
@"params": args,
@"method": method
} completion:completeBlock];
}
+(void)rpc2WithMethodName:(NSString*)method andParams:(id)params completion:(JSONObjectBlock)completeBlock
{
NSAssert(method, @"No method specified");
if (!params) params = @[];
[self __rpcRequestWithObject:@{
//rpc 2.0
@"jsonrpc": @"2.0",
@"id": @(++jsonRpcId),
@"params": params,
@"method": method
} completion:completeBlock];
}
@end
#pragma mark - helper rpc error model class implementation
@implementation JSONAPIRPCErrorModel
@end
//
// JSONModelHTTPClient.h
// JSONModel
//
#import "JSONModel.h"
extern NSString *const kHTTPMethodGET DEPRECATED_ATTRIBUTE;
extern NSString *const kHTTPMethodPOST DEPRECATED_ATTRIBUTE;
extern NSString *const kContentTypeAutomatic DEPRECATED_ATTRIBUTE;
extern NSString *const kContentTypeJSON DEPRECATED_ATTRIBUTE;
extern NSString *const kContentTypeWWWEncoded DEPRECATED_ATTRIBUTE;
typedef void (^JSONObjectBlock)(id json, JSONModelError *err) DEPRECATED_ATTRIBUTE;
DEPRECATED_ATTRIBUTE
@interface JSONHTTPClient : NSObject
+ (NSMutableDictionary *)requestHeaders DEPRECATED_ATTRIBUTE;
+ (void)setDefaultTextEncoding:(NSStringEncoding)encoding DEPRECATED_ATTRIBUTE;
+ (void)setCachingPolicy:(NSURLRequestCachePolicy)policy DEPRECATED_ATTRIBUTE;
+ (void)setTimeoutInSeconds:(int)seconds DEPRECATED_ATTRIBUTE;
+ (void)setRequestContentType:(NSString *)contentTypeString DEPRECATED_ATTRIBUTE;
+ (void)getJSONFromURLWithString:(NSString *)urlString completion:(JSONObjectBlock)completeBlock DEPRECATED_ATTRIBUTE;
+ (void)getJSONFromURLWithString:(NSString *)urlString params:(NSDictionary *)params completion:(JSONObjectBlock)completeBlock DEPRECATED_ATTRIBUTE;
+ (void)JSONFromURLWithString:(NSString *)urlString method:(NSString *)method params:(NSDictionary *)params orBodyString:(NSString *)bodyString completion:(JSONObjectBlock)completeBlock DEPRECATED_ATTRIBUTE;
+ (void)JSONFromURLWithString:(NSString *)urlString method:(NSString *)method params:(NSDictionary *)params orBodyString:(NSString *)bodyString headers:(NSDictionary *)headers completion:(JSONObjectBlock)completeBlock DEPRECATED_ATTRIBUTE;
+ (void)JSONFromURLWithString:(NSString *)urlString method:(NSString *)method params:(NSDictionary *)params orBodyData:(NSData *)bodyData headers:(NSDictionary *)headers completion:(JSONObjectBlock)completeBlock DEPRECATED_ATTRIBUTE;
+ (void)postJSONFromURLWithString:(NSString *)urlString params:(NSDictionary *)params completion:(JSONObjectBlock)completeBlock DEPRECATED_ATTRIBUTE;
+ (void)postJSONFromURLWithString:(NSString *)urlString bodyString:(NSString *)bodyString completion:(JSONObjectBlock)completeBlock DEPRECATED_ATTRIBUTE;
+ (void)postJSONFromURLWithString:(NSString *)urlString bodyData:(NSData *)bodyData completion:(JSONObjectBlock)completeBlock DEPRECATED_ATTRIBUTE;
@end
//
// JSONModel+networking.h
// JSONModel
//
#import "JSONModel.h"
#import "JSONHTTPClient.h"
typedef void (^JSONModelBlock)(id model, JSONModelError *err) DEPRECATED_ATTRIBUTE;
@interface JSONModel (Networking)
@property (assign, nonatomic) BOOL isLoading DEPRECATED_ATTRIBUTE;
- (instancetype)initFromURLWithString:(NSString *)urlString completion:(JSONModelBlock)completeBlock DEPRECATED_ATTRIBUTE;
+ (void)getModelFromURLWithString:(NSString *)urlString completion:(JSONModelBlock)completeBlock DEPRECATED_ATTRIBUTE;
+ (void)postModel:(JSONModel *)post toURLWithString:(NSString *)urlString completion:(JSONModelBlock)completeBlock DEPRECATED_ATTRIBUTE;
@end
//
// JSONModel+networking.m
// JSONModel
//
#import "JSONModel+networking.h"
#import "JSONHTTPClient.h"
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#pragma GCC diagnostic ignored "-Wdeprecated-implementations"
BOOL _isLoading;
@implementation JSONModel(Networking)
@dynamic isLoading;
-(BOOL)isLoading
{
return _isLoading;
}
-(void)setIsLoading:(BOOL)isLoading
{
_isLoading = isLoading;
}
-(instancetype)initFromURLWithString:(NSString *)urlString completion:(JSONModelBlock)completeBlock
{
id placeholder = [super init];
__block id blockSelf = self;
if (placeholder) {
//initialization
self.isLoading = YES;
[JSONHTTPClient getJSONFromURLWithString:urlString
completion:^(NSDictionary *json, JSONModelError* e) {
JSONModelError* initError = nil;
blockSelf = [self initWithDictionary:json error:&initError];
if (completeBlock) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_MSEC), dispatch_get_main_queue(), ^{
completeBlock(blockSelf, e?e:initError );
});
}
self.isLoading = NO;
}];
}
return placeholder;
}
+ (void)getModelFromURLWithString:(NSString*)urlString completion:(JSONModelBlock)completeBlock
{
[JSONHTTPClient getJSONFromURLWithString:urlString
completion:^(NSDictionary* jsonDict, JSONModelError* err)
{
JSONModel* model = nil;
if(err == nil)
{
model = [[self alloc] initWithDictionary:jsonDict error:&err];
}
if(completeBlock != nil)
{
dispatch_async(dispatch_get_main_queue(), ^
{
completeBlock(model, err);
});
}
}];
}
+ (void)postModel:(JSONModel*)post toURLWithString:(NSString*)urlString completion:(JSONModelBlock)completeBlock
{
[JSONHTTPClient postJSONFromURLWithString:urlString
bodyString:[post toJSONString]
completion:^(NSDictionary* jsonDict, JSONModelError* err)
{
JSONModel* model = nil;
if(err == nil)
{
model = [[self alloc] initWithDictionary:jsonDict error:&err];
}
if(completeBlock != nil)
{
dispatch_async(dispatch_get_main_queue(), ^
{
completeBlock(model, err);
});
}
}];
}
@end
Copyright (c) 2012-2016 Marin Todorov and JSONModel contributors
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.
This diff is collapsed.
Copyright (c) 2016 北京更美互动信息科技有限公司
仅限北京更美互动信息科技有限公司内部使用
//
// UIAlertController+gm.h
// AFNetworking
//
// Created by Q14 on 2019/12/18.
//
NS_ASSUME_NONNULL_BEGIN
@interface UIAlertController (gm)
+ (void)showgm_OKAlertWithTitle:(NSString *)title message:(NSString *)message actionTitle:(NSString *)actionTitle actionHandler:(void(^)(void))actionHandler;
+ (void)gm_Alert:(NSString *)title leftTitle:(NSString *)leftTitle rightTitle:(NSString *)rightTitle leftAlterAction:(void(^)(void))leftAlterAction rightAlertAction:(void(^)(void))rightAlertAction;
@end
NS_ASSUME_NONNULL_END
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment