// 代码地址: https://github.com/CoderMJLee/MJRefresh #import #import #import // 弱引用 #define MJWeakSelf __weak typeof(self) weakSelf = self; // 日志输出 #ifdef DEBUG #define MJRefreshLog(...) NSLog(__VA_ARGS__) #else #define MJRefreshLog(...) #endif // 过期提醒 #define MJRefreshDeprecated(DESCRIPTION) __attribute__((deprecated(DESCRIPTION))) // 运行时objc_msgSend #define MJRefreshMsgSend(...) ((void (*)(void *, SEL, UIView *))objc_msgSend)(__VA_ARGS__) #define MJRefreshMsgTarget(target) (__bridge void *)(target) // RGB颜色 #define MJRefreshColor(r, g, b) [UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:1.0] // 文字颜色 #define MJRefreshLabelTextColor MJRefreshColor(90, 90, 90) // 字体大小 #define MJRefreshLabelFont [UIFont boldSystemFontOfSize:14] // 常量 UIKIT_EXTERN const CGFloat MJRefreshLabelLeftInset; UIKIT_EXTERN const CGFloat MJRefreshHeaderHeight; UIKIT_EXTERN const CGFloat MJRefreshFooterHeight; UIKIT_EXTERN const CGFloat MJRefreshTrailWidth; UIKIT_EXTERN const CGFloat MJRefreshFastAnimationDuration; UIKIT_EXTERN const CGFloat MJRefreshSlowAnimationDuration; UIKIT_EXTERN NSString *const MJRefreshKeyPathContentOffset; UIKIT_EXTERN NSString *const MJRefreshKeyPathContentSize; UIKIT_EXTERN NSString *const MJRefreshKeyPathContentInset; UIKIT_EXTERN NSString *const MJRefreshKeyPathPanState; UIKIT_EXTERN NSString *const MJRefreshHeaderLastUpdatedTimeKey; UIKIT_EXTERN NSString *const MJRefreshHeaderIdleText; UIKIT_EXTERN NSString *const MJRefreshHeaderPullingText; UIKIT_EXTERN NSString *const MJRefreshHeaderRefreshingText; UIKIT_EXTERN NSString *const MJRefreshTrailerIdleText; UIKIT_EXTERN NSString *const MJRefreshTrailerPullingText; UIKIT_EXTERN NSString *const MJRefreshAutoFooterIdleText; UIKIT_EXTERN NSString *const MJRefreshAutoFooterRefreshingText; UIKIT_EXTERN NSString *const MJRefreshAutoFooterNoMoreDataText; UIKIT_EXTERN NSString *const MJRefreshBackFooterIdleText; UIKIT_EXTERN NSString *const MJRefreshBackFooterPullingText; UIKIT_EXTERN NSString *const MJRefreshBackFooterRefreshingText; UIKIT_EXTERN NSString *const MJRefreshBackFooterNoMoreDataText; UIKIT_EXTERN NSString *const MJRefreshHeaderLastTimeText; UIKIT_EXTERN NSString *const MJRefreshHeaderDateTodayText; UIKIT_EXTERN NSString *const MJRefreshHeaderNoneLastDateText; UIKIT_EXTERN NSString *const MJRefreshDidChangeLanguageNotification; // 状态检查 #define MJRefreshCheckState \ MJRefreshState oldState = self.state; \ if (state == oldState) return; \ [super setState:state]; // 异步主线程执行,不强持有Self #define MJRefreshDispatchAsyncOnMainQueue(x) \ __weak typeof(self) weakSelf = self; \ dispatch_async(dispatch_get_main_queue(), ^{ \ typeof(weakSelf) self = weakSelf; \ {x} \ }); /// 替换方法实现 /// @param _fromClass 源类 /// @param _originSelector 源类的 Selector /// @param _toClass 目标类 /// @param _newSelector 目标类的 Selector CG_INLINE BOOL MJRefreshExchangeImplementations( Class _fromClass, SEL _originSelector, Class _toClass, SEL _newSelector) { if (!_fromClass || !_toClass) { return NO; } Method oriMethod = class_getInstanceMethod(_fromClass, _originSelector); Method newMethod = class_getInstanceMethod(_toClass, _newSelector); if (!newMethod) { return NO; } BOOL isAddedMethod = class_addMethod(_fromClass, _originSelector, method_getImplementation(newMethod), method_getTypeEncoding(newMethod)); if (isAddedMethod) { // 如果 class_addMethod 成功了,说明之前 fromClass 里并不存在 originSelector,所以要用一个空的方法代替它,以避免 class_replaceMethod 后,后续 toClass 的这个方法被调用时可能会 crash IMP emptyIMP = imp_implementationWithBlock(^(id selfObject) {}); IMP oriMethodIMP = method_getImplementation(oriMethod) ?: emptyIMP; const char *oriMethodTypeEncoding = method_getTypeEncoding(oriMethod) ?: "v@:"; class_replaceMethod(_toClass, _newSelector, oriMethodIMP, oriMethodTypeEncoding); } else { method_exchangeImplementations(oriMethod, newMethod); } return YES; }