├── .gitignore ├── .travis.yml ├── LICENSE ├── Objective-CArmyKnife.podspec ├── Objective-CArmyKnife ├── Controls │ ├── Loading │ │ ├── OCKLoopLoadingView.h │ │ └── OCKLoopLoadingView.m │ └── Timer │ │ ├── OCKCountDownLabel.h │ │ └── OCKCountDownLabel.m ├── CoreAnimationExtensions │ └── ConvenienceAnimation │ │ ├── CAAnimation+Extensions.h │ │ └── CAAnimation+Extensions.m ├── CoreGraphicsExtensions │ └── CGRect │ │ ├── CGRect+Convenience.h │ │ └── CGRect+Convenience.m ├── FoundationExtensions │ ├── Base64 │ │ ├── NSData+Base64.h │ │ └── NSData+Base64.m │ ├── Bundle │ │ ├── NSString+Bundle.h │ │ └── NSString+Bundle.m │ ├── Calendar │ │ ├── NSDate+Calendar.h │ │ └── NSDate+Calendar.m │ ├── Edit │ │ ├── NSString+Edit.h │ │ └── NSString+Edit.m │ ├── MD5 │ │ ├── NSString+MD5.h │ │ └── NSString+MD5.m │ ├── Palindrome │ │ ├── NSString+Palindrome.h │ │ └── NSString+Palindrome.m │ ├── Regex │ │ ├── NSString+Regex.h │ │ └── NSString+Regex.m │ ├── UIDevice+Extensions.h │ ├── UIDevice+Extensions.m │ ├── UIView+Extensions.h │ ├── UIView+Extensions.m │ └── Week │ │ ├── NSDate+Week.h │ │ └── NSDate+Week.m ├── PublicHeaders │ ├── Objective-CArmyKnife.h │ └── PrintModelProperty.h ├── RuntimeExtensions │ ├── MethodSwizzConvenienceInterface │ │ ├── MethodSwizzConvenienceInterface.h │ │ └── MethodSwizzConvenienceInterface.m │ └── PrintModelProperty │ │ ├── NSArray+PrintModelProperty.h │ │ ├── NSArray+PrintModelProperty.m │ │ ├── NSDictionary+PrintModelProperty.h │ │ ├── NSDictionary+PrintModelProperty.m │ │ ├── NSObject+PrintModelProperty.h │ │ ├── NSObject+PrintModelProperty.m │ │ ├── NSSet+PrintModelProperty.h │ │ └── NSSet+PrintModelProperty.m └── UIKitExtensions │ ├── BounceAnimation │ ├── UIView+BounceAnimation.h │ └── UIView+BounceAnimation.m │ ├── ColorfulNavigationBar │ ├── NavigationBar+Colorful.h │ └── NavigationBar+Colorful.m │ ├── DataSourceCollections │ ├── NSArray+CollectionViewDataSource.h │ ├── NSArray+CollectionViewDataSource.m │ ├── NSArray+TableViewDataSource.h │ └── NSArray+TableViewDataSource.m │ ├── HexStringColor │ ├── UIColor+HexString.h │ └── UIColor+HexString.m │ ├── ImageViewAnimation │ ├── UIImageView+Animation.h │ └── UIImageView+Animation.m │ ├── LoadImage │ ├── UIImage+LoadImage.h │ └── UIImage+LoadImage.m │ ├── MoveCell │ ├── UITableView+MoveCell.h │ └── UITableView+MoveCell.m │ ├── RegisterCell │ ├── UICollectionView+RegisterCell.h │ ├── UICollectionView+RegisterCell.m │ ├── UITableView+RegisterCell.h │ └── UITableView+RegisterCell.m │ ├── RotateAnimation │ ├── UIView+RotateAnimation.h │ └── UIView+RotateAnimation.m │ ├── RoundCorner │ ├── UIView+RoundCorner.h │ └── UIView+RoundCorner.m │ ├── ShakeAnimation │ ├── UIView+ShakeAnimation.h │ └── UIView+ShakeAnimation.m │ ├── Tab+Navs │ ├── UITabBarController+UINavigationController.h │ └── UITabBarController+UINavigationController.m │ ├── TableViewSeparator │ ├── UITableView+Separator.h │ └── UITableView+Separator.m │ ├── Transform3DAnimation │ ├── UIView+Transform3DAnimation.h │ └── UIView+Transform3DAnimation.m │ └── ViewFrame │ ├── UIView+Frame.h │ └── UIView+Frame.m ├── Objective-CArmyKnifeExample.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── Objective-CArmyKnifeExample ├── AppDelegate.h ├── AppDelegate.m ├── Base.lproj │ ├── LaunchScreen.xib │ └── Main.storyboard ├── GradientViewController.h ├── GradientViewController.m ├── Images.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ ├── loading_loop.imageset │ │ ├── Contents.json │ │ └── loading_loop@2x.png │ └── loading_monkey.imageset │ │ ├── Contents.json │ │ └── loading_monkey@2x.png ├── SecondViewController.h ├── SecondViewController.m ├── Supporting Files │ ├── Info.plist │ └── main.m ├── TableViewController.h ├── TableViewController.m ├── ViewController.h └── ViewController.m └── Objective-CArmyKnifeExampleTests ├── Objective_CArmyKnifeExampleTests.m └── Supporting Files └── Info.plist /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.xccheckout 14 | *.moved-aside 15 | DerivedData 16 | *.hmap 17 | *.ipa 18 | *.xcuserstate 19 | 20 | # CocoaPods 21 | # 22 | # We recommend against adding the Pods directory to your .gitignore. However 23 | # you should judge for yourself, the pros and cons are mentioned at: 24 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 25 | # 26 | #Pods/ 27 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Michael-Lfx 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /Objective-CArmyKnife.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "Objective-CArmyKnife" 3 | s.version = "v0.4-animation.alpha.1" 4 | s.summary = "收录oc常用工具方法,提高开发效率,避免重复造轮子,欢迎分享代码" 5 | s.homepage = "http://github.com/Michael-Lfx/Objective-CArmyKnife" 6 | s.license = "MIT" 7 | s.author = { "Michael-LFX" => "cihv2@163.com" } 8 | s.platform = :ios, "7.0" 9 | s.source = { :git => "https://github.com/Michael-Lfx/Objective-CArmyKnife.git", :tag => s.version.to_s } 10 | s.source_files = "Objective-CArmyKnife", "Objective-CArmyKnife/**/*.{h,m}" 11 | s.requires_arc = true 12 | 13 | end 14 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/Controls/Loading/OCKLoopLoadingView.h: -------------------------------------------------------------------------------- 1 | @import UIKit; 2 | 3 | /** 4 | * 旋转LoopImage、LogoImage时亮时暗动画的视图 5 | * 6 | * 建议使用场合:加载数据等无预计时间的等待画面 7 | */ 8 | @interface OCKLoopLoadingView : UIView 9 | 10 | /** 11 | * 是否正在加载 12 | */ 13 | @property (assign, nonatomic, readonly, getter=isLoading) BOOL loading; 14 | 15 | /** 16 | * 设置外圈旋转图标,应该大于LogoImage,且最好为非完整圆 17 | * 18 | * @param image 外圈旋转图标 19 | */ 20 | - (void)setLoopImage:(UIImage *)image; 21 | 22 | /** 23 | * 内图标,要求小于LogoImage,最好被LoopImage包起来后还有些边距,一般是产品图标缩略图 24 | * 25 | * @param image 内圈LOGO图标 26 | */ 27 | - (void)setLogoImage:(UIImage *)image; 28 | 29 | - (void)startAnimating; 30 | 31 | - (void)stopAnimating; 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/Controls/Loading/OCKLoopLoadingView.m: -------------------------------------------------------------------------------- 1 | #import "OCKLoopLoadingView.h" 2 | 3 | @interface OCKLoopLoadingView () 4 | 5 | /** 6 | * 外圈旋转图标 7 | */ 8 | @property (weak, nonatomic, readonly) UIImageView *loopImageView; 9 | 10 | /** 11 | * 内圈LOGO图标 12 | */ 13 | @property (weak, nonatomic, readonly) UIImageView *logoImageView; 14 | 15 | /** 16 | * 默认值0度 17 | */ 18 | @property (nonatomic, assign) CGFloat loopAngle; 19 | 20 | /** 21 | * 默认值1.0,完全不透明 22 | */ 23 | @property (nonatomic, assign) CGFloat logoAlpha; 24 | 25 | /** 26 | * 默认值360/3 = 120度 27 | */ 28 | @property (nonatomic, assign) CGFloat angleStep; 29 | 30 | /** 31 | * 步进:默认值1.0/3.0 32 | */ 33 | @property (nonatomic, assign) CGFloat alphaStep; 34 | 35 | /** 36 | * 默认值 NO 37 | */ 38 | @property (assign, nonatomic, readwrite) BOOL loading; 39 | 40 | @end 41 | 42 | @implementation OCKLoopLoadingView 43 | 44 | - (instancetype)initWithFrame:(CGRect)frame { 45 | self = [super initWithFrame:frame]; 46 | if (self) { 47 | self.backgroundColor = [UIColor clearColor]; 48 | 49 | _loopImageView = [self buildImageView]; 50 | _logoImageView = [self buildImageView]; 51 | 52 | _loopAngle = 0.0; 53 | _logoAlpha = 1.0; 54 | _angleStep = 360/3; 55 | _alphaStep = 1.0/3.0; 56 | _loading = NO; 57 | } 58 | return self; 59 | } 60 | 61 | - (UIImageView *)buildImageView { 62 | UIImageView *imageView = [UIImageView new]; 63 | imageView.center = self.center; 64 | [self addSubview:imageView]; 65 | [self makeCenterEqualLayoutConstraintForView:imageView]; 66 | return imageView; 67 | } 68 | 69 | - (void)makeCenterEqualLayoutConstraintForView:(UIView *)view { 70 | view.translatesAutoresizingMaskIntoConstraints = false; 71 | [self makeCenterEqualLayoutConstraintForView:view attribute:NSLayoutAttributeCenterX]; 72 | [self makeCenterEqualLayoutConstraintForView:view attribute:NSLayoutAttributeCenterY]; 73 | } 74 | 75 | - (void)makeCenterEqualLayoutConstraintForView:(UIView *)view attribute:(NSLayoutAttribute)attr{ 76 | NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:view 77 | attribute:attr 78 | relatedBy:NSLayoutRelationEqual 79 | toItem:self 80 | attribute:attr 81 | multiplier:1 82 | constant:0]; 83 | [self addConstraint:constraint]; 84 | } 85 | 86 | - (void)loadingAnimation{ 87 | static CGFloat duration = 0.25f; 88 | self.loopAngle += self.angleStep; 89 | if (self.logoAlpha <= 0.0 || self.logoAlpha >= 1.0 ) { 90 | self.alphaStep = -self.alphaStep; 91 | } 92 | self.logoAlpha += self.alphaStep; 93 | [UIView animateWithDuration:duration delay:0.0 options:UIViewAnimationOptionCurveLinear animations:^{ 94 | [self updateLoopAngleTransform]; 95 | } completion:^(BOOL finished) { 96 | if (self.isLoading && [self superview] != nil) { 97 | [self loadingAnimation]; 98 | } else { 99 | [self removeFromSuperview]; 100 | 101 | self.loopAngle = 0.0; 102 | self.logoAlpha = 0; 103 | self.alphaStep = ABS(self.alphaStep); 104 | [self updateLoopAngleTransform]; 105 | } 106 | }]; 107 | } 108 | 109 | - (void)updateLoopAngleTransform { 110 | CGAffineTransform loopAngleTransform = CGAffineTransformMakeRotation(self.loopAngle * (M_PI / 180.0f)); 111 | self.loopImageView.transform = loopAngleTransform; 112 | self.logoImageView.alpha = self.logoAlpha; 113 | } 114 | 115 | #pragma mark - 分开接口 116 | 117 | - (void)startAnimating{ 118 | self.hidden = NO; 119 | if (self.isLoading) { 120 | return; 121 | } 122 | self.loading = YES; 123 | [self loadingAnimation]; 124 | } 125 | 126 | - (void)stopAnimating{ 127 | self.hidden = YES; 128 | self.loading = NO; 129 | } 130 | 131 | - (void)setLoopImage:(UIImage *)image { 132 | self.loopImageView.image = image; 133 | } 134 | 135 | - (void)setLogoImage:(UIImage *)image { 136 | self.logoImageView.image = image; 137 | } 138 | 139 | @end 140 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/Controls/Timer/OCKCountDownLabel.h: -------------------------------------------------------------------------------- 1 | // 2 | // WMCountDownLabel.h 3 | // WMObjCsWorld 4 | // 5 | // Created by maginawin on 15/6/17. 6 | // Copyright (c) 2015年 wendong wang. All rights reserved. 7 | // 8 | 9 | /// 支持倒计时的 UILabel, 可以拖控件用, 也可以代码初始化, 在后台继续倒计 (伪) 10 | /// 使用例子: 11 | /// [_countDownLabel setupCountDownSeconds:888]; 12 | /// [_countDownLabel start]; 13 | /// [_countDownLabel stop]; 14 | /// warning : 暂时最高支持 99 分钟 59 秒, 小时还未写, 有空补上 15 | 16 | #import 17 | 18 | @protocol OCKCountDownLabelDelegate 19 | 20 | @optional 21 | 22 | /** 23 | * @brief 倒计时开始 24 | * @param mTag : count down label's tag 25 | */ 26 | - (void)countDownLabelStart:(NSInteger)mTag; 27 | 28 | /** 29 | * @brief 倒计时结束 30 | * @param mTag : count down label's tag 31 | */ 32 | - (void)countDownLabelStop:(NSInteger)mTag; 33 | 34 | @end 35 | 36 | @interface OCKCountDownLabel : UILabel 37 | 38 | @property (weak, nonatomic) id delegate; 39 | 40 | /** 41 | * @brief 设置倒计时的倒计时间, 建议在未 start 的情况下设置 42 | * @param seconds : 倒计时间, 不要超过 99 分钟, 小时的还没有实现, 有空再来写 43 | */ 44 | - (void)setupCountDownSeconds:(NSInteger)seconds; 45 | 46 | /** 47 | * @brief 开始倒计时 48 | */ 49 | - (void)start; 50 | 51 | /** 52 | * @brief 结束倒计时 53 | */ 54 | - (void)stop; 55 | 56 | @end 57 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/Controls/Timer/OCKCountDownLabel.m: -------------------------------------------------------------------------------- 1 | // 2 | // WMCountDownLabel.m 3 | // WMObjCsWorld 4 | // 5 | // Created by maginawin on 15/6/17. 6 | // Copyright (c) 2015年 wendong wang. All rights reserved. 7 | // 8 | 9 | #import "OCKCountDownLabel.h" 10 | #import "AppDelegate.h" 11 | 12 | @interface OCKCountDownLabel() 13 | 14 | @property (nonatomic) NSInteger seconds; 15 | 16 | @property (strong, nonatomic) NSTimer* countTimer; 17 | 18 | @property (nonatomic) BOOL isStarting; 19 | @property (nonatomic) NSInteger remainSeconds; 20 | @property (nonatomic) NSDate* dateEnterBackground; 21 | 22 | @end 23 | 24 | @implementation OCKCountDownLabel 25 | 26 | - (id)initWithCoder:(NSCoder *)aDecoder { 27 | self = [super initWithCoder:aDecoder]; 28 | if (self) { 29 | 30 | } 31 | return self; 32 | } 33 | 34 | - (id)initWithFrame:(CGRect)frame { 35 | self = [super initWithFrame:frame]; 36 | if (self) { 37 | [self setupDefaultValues]; 38 | } 39 | return self; 40 | } 41 | 42 | - (void)awakeFromNib { 43 | [self setupDefaultValues]; 44 | } 45 | 46 | #pragma mark - Out methods 47 | 48 | - (void)setupCountDownSeconds:(NSInteger)seconds { 49 | _seconds = seconds; 50 | _remainSeconds = _seconds; 51 | 52 | [self showLabelTextWithSeconds:_seconds]; 53 | } 54 | 55 | - (void)start { 56 | if (!_isStarting) { 57 | _isStarting = YES; 58 | 59 | [self handleCountDown]; 60 | 61 | _countTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(handleCountDown) userInfo:nil repeats:YES]; 62 | 63 | @try { 64 | [_delegate countDownLabelStart:self.tag]; 65 | } 66 | @catch (NSException *exception) { 67 | NSLog(@"delegate countDownLabelStart exception : %@", exception); 68 | } 69 | @finally { 70 | 71 | } 72 | } 73 | } 74 | 75 | - (void)stop { 76 | _isStarting = NO; 77 | 78 | _remainSeconds = _seconds; 79 | [self showLabelTextWithSeconds:_seconds]; 80 | 81 | if (_countTimer.isValid) { 82 | [_countTimer invalidate]; 83 | _countTimer = nil; 84 | } 85 | 86 | @try { 87 | [_delegate countDownLabelStop:self.tag]; 88 | } 89 | @catch (NSException *exception) { 90 | NSLog(@"delegate countDownLabelStop exception : %@", exception); 91 | } 92 | @finally { 93 | 94 | } 95 | } 96 | 97 | - (void)pause { 98 | 99 | } 100 | 101 | #pragma mark - Assistor 102 | 103 | /** 104 | * @brief 初始化, 默认值与视图, 配置等 105 | */ 106 | - (void)setupDefaultValues { 107 | [self setupNotificationForEnterBackground]; 108 | 109 | _isStarting = NO; 110 | _seconds = 30; 111 | _remainSeconds = _seconds; 112 | 113 | [self showLabelTextWithSeconds:_seconds]; 114 | 115 | _countTimer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(handleCountDown) userInfo:nil repeats:YES]; 116 | } 117 | 118 | /** 119 | * @brief 添加后台监听, 即后台支持 120 | */ 121 | - (void)setupNotificationForEnterBackground { 122 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 123 | [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidEnterBackgroundNotification object:nil queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification *note) { 124 | _dateEnterBackground = [NSDate date]; 125 | }]; 126 | [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidBecomeActiveNotification object:nil queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification *note) { 127 | NSTimeInterval timeInterval = [[NSDate date] timeIntervalSinceDate:_dateEnterBackground]; 128 | if (_isStarting) { 129 | _remainSeconds -= timeInterval; 130 | } 131 | }]; 132 | } 133 | 134 | /** 135 | * @brief 倒计时每秒减 1 秒, 作用于 mTimer 136 | */ 137 | - (void)handleCountDown { 138 | if (!_isStarting) { 139 | [self showLabelTextWithSeconds:_seconds]; 140 | return; 141 | } 142 | 143 | // 自然结束 144 | if (_remainSeconds <= 0) { 145 | [self stop]; 146 | return; 147 | } 148 | 149 | [self showLabelTextWithSeconds:_remainSeconds]; 150 | 151 | _remainSeconds--; 152 | } 153 | 154 | /** 155 | * @brief 根据传入的秒数来改变 Label.text, 暂时只支持 mm : ss 格式, 所以不要超过 99 分钟 156 | * @param seconds : 需要显示的秒数 157 | */ 158 | - (void)showLabelTextWithSeconds:(NSInteger)seconds { 159 | NSString* minString, * secondString; 160 | 161 | NSInteger min = seconds / 60; 162 | if (min < 10) { 163 | minString = [NSString stringWithFormat:@"0%zi", min]; 164 | } else { 165 | minString = [NSString stringWithFormat:@"%zi", min]; 166 | } 167 | 168 | NSInteger second = seconds % 60; 169 | if (second < 10) { 170 | secondString = [NSString stringWithFormat:@"0%zi", second]; 171 | } else { 172 | secondString = [NSString stringWithFormat:@"%zi", second]; 173 | } 174 | 175 | NSString* time = [NSString stringWithFormat:@"%@ : %@", minString, secondString]; 176 | 177 | self.text = time; 178 | } 179 | 180 | @end 181 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/CoreAnimationExtensions/ConvenienceAnimation/CAAnimation+Extensions.h: -------------------------------------------------------------------------------- 1 | @import UIKit; 2 | 3 | @interface CAAnimation (Convenience) 4 | 5 | + (CAKeyframeAnimation *)keyframeAnimationWithKeyPath:(NSString *)keyPath values:(NSArray *)values duration:(CFTimeInterval)duration repeatCount:(float)repeatCount; 6 | 7 | + (CABasicAnimation *)basicAnimationWithKeyPath:(NSString *)keyPath fromValue:(CGFloat)fromValue toValue:(CGFloat)toValue duration:(CFTimeInterval)duration repeatCount:(float)repeatCount; 8 | 9 | @end 10 | 11 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/CoreAnimationExtensions/ConvenienceAnimation/CAAnimation+Extensions.m: -------------------------------------------------------------------------------- 1 | #import "CAAnimation+Extensions.h" 2 | 3 | #pragma mark - 便捷方法 4 | 5 | @implementation CAAnimation (Convenience) 6 | 7 | + (CAKeyframeAnimation *)keyframeAnimationWithKeyPath:(NSString *)keyPath values:(NSArray *)values duration:(CFTimeInterval)duration repeatCount:(float)repeatCount { 8 | CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:keyPath]; 9 | animation.values = values; 10 | animation.duration = duration; 11 | animation.calculationMode = kCAAnimationCubic; 12 | animation.fillMode = kCAFillModeForwards; 13 | return animation; 14 | } 15 | 16 | + (CABasicAnimation *)basicAnimationWithKeyPath:(NSString *)keyPath fromValue:(CGFloat)fromValue toValue:(CGFloat)toValue duration:(CFTimeInterval)duration repeatCount:(float)repeatCount { 17 | CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:keyPath]; 18 | animation.fromValue = [NSNumber numberWithDouble:fromValue]; 19 | animation.toValue = [NSNumber numberWithDouble:toValue]; 20 | animation.duration = duration; 21 | animation.repeatCount = repeatCount; 22 | return animation; 23 | } 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/CoreGraphicsExtensions/CGRect/CGRect+Convenience.h: -------------------------------------------------------------------------------- 1 | @import UIKit; 2 | 3 | /** 4 | * 创建一个origin = CGPointZero,size为传入size的矩形 5 | * 6 | * @param size 矩形大小 7 | * 8 | * @return 新建的矩形 9 | */ 10 | OBJC_EXPORT CGRect CGRectFromCGSize(CGSize size); 11 | 12 | /** 13 | * 根据中心点及大小创建矩形 14 | * 15 | * @param center 中心点坐标 16 | * @param size 大小 17 | * 18 | * @return 新建的矩形 19 | */ 20 | OBJC_EXPORT CGRect CGRectMakeWithCenterAndSize(CGPoint center, CGSize size); 21 | 22 | /** 23 | * 通过起点坐标及大小创建矩形 24 | * 25 | * @param origin 起点坐标 26 | * @param size 大小 27 | * 28 | * @return 新建的矩形 29 | */ 30 | OBJC_EXPORT CGRect CGRectMakeWithOriginAndSize(CGPoint origin, CGSize size); 31 | 32 | /** 33 | * 返回矩形中心点坐标 34 | * 35 | * @param rect 矩形 36 | * 37 | * @return 中心点坐标 38 | */ 39 | OBJC_EXPORT CGPoint CGRectCenter(CGRect rect); 40 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/CoreGraphicsExtensions/CGRect/CGRect+Convenience.m: -------------------------------------------------------------------------------- 1 | #import "CGRect+Convenience.h" 2 | 3 | inline CGRect CGRectFromCGSize(CGSize size) { 4 | return (CGRect){ .origin = CGPointZero, .size = size }; 5 | } 6 | 7 | inline CGRect CGRectMakeWithCenterAndSize(CGPoint center, CGSize size) { 8 | return (CGRect){ center.x - size.width * 0.5, center.y - size.height * 0.5, size }; 9 | } 10 | 11 | inline CGRect CGRectMakeWithOriginAndSize(CGPoint origin, CGSize size) { 12 | return (CGRect){ .origin = origin, .size = size }; 13 | } 14 | 15 | inline CGPoint CGRectCenter(CGRect rect) { 16 | return (CGPoint){ CGRectGetMidX(rect), CGRectGetMidY(rect) }; 17 | } 18 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/FoundationExtensions/Base64/NSData+Base64.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+Base64.h 3 | // Objective-CArmyKnifeExample 4 | // 5 | // Created by Michael on 6/15/15. 6 | // Copyright (c) 2015 Michael-lfx. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSData (Base64) 12 | 13 | - (NSString *)base64String; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/FoundationExtensions/Base64/NSData+Base64.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSData+Base64.m 3 | // Objective-CArmyKnifeExample 4 | // 5 | // Created by Michael on 6/15/15. 6 | // Copyright (c) 2015 Michael-lfx. All rights reserved. 7 | // 8 | 9 | #import "NSData+Base64.h" 10 | 11 | static char base64EncodingTable[64] = { 12 | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 13 | 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 14 | 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 15 | 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' 16 | }; 17 | 18 | @implementation NSData (Base64) 19 | 20 | - (NSString *)base64String { 21 | unsigned long ixtext, lentext; 22 | long ctremaining; 23 | unsigned char input[3], output[4]; 24 | short i, charsonline = 0, ctcopy; 25 | const unsigned char *raw; 26 | NSMutableString *result; 27 | 28 | lentext = self.length; 29 | if (lentext < 1) { 30 | return @""; 31 | } 32 | result = [NSMutableString stringWithCapacity: lentext]; 33 | raw = [self bytes]; 34 | ixtext = 0; 35 | 36 | while (true) { 37 | ctremaining = lentext - ixtext; 38 | if (ctremaining <= 0) { 39 | break; 40 | } 41 | for (i = 0; i < 3; i++) { 42 | unsigned long ix = ixtext + i; 43 | if (ix < lentext) { 44 | input[i] = raw[ix]; 45 | } 46 | else { 47 | input[i] = 0; 48 | } 49 | } 50 | output[0] = (input[0] & 0xFC) >> 2; 51 | output[1] = ((input[0] & 0x03) << 4) | ((input[1] & 0xF0) >> 4); 52 | output[2] = ((input[1] & 0x0F) << 2) | ((input[2] & 0xC0) >> 6); 53 | output[3] = input[2] & 0x3F; 54 | ctcopy = 4; 55 | switch (ctremaining) { 56 | case 1: 57 | ctcopy = 2; 58 | break; 59 | case 2: 60 | ctcopy = 3; 61 | break; 62 | } 63 | 64 | for (i = 0; i < ctcopy; i++) { 65 | [result appendString: [NSString stringWithFormat: @"%c", base64EncodingTable[output[i]]]]; 66 | } 67 | 68 | for (i = ctcopy; i < 4; i++) { 69 | [result appendString: @"="]; 70 | } 71 | 72 | ixtext += 3; 73 | charsonline += 4; 74 | 75 | if ((self.length > 0) && (charsonline >= self.length)) { 76 | charsonline = 0; 77 | } 78 | } 79 | return result; 80 | } 81 | 82 | @end 83 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/FoundationExtensions/Bundle/NSString+Bundle.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+Bundle.h 3 | // Objective-CArmyKnifeExample 4 | // 5 | // Created by Michael on 6/15/15. 6 | // Copyright (c) 2015 Michael-lfx. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSString (Bundle) 12 | 13 | /** 14 | * 读取Main Bundle中的文本文件内容 15 | 16 | 使用示例: 17 | 18 | NSString *contentOfSomeText = [NSString stringFromMainBundleWithFilename:@"readme.txt"]; 19 | 20 | * 21 | * @param filename 文件名 22 | * 23 | * @return 文件内容 24 | */ 25 | + (NSString *)stringFromMainBundleWithFilename:(NSString *)filename; 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/FoundationExtensions/Bundle/NSString+Bundle.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+Bundle.m 3 | // Objective-CArmyKnifeExample 4 | // 5 | // Created by Michael on 6/15/15. 6 | // Copyright (c) 2015 Michael-lfx. All rights reserved. 7 | // 8 | 9 | #import "NSString+Bundle.h" 10 | 11 | @implementation NSString (Bundle) 12 | 13 | + (NSString *)stringFromMainBundleWithFilename:(NSString *)filename { 14 | NSString *path = [[NSBundle mainBundle] pathForResource:filename ofType:nil]; 15 | NSString *text = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil]; 16 | return text; 17 | } 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/FoundationExtensions/Calendar/NSDate+Calendar.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSData+Calendar.h 3 | // WMObjCsWorld 4 | // 5 | // Created by maginawin on 15/6/15. 6 | // Copyright (c) 2015年 wendong wang. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | /** 12 | * 由514763292提供 13 | */ 14 | @interface NSDate (Calendar) 15 | 16 | /** 17 | * @return 当前日期的年 18 | */ 19 | - (NSInteger)year; 20 | 21 | /** 22 | * @return 当前日期的月 23 | */ 24 | - (NSInteger)month; 25 | 26 | /** 27 | * @return 当前日期的日 28 | */ 29 | - (NSInteger)day; 30 | 31 | /** 32 | * @return 当前月有多少天 33 | */ 34 | - (NSUInteger)numberOfDaysInCurrentMonth; 35 | 36 | /** 37 | * @return 当前月的第一个星期有几天 38 | */ 39 | - (NSInteger)firstWeekDayInMonth; 40 | 41 | /** 42 | * @return 一个月有几周 43 | */ 44 | - (NSUInteger)numberOfWeeksInCurrentMonth; 45 | 46 | /** 47 | * @param date : 对比日期 48 | * @return 对比日期的上一个月的日期 49 | */ 50 | - (NSDate *)lastMonthDate:(NSDate *)date; 51 | 52 | /** 53 | * @param date : 对比日期 54 | * @return 对比日期的下一个月的日期 55 | */ 56 | - (NSDate *)nextMonthDate:(NSDate *)date; 57 | 58 | @end 59 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/FoundationExtensions/Calendar/NSDate+Calendar.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSData+Calendar.m 3 | // WMObjCsWorld 4 | // 5 | // Created by maginawin on 15/6/15. 6 | // Copyright (c) 2015年 wendong wang. All rights reserved. 7 | // 8 | 9 | #import "NSDate+Calendar.h" 10 | 11 | @implementation NSDate (Calendar) 12 | 13 | - (NSInteger)year { 14 | NSCalendar* gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian]; 15 | NSDateComponents* components = [gregorian components:NSCalendarUnitYear fromDate:self]; 16 | return components.year; 17 | } 18 | 19 | - (NSInteger)month { 20 | NSCalendar* gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian]; 21 | NSDateComponents* components = [gregorian components:NSCalendarUnitMonth fromDate:self]; 22 | return components.month; 23 | } 24 | 25 | - (NSInteger)day { 26 | NSCalendar* gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian]; 27 | NSDateComponents* components = [gregorian components:NSCalendarUnitDay fromDate:self]; 28 | return components.day; 29 | } 30 | 31 | - (NSUInteger)numberOfDaysInCurrentMonth { 32 | return [[NSCalendar currentCalendar] rangeOfUnit:NSCalendarUnitDay inUnit:NSCalendarUnitMonth forDate:self].length; 33 | } 34 | 35 | - (NSInteger)firstWeekDayInMonth { 36 | NSCalendar* gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian]; 37 | [gregorian setFirstWeekday:1]; 38 | 39 | NSDateComponents* comps = [gregorian components:NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay fromDate:self]; 40 | [comps setDay:1]; 41 | NSDate* newDate = [gregorian dateFromComponents:comps]; 42 | 43 | return (8 - [gregorian ordinalityOfUnit:NSCalendarUnitWeekday inUnit:NSCalendarUnitWeekOfMonth forDate:newDate]); 44 | } 45 | 46 | - (NSUInteger)numberOfWeeksInCurrentMonth { 47 | NSUInteger weeks = 0; 48 | NSUInteger weekday = [self firstWeekDayInMonth]; 49 | if (weekday > 0) { 50 | weeks += 1; 51 | } 52 | NSUInteger monthDays = [self numberOfDaysInCurrentMonth]; 53 | weeks = weeks + (monthDays - weekday) / 7; 54 | if ((monthDays - weekday) % 7 > 0) { 55 | weeks += 1; 56 | } 57 | return weeks; 58 | } 59 | 60 | - (NSDate*)lastMonthDate:(NSDate *)date { 61 | NSCalendar* gregorian = [NSCalendar currentCalendar]; 62 | NSDateComponents* comps = [gregorian components:NSCalendarUnitWeekday | NSCalendarUnitMonth | NSCalendarUnitYear | NSCalendarUnitDay fromDate:date]; 63 | if (comps.month == 1) { 64 | [comps setMonth:12]; 65 | [comps setYear:comps.year - 1]; 66 | } else { 67 | [comps setMonth:comps.month - 1]; 68 | } 69 | return [gregorian dateFromComponents:comps]; 70 | } 71 | 72 | - (NSDate*)nextMonthDate:(NSDate *)date { 73 | NSCalendar* gregorian = [NSCalendar currentCalendar]; 74 | NSDateComponents* comps = [gregorian components:NSCalendarUnitWeekday | NSCalendarUnitMonth | NSCalendarUnitYear | NSCalendarUnitDay fromDate:date]; 75 | if (comps.month == 12) { 76 | [comps setMonth:1]; 77 | [comps setYear:comps.year + 1]; 78 | } else { 79 | [comps setMonth:comps.month + 1]; 80 | } 81 | return [gregorian dateFromComponents:comps]; 82 | } 83 | 84 | @end 85 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/FoundationExtensions/Edit/NSString+Edit.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+Edit.h 3 | // Objective-CArmyKnifeExample 4 | // 5 | // Created by Michael on 6/15/15. 6 | // Copyright (c) 2015 Michael-lfx. All rights reserved. 7 | // 8 | 9 | @import UIKit; 10 | 11 | @interface NSString (Edit) 12 | 13 | /** 14 | -(NSString*)reverse 15 | Reverses the contents of this NSString. 16 | 17 | Example: 18 | NSString *testString = @"stressed"; 19 | NSString *testReversed = [testString reverse]; // @"desserts" 20 | 21 | Returns an NSString with the original NSString's contents reversed 22 | */ 23 | - (NSString *)reverse; 24 | 25 | /** 26 | + (NSString*)stringTruncatedToWidth:withString:andFont: 27 | Generates a truncated copy of the given NSString, truncated to the desired 28 | width for the given typeface and size. 29 | 30 | width - A CGFloat representing the desired width of the truncated NSString. 31 | string - An NSString object with the content to be truncated. 32 | font - A UIFont object representing the desired typeface and font size. 33 | 34 | Example: 35 | NSString *message = @"Can you hear this long-winded message?"; 36 | UIFont *messageFont = [UIFont fontWithName:@"Marker Felt" size:32]; 37 | NSString *output = [NSString stringTruncatedToWidth:48.0f 38 | withString:message 39 | andFont:messageFont]; 40 | 41 | Returns an NSString containing the truncated string, followed by an ellipsis. 42 | */ 43 | + (NSString *)stringTruncatedToWidth:(CGFloat)width 44 | withString:(NSString *)string 45 | andFont:(UIFont *)font; 46 | 47 | /** 48 | - (NSString*)truncateToWidth:withFont: 49 | 返回适应给定字体及其大小的删减后的字符串。Generates an NSString truncated to the indicated width 50 | for a given a typeface and size. 51 | 52 | width - A CGFloat representing the desired width of the truncated NSString. 53 | font - A UIFont object representing the desired typeface and font size. 54 | 55 | Example: 56 | NSString *testString = @"This string is too damn long!" 57 | [testString truncateToWidth:64.0f 58 | withFont:[UIFont fontWithName:@"Helvetica" 59 | size:28]]; 60 | 61 | Returns an NSString containing the truncated string, followed by an ellipsis. 62 | */ 63 | - (NSString *)truncateToWidth:(CGFloat)width withFont:(UIFont *)font; 64 | 65 | @end 66 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/FoundationExtensions/Edit/NSString+Edit.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+Edit.m 3 | // Objective-CArmyKnifeExample 4 | // 5 | // Created by Michael on 6/15/15. 6 | // Copyright (c) 2015 Michael-lfx. All rights reserved. 7 | // 8 | 9 | #import "NSString+Edit.h" 10 | 11 | #pragma mark - Edit 12 | 13 | // 整合自:https://gist.github.com/dsibilly/1038500 14 | 15 | #ifndef ELLIPSIS 16 | #define ELLIPSIS @"..." 17 | #endif 18 | 19 | @implementation NSString (Edit) 20 | 21 | - (NSString *)reverse { 22 | NSMutableString *reversedString = [NSMutableString stringWithCapacity:[self length]]; 23 | 24 | for (NSUInteger i = ([self length] - 1); i > 0; i -= 1) { 25 | [reversedString appendString:[NSString stringWithFormat:@"%C", [self characterAtIndex:i]]]; 26 | } 27 | 28 | return reversedString; 29 | } 30 | 31 | + (NSString *)stringTruncatedToWidth:(CGFloat)width withString:(NSString *)string andFont:(UIFont *)font { 32 | return [string truncateToWidth:width withFont:font]; 33 | } 34 | 35 | - (NSString *)truncateToWidth:(CGFloat)width withFont:(UIFont *)font { 36 | // Obtain a mutable copy of this NSString. 37 | NSMutableString *truncatedString = [self mutableCopy]; 38 | 39 | // If this NSString is longer than the desired width, truncate. 40 | if ([self sizeWithAttributes:@{NSFontAttributeName: font}].width > width) { 41 | // Subtract an ellipsis' worth of width from the desired width to obtain the 42 | // truncation width. 43 | width -= [ELLIPSIS sizeWithAttributes:@{NSFontAttributeName: font}].width; 44 | 45 | // While the string is longer than the truncation width, remove characters 46 | // from the end of the string. 47 | NSRange range = {truncatedString.length - 1, 1}; 48 | while ([truncatedString sizeWithAttributes:@{NSFontAttributeName: font}].width > width) { 49 | [truncatedString deleteCharactersInRange:range]; 50 | range.location -= 1; 51 | } 52 | 53 | // Once truncation is complete, append an ellipsis to the end of the string. 54 | [truncatedString replaceCharactersInRange:range withString:ELLIPSIS]; 55 | } 56 | 57 | return [truncatedString copy]; 58 | } 59 | 60 | @end -------------------------------------------------------------------------------- /Objective-CArmyKnife/FoundationExtensions/MD5/NSString+MD5.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+MD5.h 3 | // Objective-CArmyKnifeExample 4 | // 5 | // Created by Michael on 6/15/15. 6 | // Copyright (c) 2015 Michael-lfx. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSString (MD5) 12 | 13 | /** 14 | - (NSString *)MD5Hash 15 | Generates an MD5 cryptographic hash of this NSString's contents 16 | 17 | Example: 18 | NSString *hash = [@"The quick brown fox jumped over the lazy dog" MD5Hash]; 19 | 20 | Returns an NSString containing the hexidecimal representation of the MD5 hash. 21 | */ 22 | - (NSString *)MD5Hash; 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/FoundationExtensions/MD5/NSString+MD5.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+MD5.m 3 | // Objective-CArmyKnifeExample 4 | // 5 | // Created by Michael on 6/15/15. 6 | // Copyright (c) 2015 Michael-lfx. All rights reserved. 7 | // 8 | 9 | #import "NSString+MD5.h" 10 | 11 | // 整合自:https://gist.github.com/dsibilly/1038500 12 | 13 | #import 14 | 15 | @implementation NSString (MD5) 16 | 17 | - (NSString*)MD5Hash { 18 | // Create a C-style pointer to the UT8-encoded contents of the NSString 19 | const char *pointer = [self UTF8String]; 20 | 21 | // Create a buffer array big enough to hold the digest 22 | unsigned char buffer[CC_MD5_DIGEST_LENGTH]; 23 | 24 | // Create 16-byte MD5 hash value, store in buffer 25 | // See: CC_MD5(3cc) manpage on OS X & iOS. 26 | CC_MD5(pointer, (CC_LONG)strlen(pointer), buffer); 27 | 28 | // Convert MD5 digest in buffer to an autoreleased NSString of hexidecimal 29 | // values. 30 | NSMutableString *result = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2]; 31 | for (int i = 0; i < CC_MD5_DIGEST_LENGTH; i += 1) { 32 | [result appendFormat:@"%02x", buffer[i]]; 33 | } 34 | 35 | return [result copy]; 36 | } 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/FoundationExtensions/Palindrome/NSString+Palindrome.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+Palindrome.h 3 | // Objective-CArmyKnifeExample 4 | // 5 | // Created by Michael on 6/15/15. 6 | // Copyright (c) 2015 Michael-lfx. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSString (Palindrome) 12 | 13 | /** 14 | - (BOOL)isPalindrome 15 | 判断字符串是否为回文串。 16 | 17 | Example: 18 | [@"HANNAH" isPalindrome]; // returns YES 19 | [@"CLAUDE" isPalindrome]; // returns NO 20 | 21 | Returns a BOOL corresponding to this NSString's palindrome status. 22 | */ 23 | - (BOOL)isPalindrome; 24 | 25 | /** 26 | + (BOOL)stringIsPalindrome: 27 | 判断字符串是否为回文串。 28 | 29 | aString - The NSString to be tested. 30 | 31 | Example: 32 | [NSString stringIsPalindrome:@"RADAR"]; // return YES 33 | 34 | Returns a BOOL cooresponding to the NSString palindrome status. 35 | */ 36 | + (BOOL)stringIsPalindrome:(NSString*)aString; 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/FoundationExtensions/Palindrome/NSString+Palindrome.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+Palindrome.m 3 | // Objective-CArmyKnifeExample 4 | // 5 | // Created by Michael on 6/15/15. 6 | // Copyright (c) 2015 Michael-lfx. All rights reserved. 7 | // 8 | 9 | #import "NSString+Palindrome.h" 10 | 11 | // 整合自:https://gist.github.com/dsibilly/1038500 12 | 13 | @implementation NSString (Palindrome) 14 | 15 | - (BOOL)isPalindrome { 16 | return [NSString stringIsPalindrome:self]; 17 | } 18 | 19 | + (BOOL)stringIsPalindrome:(NSString *)aString position:(NSInteger)position { 20 | NSString *_string = [NSString stringWithString:aString]; 21 | NSInteger _position = position; 22 | 23 | if (!_string) { 24 | return NO; 25 | } 26 | 27 | NSInteger stringLength = [_string length]; 28 | NSString *firstChar = [[_string substringToIndex:_position] substringToIndex:1]; 29 | NSString *lastChar = [[_string substringToIndex:(stringLength - 1 - _position)] substringToIndex:1]; 30 | 31 | if (_position > (stringLength / 2)) { 32 | return YES; 33 | } 34 | 35 | if (! [firstChar isEqualToString:lastChar]) { 36 | return NO; 37 | } 38 | 39 | return [NSString stringIsPalindrome:_string position:(_position + 1)]; 40 | } 41 | 42 | + (BOOL)stringIsPalindrome:(NSString *)aString { 43 | return [NSString stringIsPalindrome:aString position:0]; 44 | } 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/FoundationExtensions/Regex/NSString+Regex.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+Regex.h 3 | // Objective-CArmyKnifeExample 4 | // 5 | // Created by Michael on 6/15/15. 6 | // Copyright (c) 2015 Michael-lfx. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | /** 12 | * 整合自 https://github.com/carlbrown/RegexOnNSString 13 | */ 14 | @interface NSString (Regex) 15 | 16 | - (NSString *)stringByReplacingRegexPattern:(NSString *)regex withString:(NSString *)replacement; 17 | - (NSString *)stringByReplacingRegexPattern:(NSString *)regex withString:(NSString *)replacement caseInsensitive:(BOOL)ignoreCase; 18 | - (NSString *)stringByReplacingRegexPattern:(NSString *)regex withString:(NSString *)replacement caseInsensitive:(BOOL)ignoreCase treatAsOneLine:(BOOL)assumeMultiLine; 19 | - (NSArray *)stringsByExtractingGroupsUsingRegexPattern:(NSString *)regex; 20 | - (NSArray *)stringsByExtractingGroupsUsingRegexPattern:(NSString *)regex caseInsensitive:(BOOL) ignoreCase treatAsOneLine:(BOOL)assumeMultiLine; 21 | - (BOOL)matchesPatternRegexPattern:(NSString *)regex; 22 | - (BOOL)matchesPatternRegexPattern:(NSString *)regex caseInsensitive:(BOOL)ignoreCase treatAsOneLine:(BOOL)assumeMultiLine; 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/FoundationExtensions/Regex/NSString+Regex.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+Regex.m 3 | // Objective-CArmyKnifeExample 4 | // 5 | // Created by Michael on 6/15/15. 6 | // Copyright (c) 2015 Michael-lfx. All rights reserved. 7 | // 8 | 9 | #import "NSString+Regex.h" 10 | 11 | @implementation NSString (Regex) 12 | 13 | - (NSString *)stringByReplacingRegexPattern:(NSString *)regex withString:(NSString *)replacement caseInsensitive:(BOOL)ignoreCase { 14 | return [self stringByReplacingRegexPattern:regex withString:replacement caseInsensitive:ignoreCase treatAsOneLine:NO]; 15 | } 16 | 17 | - (NSString *)stringByReplacingRegexPattern:(NSString *)regex withString:(NSString *)replacement caseInsensitive:(BOOL)ignoreCase treatAsOneLine:(BOOL)assumeMultiLine { 18 | 19 | NSUInteger options=0; 20 | if (ignoreCase) { 21 | options = options | NSRegularExpressionCaseInsensitive; 22 | } 23 | if (assumeMultiLine) { 24 | options = options | NSRegularExpressionDotMatchesLineSeparators; 25 | } 26 | 27 | NSError *error=nil; 28 | NSRegularExpression *pattern = [NSRegularExpression regularExpressionWithPattern:regex options:options error:&error]; 29 | if (error) { 30 | NSLog(@"Error creating Regex: %@",[error description]); 31 | return nil; 32 | } 33 | 34 | NSString *retVal= [pattern stringByReplacingMatchesInString:self options:0 range:NSMakeRange(0, [self length]) withTemplate:replacement]; 35 | return retVal; 36 | } 37 | 38 | - (NSString *)stringByReplacingRegexPattern:(NSString *)regex withString:(NSString *)replacement { 39 | return [self stringByReplacingRegexPattern:regex withString:replacement caseInsensitive:NO treatAsOneLine:NO]; 40 | } 41 | 42 | - (NSArray *)stringsByExtractingGroupsUsingRegexPattern:(NSString *)regex caseInsensitive:(BOOL)ignoreCase treatAsOneLine:(BOOL)assumeMultiLine { 43 | NSUInteger options=0; 44 | if (ignoreCase) { 45 | options = options | NSRegularExpressionCaseInsensitive; 46 | } 47 | if (assumeMultiLine) { 48 | options = options | NSRegularExpressionDotMatchesLineSeparators; 49 | } 50 | 51 | NSError *error=nil; 52 | NSRegularExpression *pattern = [NSRegularExpression regularExpressionWithPattern:regex options:options error:&error]; 53 | if (error) { 54 | NSLog(@"Error creating Regex: %@",[error description]); 55 | return nil; 56 | } 57 | 58 | __block NSMutableArray *retVal = [NSMutableArray array]; 59 | [pattern enumerateMatchesInString:self options:0 range:NSMakeRange(0, [self length]) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) { 60 | //Note, we only want to return the things in parens, so we're skipping index 0 intentionally 61 | for (int i=1; i<[result numberOfRanges]; i++) { 62 | NSString *matchedString=[self substringWithRange:[result rangeAtIndex:i]]; 63 | [retVal addObject:matchedString]; 64 | } 65 | }]; 66 | return retVal; 67 | } 68 | 69 | - (NSArray *)stringsByExtractingGroupsUsingRegexPattern:(NSString *)regex { 70 | return [self stringsByExtractingGroupsUsingRegexPattern:regex caseInsensitive:NO treatAsOneLine:NO]; 71 | } 72 | 73 | - (BOOL)matchesPatternRegexPattern:(NSString *)regex caseInsensitive:(BOOL)ignoreCase treatAsOneLine:(BOOL)assumeMultiLine { 74 | NSUInteger options=0; 75 | if (ignoreCase) { 76 | options = options | NSRegularExpressionCaseInsensitive; 77 | } 78 | if (assumeMultiLine) { 79 | options = options | NSRegularExpressionDotMatchesLineSeparators; 80 | } 81 | 82 | NSError *error=nil; 83 | NSRegularExpression *pattern = [NSRegularExpression regularExpressionWithPattern:regex options:options error:&error]; 84 | if (error) { 85 | NSLog(@"Error creating Regex: %@",[error description]); 86 | return NO; //Can't possibly match an invalid Regex 87 | } 88 | 89 | return ([pattern numberOfMatchesInString:self options:0 range:NSMakeRange(0, [self length])] > 0); 90 | } 91 | 92 | - (BOOL)matchesPatternRegexPattern:(NSString *)regex { 93 | return [self matchesPatternRegexPattern:regex caseInsensitive:NO treatAsOneLine:NO]; 94 | } 95 | 96 | @end 97 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/FoundationExtensions/UIDevice+Extensions.h: -------------------------------------------------------------------------------- 1 | @import UIKit; 2 | 3 | @interface UIDevice (Identifier) 4 | 5 | /* 6 | * @method uniqueDeviceIdentifier 7 | * @description use this method when you need a unique identifier in one app. 8 | * It generates a hash from the MAC-address in combination with the bundle identifier 9 | * of your app. 10 | */ 11 | - (NSString *) uniqueDeviceIdentifier; 12 | 13 | /* 14 | * @method uniqueGlobalDeviceIdentifier 15 | * @description use this method when you need a unique global identifier to track a device 16 | * with multiple apps. as example a advertising network will use this method to track the device 17 | * from different apps. 18 | * It generates a hash from the MAC-address only. 19 | */ 20 | - (NSString *) uniqueGlobalDeviceIdentifier; 21 | 22 | - (NSString *) platformString; 23 | 24 | @end 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/FoundationExtensions/UIDevice+Extensions.m: -------------------------------------------------------------------------------- 1 | //#import "UIDevice+Extensions.h" 2 | // 3 | //#include // Per msqr 4 | //#include 5 | //#include 6 | //#include 7 | // 8 | //@interface UIDevice(Private) 9 | // 10 | //- (NSString *) macaddress; 11 | // 12 | //@end 13 | // 14 | //@implementation UIDevice (IdentifierAddition) 15 | // 16 | ////////////////////////////////////////////////////////////////////////////////// 17 | //#pragma mark - 18 | //#pragma mark Private Methods 19 | // 20 | //// Return the local MAC addy 21 | //// Courtesy of FreeBSD hackers email list 22 | //// Accidentally munged during previous update. Fixed thanks to erica sadun & mlamb. 23 | //- (NSString *) macaddress{ 24 | // 25 | // int mib[6]; 26 | // size_t len; 27 | // char *buf; 28 | // unsigned char *ptr; 29 | // struct if_msghdr *ifm; 30 | // struct sockaddr_dl *sdl; 31 | // 32 | // mib[0] = CTL_NET; 33 | // mib[1] = AF_ROUTE; 34 | // mib[2] = 0; 35 | // mib[3] = AF_LINK; 36 | // mib[4] = NET_RT_IFLIST; 37 | // 38 | // if ((mib[5] = if_nametoindex("en0")) == 0) { 39 | // printf("Error: if_nametoindex error\n"); 40 | // return NULL; 41 | // } 42 | // 43 | // if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) { 44 | // printf("Error: sysctl, take 1\n"); 45 | // return NULL; 46 | // } 47 | // 48 | // if ((buf = malloc(len)) == NULL) { 49 | // printf("Could not allocate memory. error!\n"); 50 | // return NULL; 51 | // } 52 | // 53 | // if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) { 54 | // printf("Error: sysctl, take 2"); 55 | // free(buf); 56 | // return NULL; 57 | // } 58 | // 59 | // ifm = (struct if_msghdr *)buf; 60 | // sdl = (struct sockaddr_dl *)(ifm + 1); 61 | // ptr = (unsigned char *)LLADDR(sdl); 62 | // NSString *outstring = [NSString stringWithFormat:@"%02X:%02X:%02X:%02X:%02X:%02X", 63 | // *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5)]; 64 | // free(buf); 65 | // 66 | // return outstring; 67 | //} 68 | // 69 | ////////////////////////////////////////////////////////////////////////////////// 70 | //#pragma mark - 71 | //#pragma mark Public Methods 72 | // 73 | //- (NSString *) SFAgentUniqueDeviceIdentifier{ 74 | // NSString *macaddress = [[UIDevice currentDevice] macaddress]; 75 | // NSString *bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier]; 76 | // 77 | // NSString *stringToHash = [NSString stringWithFormat:@"%@%@",macaddress,bundleIdentifier]; 78 | // NSString *uniqueIdentifier = [UtilityHelper md5:stringToHash]; 79 | // 80 | // return uniqueIdentifier; 81 | //} 82 | // 83 | //- (NSString *) uniqueGlobalDeviceIdentifier{ 84 | // NSString *macaddress = [[UIDevice currentDevice] macaddress]; 85 | // NSString *uniqueIdentifier = [UtilityHelper md5:macaddress]; 86 | // 87 | // return uniqueIdentifier; 88 | //} 89 | // 90 | // 91 | ////- (BOOL)isJailbroken 92 | ////{ 93 | //// BOOL jailbroken = NO; 94 | //// NSString *cydiaPath = @"/Applications/Cydia.app"; 95 | //// 96 | //// NSString *aptPath = @"/private/var/lib/apt/"; 97 | //// 98 | //// if ([[NSFileManager defaultManager] fileExistsAtPath:cydiaPath]) { 99 | //// 100 | //// jailbroken = YES; 101 | //// 102 | //// } 103 | //// 104 | //// if ([[NSFileManager defaultManager] fileExistsAtPath:aptPath]) { 105 | //// 106 | //// jailbroken = YES; 107 | //// 108 | //// } 109 | //// 110 | //// return jailbroken; 111 | ////} 112 | // 113 | //- (NSString *) platform 114 | //{ 115 | // size_t size; 116 | // 117 | // sysctlbyname("hw.machine", NULL, &size, NULL, 0); 118 | // 119 | // char *machine = malloc(size); 120 | // 121 | // sysctlbyname("hw.machine", machine, &size, NULL, 0); 122 | // 123 | // NSString *platform = [NSString stringWithCString:machine encoding:NSUTF8StringEncoding]; 124 | // 125 | // free(machine); 126 | // 127 | // return platform; 128 | //} 129 | // 130 | //- (NSString *) platformString 131 | //{ 132 | // NSString *platform = [self platform]; 133 | // 134 | // if ([platform isEqualToString:@"iPhone1,1"]) return @"iPhone 1G"; 135 | // if ([platform isEqualToString:@"iPhone1,2"]) return @"iPhone 3G"; 136 | // if ([platform isEqualToString:@"iPhone2,1"]) return @"iPhone 3GS"; 137 | // if ([platform isEqualToString:@"iPhone3,1"]) return @"iPhone 4"; 138 | // if ([platform isEqualToString:@"iPhone3,2"] || [platform isEqualToString:@"iPhone3,3"]) return @"iPhone 4"; 139 | // if ([platform isEqualToString:@"iPhone4,1"]) return @"iPhone 4S"; 140 | // if ([platform isEqualToString:@"iPhone5,2"]) return @"iPhone 5"; 141 | // if ([platform isEqualToString:@"iPhone5,3"] || [platform isEqualToString:@"iPhone5,4"]) { 142 | // return @"iPhone 5C";//add by tongkun 143 | // } 144 | // if ([platform isEqualToString:@"iPhone6,2"] || [platform isEqualToString:@"iPhone6,1"]) { 145 | // return @"iPhone 5S";//add by tongkun 146 | // } 147 | // if ([platform isEqualToString:@"iPod1,1"]) return @"iPod Touch 1G"; 148 | // if ([platform isEqualToString:@"iPod2,1"]) return @"iPod Touch 2G"; 149 | // if ([platform isEqualToString:@"iPod3,1"]) return @"iPod Touch 3G"; 150 | // if ([platform isEqualToString:@"iPod4,1"]) return @"iPod Touch 4G"; 151 | // if ([platform isEqualToString:@"iPod5,1"]) return @"iPod Touch 5G"; 152 | // if ([platform isEqualToString:@"iPad1,1"]) return @"iPad"; 153 | // if ([platform isEqualToString:@"iPad2,1"]) return @"iPad 2 (WiFi)"; 154 | // if ([platform isEqualToString:@"iPad2,2"]) return @"iPad 2 (GSM)"; 155 | // if ([platform isEqualToString:@"iPad2,3"]) return @"iPad 2 (CDMA)"; 156 | // if ([platform isEqualToString:@"iPad2,5"]) return @"iPad mini (WiFi)"; 157 | // if ([platform isEqualToString:@"i386"] || [platform isEqualToString:@"x86_64"]) 158 | // return @"Simulator"; 159 | // return @""; 160 | //} 161 | // 162 | //@end 163 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/FoundationExtensions/UIView+Extensions.h: -------------------------------------------------------------------------------- 1 | @import UIKit; 2 | 3 | //@interface UIView (TextSize) 4 | // 5 | //- (CGSize)boundingRectWithSize:(CGSize)size; 6 | // 7 | //@end 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/FoundationExtensions/UIView+Extensions.m: -------------------------------------------------------------------------------- 1 | #import "UIView+Extensions.h" 2 | 3 | 4 | //@implementation UILabel (TextSize) 5 | // 6 | //- (CGSize)boundingRectWithSize:(CGSize)size { 7 | // NSDictionary *attribute = @{NSFontAttributeName: self.font}; 8 | // 9 | // CGSize retSize = [self.text boundingRectWithSize:size 10 | // options:\ 11 | // NSStringDrawingTruncatesLastVisibleLine | 12 | // NSStringDrawingUsesLineFragmentOrigin | 13 | // NSStringDrawingUsesFontLeading 14 | // attributes:attribute 15 | // context:nil].size; 16 | // 17 | // return retSize; 18 | //} 19 | // 20 | // 21 | //@end 22 | 23 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/FoundationExtensions/Week/NSDate+Week.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSDate+Week.h 3 | // Objective-CArmyKnifeExample 4 | // 5 | // Created by Michael on 6/15/15. 6 | // Copyright (c) 2015 Michael-lfx. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | /** 12 | * NSLog(@"从周日开始算,今天是本周的第 %zi 天", [NSDate date].dayOfWeek) 13 | * NSLog(@"从周一开始算,今天是本周的第 %zi 天", [NSDate date].dayOfWeekStartWithMonday) 14 | */ 15 | @interface NSDate (Week) 16 | 17 | /** 18 | * 日期所属的星期数,周日为1,周六为7。如 2015年1月1日为5,即周4 19 | * 20 | * @return 日期所属的星期数 21 | */ 22 | - (NSUInteger)dayOfWeek; 23 | 24 | /** 25 | * 日期所属的星期数,周日为1,周六为7。如 2015年1月1日为4,即周4 26 | * 27 | * @return 日期所属的星期数 28 | */ 29 | - (NSUInteger)dayOfWeekStartWithMonday; 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/FoundationExtensions/Week/NSDate+Week.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSDate+Week.m 3 | // Objective-CArmyKnifeExample 4 | // 5 | // Created by Michael on 6/15/15. 6 | // Copyright (c) 2015 Michael-lfx. All rights reserved. 7 | // 8 | 9 | #import "NSDate+Week.h" 10 | 11 | static inline NSUInteger dayOfWeek(NSDate *date) { 12 | NSCalendar *calendar = [[NSCalendar alloc] 13 | initWithCalendarIdentifier:NSCalendarIdentifierGregorian]; 14 | NSDateComponents *components = [[NSDateComponents alloc] init]; 15 | NSInteger unitFlags = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitWeekday | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond; 16 | components = [calendar components:unitFlags 17 | fromDate:date]; 18 | NSUInteger weekday = [components weekday]; 19 | return weekday; 20 | } 21 | 22 | 23 | @implementation NSDate (Week) 24 | 25 | - (NSUInteger)dayOfWeek { 26 | NSUInteger weekday = dayOfWeek(self); 27 | return weekday; 28 | } 29 | 30 | - (NSUInteger)dayOfWeekStartWithMonday { 31 | NSUInteger weekday = dayOfWeek(self); 32 | return weekday - 1; 33 | } 34 | 35 | @end 36 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/PublicHeaders/Objective-CArmyKnife.h: -------------------------------------------------------------------------------- 1 | 2 | // UIKit 3 | 4 | 5 | // Foundation 6 | //#import "NSData+Extensions.h" 7 | //#import "NSObject+PrintProperty.h" 8 | //#import "NSArray+PrintProperty.h" 9 | //#import "NSSet+PrintProperty.h" 10 | //#import "NSDictionary+PrintProperty.h" 11 | //#import "NSString+Extensions.h" 12 | 13 | // Core Graphics 14 | //#import "CGRect+Extensions.h" 15 | 16 | // Core Animation 17 | //#import "CAAnimation+Extensions.h" 18 | 19 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/PublicHeaders/PrintModelProperty.h: -------------------------------------------------------------------------------- 1 | #import "NSObject+PrintProperty.h" 2 | #import "NSArray+PrintProperty.h" 3 | #import "NSSet+PrintProperty.h" 4 | #import "NSDictionary+PrintProperty.h" 5 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/RuntimeExtensions/MethodSwizzConvenienceInterface/MethodSwizzConvenienceInterface.h: -------------------------------------------------------------------------------- 1 | @import Foundation; 2 | 3 | /** 4 | * 线程安全的混写,先尝试混写实例方法,再尝试混写类方法 5 | * 全部尝试失败时,输出“混写失败:srcSelector或dstSelector对应的Method不存在” 6 | * 7 | * @param cls 需要混写的类 8 | * @param srcSelector 原始选择器 9 | * @param dstSelector 目标选择器 10 | */ 11 | extern void methodSwizz(Class cls, SEL srcSelector, SEL dstSelector); 12 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/RuntimeExtensions/MethodSwizzConvenienceInterface/MethodSwizzConvenienceInterface.m: -------------------------------------------------------------------------------- 1 | #import "MethodSwizzConvenienceInterface.h" 2 | #import 3 | 4 | void swizz(Class cls, SEL, SEL, Method, Method); 5 | BOOL swizzClassMethod(Class, SEL srcSelector, SEL); 6 | BOOL swizzInstanceMethod(Class, SEL, SEL); 7 | BOOL trySwizz(Class cls, SEL, SEL, Method, Method); 8 | 9 | inline void methodSwizz(Class cls, SEL srcSelector, SEL dstSelector) { 10 | if (swizzInstanceMethod(cls, srcSelector, dstSelector) || 11 | swizzClassMethod(cls, srcSelector, dstSelector)) 12 | { 13 | return; 14 | } 15 | printf("\n=====混写失败:srcSelector或dstSelector对应的Method不存在=====\n\n"); 16 | } 17 | 18 | #pragma mark - 私有实现 19 | 20 | inline BOOL swizzInstanceMethod(Class cls, SEL srcSelector, SEL dstSelector) { 21 | Method srcMethod = class_getInstanceMethod(cls, srcSelector); 22 | Method dstMethod = class_getInstanceMethod(cls, dstSelector); 23 | return trySwizz(cls, srcSelector, dstSelector, srcMethod, dstMethod); 24 | } 25 | 26 | inline BOOL swizzClassMethod(Class cls, SEL srcSelector, SEL dstSelector) { 27 | Method srcMethod = class_getClassMethod(cls, srcSelector); 28 | Method dstMethod = class_getClassMethod(cls, dstSelector); 29 | return trySwizz(objc_getMetaClass(class_getName(cls)), srcSelector, dstSelector, srcMethod, dstMethod); 30 | } 31 | 32 | inline BOOL trySwizz(Class cls, SEL srcSelector, SEL dstSelector, Method srcMethod, Method dstMethod) { 33 | if ((srcMethod == NULL || dstMethod == NULL)) { 34 | return FALSE; 35 | } 36 | swizz(cls, srcSelector, dstSelector, srcMethod, dstMethod); 37 | return TRUE; 38 | } 39 | 40 | inline void swizz(Class cls, SEL srcSelector, SEL dstSelector, Method srcMethod, Method dstMethod) { 41 | @synchronized(cls) { 42 | BOOL didAddMethod = class_addMethod(cls, srcSelector, method_getImplementation(dstMethod), method_getTypeEncoding(dstMethod)); 43 | if (didAddMethod) { 44 | class_replaceMethod(cls, dstSelector, method_getImplementation(srcMethod), method_getTypeEncoding(srcMethod)); 45 | } else { 46 | method_exchangeImplementations(srcMethod, dstMethod); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/RuntimeExtensions/PrintModelProperty/NSArray+PrintModelProperty.h: -------------------------------------------------------------------------------- 1 | @import Foundation; 2 | 3 | 4 | /** 5 | * 输出可便于阅读的内容 6 | */ 7 | @interface NSArray (PrintModelProperty) 8 | 9 | /** 10 | * 输出可便于阅读的内容 11 | */ 12 | - (NSString *)readableDescription; 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/RuntimeExtensions/PrintModelProperty/NSArray+PrintModelProperty.m: -------------------------------------------------------------------------------- 1 | #import "NSObject+PrintModelProperty.h" 2 | #import "NSArray+PrintModelProperty.h" 3 | 4 | 5 | @implementation NSArray (PrintModelProperty) 6 | 7 | - (NSString *)readableDescription { 8 | NSMutableString *result = [NSMutableString string]; 9 | 10 | for (id value in self) { 11 | [result appendFormat:@"%@, ", [value readableDescription]]; 12 | } 13 | deleteLastTwoCharacters(result); 14 | 15 | return [NSString stringWithFormat:@"(%@)", result]; 16 | } 17 | 18 | @end 19 | 20 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/RuntimeExtensions/PrintModelProperty/NSDictionary+PrintModelProperty.h: -------------------------------------------------------------------------------- 1 | @import Foundation; 2 | 3 | 4 | /** 5 | * 输出可便于阅读的内容 6 | */ 7 | @interface NSDictionary (PrintModelProperty) 8 | 9 | /** 10 | * 输出可便于阅读的内容 11 | */ 12 | - (NSString *)readableDescription; 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/RuntimeExtensions/PrintModelProperty/NSDictionary+PrintModelProperty.m: -------------------------------------------------------------------------------- 1 | #import "NSObject+PrintModelProperty.h" 2 | #import "NSDictionary+PrintModelProperty.h" 3 | 4 | 5 | @implementation NSDictionary (PrintModelProperty) 6 | 7 | - (NSString *)readableDescription { 8 | NSMutableString *result = [NSMutableString string]; 9 | 10 | for (id key in self) { 11 | id value = [self objectForKey:key]; 12 | [result appendFormat:@"%@ = %@; ", [key readableDescription], [value readableDescription]]; 13 | } 14 | deleteLastTwoCharacters(result); 15 | 16 | return [NSString stringWithFormat:@"{%@}", result]; 17 | } 18 | 19 | @end 20 | 21 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/RuntimeExtensions/PrintModelProperty/NSObject+PrintModelProperty.h: -------------------------------------------------------------------------------- 1 | @import Foundation; 2 | 3 | 4 | extern void deleteLastTwoCharacters(NSMutableString *string); 5 | 6 | /** 7 | * 输出可便于阅读的内容,用于Debug 8 | */ 9 | @interface NSObject (PrintModelProperty) 10 | 11 | /** 12 | * 输出对象及其继承的属性值,只支持自定义模型类 13 | * 不支持UIKit中定义的类及其派生类 14 | */ 15 | - (NSString *)autoDescription; 16 | 17 | /** 18 | * 输出可便于阅读的内容 19 | */ 20 | - (NSString *)readableDescription; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/RuntimeExtensions/PrintModelProperty/NSObject+PrintModelProperty.m: -------------------------------------------------------------------------------- 1 | #import "NSObject+PrintModelProperty.h" 2 | #import 3 | 4 | 5 | /** 6 | * 当拓展实现协议时会输出hash、superclass、description、debugDescription等属性 7 | * 干扰阅读,本函数是删除这些额外的信息 8 | */ 9 | static inline BOOL isAvoidProperty(id obj, NSString *propertyName) { 10 | NSArray *avoidSelectorNames = @[@"hash", @"superclass", @"description", @"debugDescription"]; 11 | return [avoidSelectorNames containsObject:propertyName]; 12 | } 13 | 14 | static NSString* makePropertiesAndValuesString(Class cls, id obj) { 15 | NSMutableString *result = [NSMutableString string]; 16 | 17 | uint property_count; 18 | objc_property_t *property_list = class_copyPropertyList(cls, &property_count); // 可获取到拓展实现了协议中的属性 19 | 20 | for (int i = 0; i < property_count; i++) { 21 | objc_property_t property = property_list[i]; 22 | const char *property_name = property_getName(property); // 这里假设不会返回空字符串 23 | NSString *propertyName = [NSString stringWithCString:property_name encoding:NSASCIIStringEncoding]; 24 | if (isAvoidProperty(obj, propertyName)) { 25 | continue; 26 | } 27 | id value = [obj valueForKey:propertyName]; 28 | [result appendFormat:@"%@ = %@; ", propertyName, [value readableDescription]]; 29 | } 30 | 31 | if (property_list) free(property_list); 32 | 33 | return result; 34 | } 35 | 36 | inline void deleteLastTwoCharacters(NSMutableString *string) { 37 | NSUInteger length = [string length]; 38 | if (length > 2) { 39 | [string deleteCharactersInRange:NSMakeRange(length - 2, 2)]; 40 | } 41 | } 42 | 43 | @implementation NSObject (PrintModelProperty) 44 | 45 | /** 46 | * 采用非递归实现。尝试了支持所有类,在处理UIKit时遇到取出的属性要么不存在,要么不支持KVC,故放弃。 47 | * 48 | * @return 对象本身定义的属性及其继承的属性与值组成的字符串,如:p1 = v1; p2 = v2 49 | */ 50 | - (NSString *)enumeratePropertiesAndValues { 51 | @autoreleasepool { 52 | NSMutableString *result = [NSMutableString string]; 53 | 54 | Class cls = self.class; 55 | while (cls != nil && ![cls isEqual:NSObject.class]) { 56 | [result appendString:makePropertiesAndValuesString(cls, self)]; 57 | cls = class_getSuperclass(cls); 58 | } 59 | deleteLastTwoCharacters(result); 60 | return [result copy]; 61 | } 62 | } 63 | 64 | - (NSString *)autoDescription { 65 | return [NSString stringWithFormat:@"<%@: %p; %@>", NSStringFromClass(self.class), self, [self enumeratePropertiesAndValues]]; 66 | } 67 | 68 | - (NSString *)readableDescription { 69 | return [self description]; 70 | } 71 | 72 | @end 73 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/RuntimeExtensions/PrintModelProperty/NSSet+PrintModelProperty.h: -------------------------------------------------------------------------------- 1 | @import Foundation; 2 | 3 | 4 | /** 5 | * 输出可便于阅读的内容 6 | */ 7 | @interface NSSet (PrintModelProperty) 8 | 9 | /** 10 | * 输出可便于阅读的内容 11 | */ 12 | - (NSString *)readableDescription; 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/RuntimeExtensions/PrintModelProperty/NSSet+PrintModelProperty.m: -------------------------------------------------------------------------------- 1 | #import "NSObject+PrintModelProperty.h" 2 | #import "NSSet+PrintModelProperty.h" 3 | 4 | 5 | @implementation NSSet (PrintModelProperty) 6 | 7 | - (NSString *)readableDescription { 8 | return [NSString stringWithFormat:@"{%@}", [[self allObjects] readableDescription]]; 9 | } 10 | 11 | @end 12 | 13 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/UIKitExtensions/BounceAnimation/UIView+BounceAnimation.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+BounceAnimation.h 3 | // Objective-CArmyKnifeExample 4 | // 5 | // Created by Michael on 6/12/15. 6 | // Copyright (c) 2015 Michael-lfx. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | /** 12 | * 弹性动画 13 | */ 14 | @interface UIView (BounceAnimation) 15 | 16 | - (void)defaultBounceAnimation; 17 | - (void)bounceAnimationWithValues:(NSArray *)values duration:(CGFloat)duration repeatCount:(CGFloat)repeatCount; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/UIKitExtensions/BounceAnimation/UIView+BounceAnimation.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+BounceAnimation.m 3 | // Objective-CArmyKnifeExample 4 | // 5 | // Created by Michael on 6/12/15. 6 | // Copyright (c) 2015 Michael-lfx. All rights reserved. 7 | // 8 | 9 | #import "UIView+BounceAnimation.h" 10 | 11 | @implementation UIView (BounceAnimation) 12 | 13 | - (void)defaultBounceAnimation { 14 | [self bounceAnimationWithValues:@[@1.0, @1.4, @0.9, @1.15, @0.95, @1.02, @1.0] duration:0.5 repeatCount:1]; 15 | } 16 | 17 | - (void)bounceAnimationWithValues:(NSArray *)values duration:(CGFloat)duration repeatCount:(CGFloat)repeatCount { 18 | CAKeyframeAnimation *bounceAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform.scale"]; 19 | bounceAnimation.values = values; 20 | bounceAnimation.duration = duration; 21 | bounceAnimation.repeatCount = repeatCount; 22 | bounceAnimation.calculationMode = kCAAnimationCubic; 23 | [self.layer addAnimation:bounceAnimation forKey:@"bounceAnimation"]; 24 | } 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/UIKitExtensions/ColorfulNavigationBar/NavigationBar+Colorful.h: -------------------------------------------------------------------------------- 1 | @import UIKit; 2 | 3 | /** 4 | * @brief 支持透明、多种颜色渐变的NavigationBar。 5 | * 6 | * 说明:Xcode 6.3.2中Interface Builder不支持NavigationBar的实时渲染,加上IB_DESIGNABLE与IBInspectable无任何意义 7 | * 故不做成子类,改用拓展实现 8 | */ 9 | @interface UINavigationBar (Colorful) 10 | 11 | /** 12 | * 单个颜色,与gradientColors互斥 13 | * 14 | * @see 设置一组渐变色可使用 gradientColors 属性 15 | */ 16 | @property (strong, nonatomic) UIColor *soloColor; 17 | 18 | /** 19 | * 一组(只支持两个,多了自己改代码吧)渐变颜色,从顶到底渐变。与soloColor互斥 20 | */ 21 | @property (copy, nonatomic) NSArray *gradientColors; // for Colors 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/UIKitExtensions/ColorfulNavigationBar/NavigationBar+Colorful.m: -------------------------------------------------------------------------------- 1 | #import "NavigationBar+Colorful.h" 2 | #import 3 | 4 | @implementation UINavigationBar (Colorful) 5 | 6 | #pragma mark - 公开接口 7 | 8 | static const char *kSoloColorKey = "kSoloColorKey"; 9 | 10 | - (void)setSoloColor:(UIColor *)soloColor { 11 | objc_setAssociatedObject(self, &kSoloColorKey, soloColor, OBJC_ASSOCIATION_RETAIN); 12 | UIImage *image = [self imageWithColorConstructBlock:^(CGRect *rect) { 13 | [soloColor setFill]; 14 | UIRectFill(*rect); 15 | }]; 16 | [self updateNavigationBarWithImage:image]; 17 | } 18 | 19 | - (UIColor *)soloColor { 20 | return (UIColor *)objc_getAssociatedObject(self, &kSoloColorKey); 21 | } 22 | 23 | static const char *kGradientColorsKey = "kGradientColorsKey"; 24 | #define kEndPoint 1.5 25 | 26 | - (void)setGradientColors:(NSArray *)gradientColors { 27 | objc_setAssociatedObject(self, &kGradientColorsKey, gradientColors, OBJC_ASSOCIATION_COPY); 28 | UIImage *image = [self imageWithColorConstructBlock:^(CGRect *rect) { 29 | CFMutableArrayRef colors = CFArrayCreateMutable(CFAllocatorGetDefault(), gradientColors.count, nil); 30 | for (UIColor *color in gradientColors) { 31 | CFArrayAppendValue(colors, color.CGColor); 32 | } 33 | CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 34 | CGFloat locations[] = { 0.0, 1.0 }; 35 | CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, colors, locations); 36 | CGPoint startPoint = CGPointMake(rect->size.width / 2, 0); 37 | CGPoint endPoint = CGPointMake(rect->size.width / 2, rect->size.height / kEndPoint); 38 | 39 | CGContextRef context = UIGraphicsGetCurrentContext(); 40 | CGContextSaveGState(context); 41 | CGContextAddRect(context, *rect); 42 | CGContextClip(context); 43 | CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, kCGGradientDrawsBeforeStartLocation); 44 | CGContextSetStrokeColorWithColor(context, [[UIColor clearColor] CGColor]); 45 | CGContextRestoreGState(context); 46 | if (colors) { 47 | CFRelease(colors); 48 | } 49 | }]; 50 | [self updateNavigationBarWithImage:image]; 51 | } 52 | 53 | - (NSArray *)gradientColors { 54 | return (NSArray *)objc_getAssociatedObject(self, &kGradientColorsKey); 55 | } 56 | 57 | #pragma mark - 私有接口 58 | 59 | - (UIImage *)imageWithColorConstructBlock:(void (^)(CGRect *rect))block { 60 | __block UIImage *image = nil; 61 | dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 62 | CGRect rect = CGRectMake(0, 0, 1, 1); 63 | UIGraphicsBeginImageContextWithOptions(rect.size, NO/*透明*/, 0/*device’s main screen*/); 64 | block(&rect); 65 | image = UIGraphicsGetImageFromCurrentImageContext(); 66 | UIGraphicsEndImageContext(); 67 | }); 68 | 69 | return image; 70 | } 71 | 72 | - (void)updateNavigationBarWithImage:(UIImage *)image { 73 | // setShadowImage:需要setBackgroundImage:forBarMetrics:配合 74 | [self setBackgroundImage:image forBarMetrics:UIBarMetricsDefault]; 75 | self.shadowImage = [UIImage new]; // 清除导航栏最下面那条线,它起到分割导航栏与下面控件内容的作用。 76 | } 77 | 78 | @end 79 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/UIKitExtensions/DataSourceCollections/NSArray+CollectionViewDataSource.h: -------------------------------------------------------------------------------- 1 | @import UIKit; 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/UIKitExtensions/DataSourceCollections/NSArray+CollectionViewDataSource.m: -------------------------------------------------------------------------------- 1 | #import "UIView+Extensions.h" 2 | 3 | 4 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/UIKitExtensions/DataSourceCollections/NSArray+TableViewDataSource.h: -------------------------------------------------------------------------------- 1 | @import UIKit; 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/UIKitExtensions/DataSourceCollections/NSArray+TableViewDataSource.m: -------------------------------------------------------------------------------- 1 | #import "NSArray+TableViewDataSource.h" 2 | 3 | 4 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/UIKitExtensions/HexStringColor/UIColor+HexString.h: -------------------------------------------------------------------------------- 1 | @import UIKit; 2 | 3 | @interface UIColor (HexString) 4 | 5 | + (UIColor *)colorWithHexString:(NSString *)hexString; 6 | 7 | @end 8 | 9 | 10 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/UIKitExtensions/HexStringColor/UIColor+HexString.m: -------------------------------------------------------------------------------- 1 | #import "UIColor+HexString.h" 2 | 3 | @implementation UIColor (HexString) 4 | 5 | + (UIColor *)colorWithHexString:(NSString *)hexString { 6 | NSString *colorString = [[hexString stringByReplacingOccurrencesOfString:@"#" withString:@""] uppercaseString]; 7 | CGFloat alpha, red, blue, green; 8 | switch ([colorString length]) { 9 | case 3: // #RGB 10 | alpha = 1.0f; 11 | red = [self colorComponentFrom:colorString start:0 length:1]; 12 | green = [self colorComponentFrom:colorString start:1 length:1]; 13 | blue = [self colorComponentFrom:colorString start:2 length:1]; 14 | break; 15 | case 4: // #ARGB 16 | alpha = [self colorComponentFrom:colorString start:0 length:1]; 17 | red = [self colorComponentFrom:colorString start:1 length:1]; 18 | green = [self colorComponentFrom:colorString start:2 length:1]; 19 | blue = [self colorComponentFrom:colorString start:3 length:1]; 20 | break; 21 | case 6: // #RRGGBB 22 | alpha = 1.0f; 23 | red = [self colorComponentFrom:colorString start:0 length:2]; 24 | green = [self colorComponentFrom:colorString start:2 length:2]; 25 | blue = [self colorComponentFrom:colorString start:4 length:2]; 26 | break; 27 | case 8: // #AARRGGBB 28 | alpha = [self colorComponentFrom:colorString start:0 length:2]; 29 | red = [self colorComponentFrom:colorString start:2 length:2]; 30 | green = [self colorComponentFrom:colorString start:4 length:2]; 31 | blue = [self colorComponentFrom:colorString start:6 length:2]; 32 | break; 33 | default: 34 | [NSException raise:@"Invalid color value" format:@"Color value %@ is invalid. It should be a hex value of the form #RBG, #ARGB, #RRGGBB, or #AARRGGBB", hexString]; 35 | break; 36 | } 37 | return [UIColor colorWithRed:red green:green blue:blue alpha:alpha]; 38 | } 39 | 40 | + (CGFloat)colorComponentFrom:(NSString *)string start:(NSUInteger)start length:(NSUInteger)length { 41 | NSString *substring = [string substringWithRange:NSMakeRange(start, length)]; 42 | NSString *fullHex = length == 2 ? substring : [NSString stringWithFormat:@"%@%@", substring, substring]; 43 | unsigned hexComponent; 44 | [[NSScanner scannerWithString:fullHex] scanHexInt:&hexComponent]; 45 | return hexComponent / 255.0; 46 | } 47 | 48 | @end 49 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/UIKitExtensions/ImageViewAnimation/UIImageView+Animation.h: -------------------------------------------------------------------------------- 1 | @import UIKit; 2 | 3 | #ifndef kDuration 4 | #define kDuration (0.5) 5 | #endif 6 | 7 | @interface UIImageView (Animation) 8 | 9 | #pragma mark FrameAnimation 10 | 11 | - (void)defaultFrameAnimationWithImages:(NSArray *)images; 12 | - (void)frameAnimation:(UIImageView *)icon images:(NSArray *)images duration:(CGFloat)duration repeatCount:(CGFloat)repeatCount; 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/UIKitExtensions/ImageViewAnimation/UIImageView+Animation.m: -------------------------------------------------------------------------------- 1 | #import "UIImageView+Animation.h" 2 | 3 | @implementation UIImageView (Animation) 4 | 5 | #pragma mark FrameAnimation 6 | 7 | - (void)defaultFrameAnimationWithImages:(NSArray *)images { 8 | [self frameAnimation:self images:images duration:kDuration repeatCount:1]; 9 | } 10 | 11 | - (void)frameAnimation:(UIImageView *)icon images:(NSArray *)images duration:(CGFloat)duration repeatCount:(CGFloat)repeatCount { 12 | CAKeyframeAnimation *frameAnimation = [CAKeyframeAnimation animationWithKeyPath:@"contents"]; 13 | frameAnimation.calculationMode = kCAAnimationDiscrete; 14 | frameAnimation.duration = duration; 15 | frameAnimation.values = images; 16 | frameAnimation.repeatCount = 1; 17 | frameAnimation.removedOnCompletion = false; 18 | frameAnimation.fillMode = kCAFillModeForwards; 19 | [icon.layer addAnimation:frameAnimation forKey:@"frameAnimation"]; 20 | } 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/UIKitExtensions/LoadImage/UIImage+LoadImage.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface UIImage (LoadImage) 4 | 5 | + (instancetype)loadImageFromMainBundleWithPath:(NSString *)path; 6 | 7 | + (instancetype)loadOriginalImageFromMainBundleWithPath:(NSString *)path; 8 | 9 | @end 10 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/UIKitExtensions/LoadImage/UIImage+LoadImage.m: -------------------------------------------------------------------------------- 1 | #import "UIImage+LoadImage.h" 2 | 3 | @implementation UIImage (LoadImage) 4 | 5 | //+ (instancetype)loadOriginalImageFromMainBundleWithPath:(NSString *)path { 6 | // UIImage *image = [[UIImage imageNamed:selectedImageName] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; 7 | // return image; 8 | //} 9 | 10 | @end 11 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/UIKitExtensions/MoveCell/UITableView+MoveCell.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | typedef void(^MoveCellDataSourceUpdateBlock)(NSIndexPath *dstIndexPath, NSIndexPath *srcIndexPath); 4 | 5 | @interface UITableView (MoveCell) 6 | 7 | /** 8 | * 长按拖拽TableViewCells,数据源需要在block中更新 9 | * 10 | 11 | 示例用法: 12 | 13 | @property (strong, nonatomic) NSMutableArray *dataForTableView; 14 | 15 | __weak typeof(self) weakSelf = self; 16 | 17 | [self.tableView enableDragCellWithDataSourceUpdateBlock: 18 | 19 | ^(NSIndexPath *dstIndexPath, NSIndexPath *srcIndexPath) { 20 | 21 | [weakSelf.dataForTableView exchangeObjectAtIndex:dstIndexPath.row withObjectAtIndex:srcIndexPath.row]; 22 | 23 | }]; 24 | 25 | 开始用二维指针传递数据源的方式实现,想把整个流程做得更自动化。发现要照顾的细节较多,故改成block由调用方决定数据源的同步操作。 26 | 27 | 参考自:http://www.raywenderlich.com/63089/cookbook-moving-table-view-cells-with-a-long-press-gesture 28 | 29 | TODO:UICollectionView实现类似功能 30 | TODO:拖拽超过屏幕时,调整容器,方便向上或向下移动单元格 31 | TODO:更自然的动画 32 | 33 | * @param block 更新数据源 34 | * 35 | * @return 表视图 36 | */ 37 | - (instancetype)enableDragCellWithDataSourceUpdateBlock:(__autoreleasing MoveCellDataSourceUpdateBlock)block; 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/UIKitExtensions/MoveCell/UITableView+MoveCell.m: -------------------------------------------------------------------------------- 1 | #import "UITableView+MoveCell.h" 2 | #import 3 | 4 | @implementation UITableView (MoveCell) 5 | 6 | - (instancetype)enableDragCellWithDataSourceUpdateBlock:(MoveCellDataSourceUpdateBlock)block { 7 | UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(moveCell_longPressGestureRecognizer:)]; 8 | [self addGestureRecognizer:longPress]; 9 | objc_setAssociatedObject(self, @selector(longPressGestureRecognizer), longPress, OBJC_ASSOCIATION_RETAIN); 10 | [self setMoveCellDataSourceUpdateBlock:block]; 11 | 12 | return self; 13 | } 14 | 15 | - (UILongPressGestureRecognizer *)longPressGestureRecognizer { 16 | return objc_getAssociatedObject(self, @selector(longPressGestureRecognizer)); 17 | } 18 | 19 | - (MoveCellDataSourceUpdateBlock)moveCellDataSourceUpdateBlock { 20 | return objc_getAssociatedObject(self, @selector(moveCellDataSourceUpdateBlock)); 21 | } 22 | 23 | - (void)setMoveCellDataSourceUpdateBlock:(MoveCellDataSourceUpdateBlock)moveCellDataSourceUpdateBlock { 24 | objc_setAssociatedObject(self, @selector(moveCellDataSourceUpdateBlock), moveCellDataSourceUpdateBlock, OBJC_ASSOCIATION_COPY); 25 | } 26 | 27 | - (void)moveCell_longPressGestureRecognizer:(id)sender { 28 | UILongPressGestureRecognizer *longPress = (UILongPressGestureRecognizer *)sender; 29 | if (longPress != self.longPressGestureRecognizer) { 30 | return; 31 | } 32 | UIGestureRecognizerState state = longPress.state; 33 | 34 | // 手指位置 35 | CGPoint location = [longPress locationInView:self]; 36 | // 手指位置对应的单元格索引,当按在section header等非普通cell时,索引无效 37 | NSIndexPath *indexPath = [self indexPathForRowAtPoint:location]; 38 | 39 | static UIView *snapshot = nil; ///< A snapshot of the row user is moving. 40 | static NSIndexPath *sourceIndexPath = nil; ///< Initial index path, where gesture begins. 41 | 42 | switch (state) { 43 | case UIGestureRecognizerStateBegan: { 44 | if (indexPath) { 45 | sourceIndexPath = indexPath; 46 | 47 | UITableViewCell *cell = [self cellForRowAtIndexPath:indexPath]; 48 | 49 | // Take a snapshot of the selected row using helper method. 50 | snapshot = [self snapshotFromView:cell]; 51 | 52 | // Add the snapshot as subview, centered at cell's center... 53 | __block CGPoint center = cell.center; 54 | snapshot.center = center; 55 | snapshot.alpha = 0.0; 56 | [self addSubview:snapshot]; 57 | [UIView animateWithDuration:0.25 animations:^{ 58 | 59 | // Offset for gesture location. 60 | center.y = location.y; 61 | snapshot.center = center; 62 | snapshot.transform = CGAffineTransformMakeScale(1.05, 1.05); 63 | snapshot.alpha = 0.98; 64 | cell.alpha = 0.0; 65 | 66 | } completion:^(BOOL finished) { 67 | 68 | cell.hidden = YES; 69 | 70 | }]; 71 | } 72 | break; 73 | } 74 | 75 | case UIGestureRecognizerStateChanged: { 76 | CGPoint center = snapshot.center; 77 | center.y = location.y; 78 | snapshot.center = center; 79 | 80 | // Is destination valid and is it different from source? 81 | if (indexPath && ![indexPath isEqual:sourceIndexPath]) { 82 | 83 | @autoreleasepool { 84 | // ... update data source. 85 | if ([self moveCellDataSourceUpdateBlock]) { 86 | [self moveCellDataSourceUpdateBlock](indexPath, sourceIndexPath); 87 | } 88 | } 89 | 90 | // ... move the rows. 91 | [self moveRowAtIndexPath:sourceIndexPath toIndexPath:indexPath]; 92 | 93 | // ... and update source so it is in sync with UI changes. 94 | sourceIndexPath = indexPath; 95 | } 96 | break; 97 | } 98 | 99 | default: { 100 | // Clean up. 101 | UITableViewCell *cell = [self cellForRowAtIndexPath:sourceIndexPath]; 102 | cell.hidden = NO; 103 | cell.alpha = 0.0; 104 | 105 | [UIView animateWithDuration:0.25 animations:^{ 106 | 107 | snapshot.center = cell.center; 108 | snapshot.transform = CGAffineTransformIdentity; 109 | snapshot.alpha = 0.0; 110 | cell.alpha = 1.0; 111 | 112 | } completion:^(BOOL finished) { 113 | 114 | sourceIndexPath = nil; 115 | [snapshot removeFromSuperview]; 116 | snapshot = nil; 117 | 118 | }]; 119 | 120 | break; 121 | } 122 | } 123 | [self reloadData]; 124 | } 125 | 126 | #pragma mark - Helper methods 127 | 128 | /** @brief Returns a customized snapshot of a given view. */ 129 | - (UIView *)snapshotFromView:(UIView *)inputView { 130 | 131 | // Make an image from the input view. 132 | UIGraphicsBeginImageContextWithOptions(inputView.bounds.size, NO, 0); 133 | [inputView.layer renderInContext:UIGraphicsGetCurrentContext()]; 134 | UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); 135 | UIGraphicsEndImageContext(); 136 | 137 | // Create an image view. 138 | UIView *snapshot = [[UIImageView alloc] initWithImage:image]; 139 | 140 | snapshot.layer.shadowOffset = CGSizeMake(-5.0, 0.0); 141 | snapshot.layer.shadowRadius = 5.0; 142 | snapshot.layer.shadowOpacity = 0.4; 143 | 144 | return snapshot; 145 | } 146 | 147 | @end 148 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/UIKitExtensions/RegisterCell/UICollectionView+RegisterCell.h: -------------------------------------------------------------------------------- 1 | @import UIKit; 2 | 3 | 4 | @interface UICollectionView (RegisterCell) 5 | 6 | //- (instancetype)registerNibWithName:(NSString *)name forCellReuseIdentifier:(NSString *)identifier; 7 | // 8 | //- (instancetype)registerNibWithName:(NSString *)name bundle:(NSBundle *)bundleOrNil forCellReuseIdentifier:(NSString *)identifier; 9 | 10 | @end 11 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/UIKitExtensions/RegisterCell/UICollectionView+RegisterCell.m: -------------------------------------------------------------------------------- 1 | #import "UICollectionView+RegisterCell.h" 2 | 3 | 4 | @implementation UICollectionView (RegisterCell) 5 | 6 | //- (instancetype)registerNibWithName:(NSString *)name 7 | // forCellReuseIdentifier:(NSString *)identifier { 8 | // return [self registerNibWithName:name bundle:nil forCellReuseIdentifier:identifier]; 9 | //} 10 | // 11 | //- (instancetype)registerNibWithName:(NSString *)name 12 | // bundle:(NSBundle *)bundleOrNil 13 | // forCellReuseIdentifier:(NSString *)identifier { 14 | // UINib *nib = [UINib nibWithNibName:name bundle:bundleOrNil]; 15 | //// [self registerNib:<#(UINib *)#> forSupplementaryViewOfKind:<#(NSString *)#> withReuseIdentifier:<#(NSString *)#>] 16 | // [self registerNib:nib forCellReuseIdentifier:identifier]; 17 | // return self; 18 | //} 19 | 20 | @end -------------------------------------------------------------------------------- /Objective-CArmyKnife/UIKitExtensions/RegisterCell/UITableView+RegisterCell.h: -------------------------------------------------------------------------------- 1 | @import UIKit; 2 | 3 | 4 | @interface UITableView (RegisterCell) 5 | 6 | - (instancetype)registerNibWithName:(NSString *)name forCellReuseIdentifier:(NSString *)identifier; 7 | 8 | - (instancetype)registerNibWithName:(NSString *)name bundle:(NSBundle *)bundleOrNil forCellReuseIdentifier:(NSString *)identifier; 9 | 10 | @end 11 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/UIKitExtensions/RegisterCell/UITableView+RegisterCell.m: -------------------------------------------------------------------------------- 1 | #import "UITableView+RegisterCell.h" 2 | 3 | 4 | @implementation UITableView (RegisterCell) 5 | 6 | - (instancetype)registerNibWithName:(NSString *)name 7 | forCellReuseIdentifier:(NSString *)identifier { 8 | return [self registerNibWithName:name bundle:nil forCellReuseIdentifier:identifier]; 9 | } 10 | 11 | - (instancetype)registerNibWithName:(NSString *)name 12 | bundle:(NSBundle *)bundleOrNil 13 | forCellReuseIdentifier:(NSString *)identifier { 14 | UINib *nib = [UINib nibWithNibName:name bundle:bundleOrNil]; 15 | [self registerNib:nib forCellReuseIdentifier:identifier]; 16 | return self; 17 | } 18 | 19 | @end -------------------------------------------------------------------------------- /Objective-CArmyKnife/UIKitExtensions/RotateAnimation/UIView+RotateAnimation.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+RotateAnimation.h 3 | // Objective-CArmyKnifeExample 4 | // 5 | // Created by Michael on 6/12/15. 6 | // Copyright (c) 2015 Michael-lfx. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | /** 12 | * 旋转360度动画 13 | */ 14 | @interface UIView (RotateAnimation) 15 | 16 | - (void)defaultRotateAnimation; 17 | 18 | - (void)rotateAnimationFrom:(CGFloat)fromValue to:(CGFloat)toValue duration:(CGFloat)duration repeatCount:(CGFloat)repeatCount; 19 | @end 20 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/UIKitExtensions/RotateAnimation/UIView+RotateAnimation.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+RotateAnimation.m 3 | // Objective-CArmyKnifeExample 4 | // 5 | // Created by Michael on 6/12/15. 6 | // Copyright (c) 2015 Michael-lfx. All rights reserved. 7 | // 8 | 9 | #import "UIView+RotateAnimation.h" 10 | 11 | @implementation UIView (RotateAnimation) 12 | 13 | - (void)defaultRotateAnimation { 14 | [self rotateAnimationFrom:0 to:M_PI * 2 duration:0.5 repeatCount:1]; 15 | } 16 | 17 | - (void)rotateAnimationFrom:(CGFloat)fromValue to:(CGFloat)toValue duration:(CGFloat)duration repeatCount:(CGFloat)repeatCount { 18 | CABasicAnimation *rotateAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"]; 19 | rotateAnimation.fromValue = [NSNumber numberWithDouble:fromValue]; 20 | rotateAnimation.toValue = [NSNumber numberWithDouble:toValue]; 21 | rotateAnimation.duration = duration; 22 | rotateAnimation.repeatCount = repeatCount; 23 | [self.layer addAnimation:rotateAnimation forKey:@"rotation360"]; 24 | } 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/UIKitExtensions/RoundCorner/UIView+RoundCorner.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+RoundCorner.h 3 | // Objective-CArmyKnifeExample 4 | // 5 | // Created by Michael on 6/12/15. 6 | // Copyright (c) 2015 Michael-lfx. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | /** 12 | * CALayer mask属性实现遮罩效果 13 | 14 | // 整合自:https://gist.github.com/bobmoff/5967220 15 | 16 | */ 17 | @interface UIView (RoundCorner) 18 | 19 | - (void)setRoundCorners:(UIRectCorner)corners radius:(CGSize)size; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/UIKitExtensions/RoundCorner/UIView+RoundCorner.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+RoundCorner.m 3 | // Objective-CArmyKnifeExample 4 | // 5 | // Created by Michael on 6/12/15. 6 | // Copyright (c) 2015 Michael-lfx. All rights reserved. 7 | // 8 | 9 | #import "UIView+RoundCorner.h" 10 | 11 | @implementation UIView (RoundCorner) 12 | 13 | - (void)setRoundCorners:(UIRectCorner)corners radius:(CGSize)size { 14 | UIBezierPath* maskPath = [UIBezierPath bezierPathWithRoundedRect:self.bounds byRoundingCorners:corners cornerRadii:size]; 15 | 16 | CAShapeLayer* maskLayer = [CAShapeLayer new]; 17 | maskLayer.frame = self.bounds; 18 | maskLayer.path = maskPath.CGPath; 19 | 20 | self.layer.mask = maskLayer; 21 | } 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/UIKitExtensions/ShakeAnimation/UIView+ShakeAnimation.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+ShakeAnimation.h 3 | // Objective-CArmyKnifeExample 4 | // 5 | // Created by Michael on 6/12/15. 6 | // Copyright (c) 2015 Michael-lfx. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface UIView (ShakeAnimation) 12 | 13 | - (void)defaultShakeAnimation; 14 | 15 | - (void)shakeAnimationWithMargin:(CGFloat)margin duration:(CGFloat)duration repeatCount:(CGFloat)repeatCount; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/UIKitExtensions/ShakeAnimation/UIView+ShakeAnimation.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+ShakeAnimation.m 3 | // Objective-CArmyKnifeExample 4 | // 5 | // Created by Michael on 6/12/15. 6 | // Copyright (c) 2015 Michael-lfx. All rights reserved. 7 | // 8 | 9 | #import "UIView+ShakeAnimation.h" 10 | 11 | @implementation UIView (ShakeAnimation) 12 | 13 | - (void)defaultShakeAnimation { 14 | [self shakeAnimationWithMargin:10 duration:0.20 repeatCount:2]; 15 | } 16 | 17 | - (void)shakeAnimationWithMargin:(CGFloat)margin duration:(CGFloat)duration repeatCount:(CGFloat)repeatCount { 18 | CAKeyframeAnimation *shakeAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform.translation.x"]; 19 | shakeAnimation.values = @[@0, @(-margin), @(margin), @0]; 20 | shakeAnimation.duration = duration; 21 | shakeAnimation.repeatCount = repeatCount; 22 | [self.layer addAnimation:shakeAnimation forKey:@"shakeAnimationWithX"]; 23 | } 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/UIKitExtensions/Tab+Navs/UITabBarController+UINavigationController.h: -------------------------------------------------------------------------------- 1 | @import UIKit; 2 | 3 | 4 | /** 5 | * 快速实现以UITabBarController为基础结构的View骨架 6 | * 建议用法: 7 | * AppleViewController *appleViewController = [AppleViewController new]; 8 | * BoyViewController *boyViewController = [BananaViewController new]; 9 | * CarViewController *carViewController = [CarViewController new]; 10 | * DogViewController *dogViewController = [DogViewController new]; 11 | * 12 | * self.window.rootViewController = 13 | * [[[[UITabBarController new] 14 | * addChildViewController:appleViewController withNavigationControllerTitle:@"苹果" ...] 15 | * addChildViewController:boyViewController withNavigationControllerTitle:@"男孩" ...] 16 | * addChildViewController:carViewController withNavigationControllerTitle:@"车" ...] 17 | * addChildViewController:dogViewController withNavigationControllerTitle:@"狗" ...]; 18 | */ 19 | @interface UITabBarController (UINavigationController) 20 | 21 | /** 22 | * 用UINavigationController将childViewController并加到UITabBarController中 23 | * 24 | * @param childViewController 当成UINavigationController rootViewController的UIViewController 25 | * @param title 导航栏标题 26 | * @param tabBarItemImage 默认TabBarItem图片 27 | * 28 | * @return 持有装载childViewController的UINavigationController的UITabBarController实例 29 | */ 30 | - (instancetype)addChildViewController:(UIViewController *)childViewController 31 | withNavigationControllerTitle:(NSString *)title 32 | tabBarItemImage:(UIImage *)tabBarItemImage; 33 | /** 34 | * 用UINavigationController将childViewController并加到UITabBarController中 35 | * 36 | * @param childViewController 当成UINavigationController rootViewController的UIViewController 37 | * @param title 导航栏标题 38 | * @param tabBarItemImage 默认TabBarItem图片 39 | * @param tabBarItemSelectedImage 选中时TabBarItem图片 40 | * 41 | * @return 持有装载childViewController的UINavigationController的UITabBarController实例 42 | */ 43 | - (instancetype)addChildViewController:(UIViewController *)childViewController 44 | withNavigationControllerTitle:(NSString *)title 45 | tabBarItemImage:(UIImage *)tabBarItemImage 46 | tabBarItemSelectedImage:(UIImage *)tabBarItemSelectedImage; 47 | 48 | @end 49 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/UIKitExtensions/Tab+Navs/UITabBarController+UINavigationController.m: -------------------------------------------------------------------------------- 1 | #import "UITabBarController+UINavigationController.h" 2 | 3 | 4 | @implementation UITabBarController (UINavigationController) 5 | 6 | - (instancetype)addChildViewController:(UIViewController *)childViewController 7 | withNavigationControllerTitle:(NSString *)title 8 | tabBarItemImage:(UIImage *)tabBarItemImage { 9 | return [self addChildViewController:childViewController 10 | withNavigationControllerTitle:title 11 | tabBarItemImage:tabBarItemImage 12 | tabBarItemSelectedImage:nil]; 13 | } 14 | 15 | - (instancetype)addChildViewController:(UIViewController *)childViewController 16 | withNavigationControllerTitle:(NSString *)title 17 | tabBarItemImage:(UIImage *)tabBarItemImage 18 | tabBarItemSelectedImage:(UIImage *)tabBarItemSelectedImage { 19 | UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:childViewController]; 20 | childViewController.title = title; 21 | childViewController.tabBarItem.image = tabBarItemImage; 22 | childViewController.tabBarItem.selectedImage = tabBarItemSelectedImage; 23 | [self addChildViewController:navigationController]; 24 | return self; 25 | } 26 | 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/UIKitExtensions/TableViewSeparator/UITableView+Separator.h: -------------------------------------------------------------------------------- 1 | @import UIKit; 2 | 3 | @interface UITableView (Separator) 4 | 5 | /** 6 | 消除Plain样式下的多余分割线 7 | 8 | Plain样式,行数不够填满整个屏幕时,无数据的Cell也会有分割线,此函数就是处理它们的 9 | 10 | * @return 当前表视图 11 | */ 12 | - (instancetype)clearExtraSeparator; 13 | 14 | /** 15 | * 让Cell分割线等于屏幕宽度 16 | 17 | 建议用法: 18 | 19 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 20 | 21 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"TestCell" forIndexPath:indexPath]; 22 | 23 | [tableView makeSeparatorEqualToScreenWidthWithCell:cell] 24 | 25 | // Configure the cell... 26 | 27 | .textLabel 28 | 29 | .text = self.dataForTableView[indexPath.row]; 30 | 31 | return cell; 32 | 33 | } 34 | 35 | 做这个功能时,我走了些弯路。想过混写dealloc,但是ARC下混写dealloc,听说有较大副作用。 36 | 37 | https://github.com/zhigang1992/ZGParallelView/issues/8 38 | 39 | >Overriding -dealloc in a category is fatal; it replaces the existing implementation, ensuring that every UITableView deallocation will, at best, leak and, at worst, crash or yield undefined behavior. 40 | 41 | >As well, you shouldn't be overriding the KVO methods, either (or any other method of the original class) in a category. 42 | 43 | ``` 44 | + (void)load 45 | { 46 | Method origMethod = class_getInstanceMethod([self class], NSSelectorFromString(@"dealloc")); 47 | Method newMethod = class_getInstanceMethod([self class], @selector(my_dealloc)); 48 | method_exchangeImplementations(origMethod, newMethod); 49 | } 50 | 51 | - (void)my_dealloc 52 | { 53 | // do your logic here 54 | 55 | 56 | //this calls original dealloc method 57 | [self my_dealloc]; 58 | } 59 | ``` 60 | * 61 | * @return 当前UITableViewCell 62 | */ 63 | - (UITableViewCell *)makeSeparatorEqualToScreenWidthWithCell:(UITableViewCell *)cell; 64 | 65 | @end 66 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/UIKitExtensions/TableViewSeparator/UITableView+Separator.m: -------------------------------------------------------------------------------- 1 | #import "UITableView+Separator.h" 2 | #import "MethodSwizzConvenienceInterface.h" 3 | #import 4 | 5 | @implementation UITableView (Separator) 6 | 7 | - (instancetype)clearExtraSeparator { 8 | UIView *maskView = [[UIView alloc] init]; 9 | maskView.backgroundColor = self.backgroundColor; 10 | self.tableFooterView = maskView; 11 | return self; 12 | } 13 | 14 | /** 15 | * 参考 http://stackoverflow.com/questions/25770119/ios-8-uitableview-separator-inset-0-not-working/25772101#25772101 16 | */ 17 | - (UITableViewCell *)makeSeparatorEqualToScreenWidthWithCell:(UITableViewCell *)cell { 18 | static dispatch_once_t onceToken; 19 | dispatch_once(&onceToken, ^{ 20 | self.separatorInset = UIEdgeInsetsMake(0, 0, 0, 0); 21 | }); 22 | cell.layoutMargins = UIEdgeInsetsZero; 23 | cell.preservesSuperviewLayoutMargins = NO; 24 | return cell; 25 | } 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/UIKitExtensions/Transform3DAnimation/UIView+Transform3DAnimation.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+Transform3DAnimation.h 3 | // Objective-CArmyKnifeExample 4 | // 5 | // Created by Michael on 6/12/15. 6 | // Copyright (c) 2015 Michael-lfx. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface UIView (Transform3DAnimation) 12 | 13 | /** 14 | * 旋转动画效果 15 | 16 | 使用示例(每个单元格出现时旋转): 17 | 18 | - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath { 19 | 20 | [cell transform3DAnimation]; 21 | 22 | } 23 | * 24 | * @return 当前视图 25 | */ 26 | - (instancetype)transform3DAnimation; 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/UIKitExtensions/Transform3DAnimation/UIView+Transform3DAnimation.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+Transform3DAnimation.m 3 | // Objective-CArmyKnifeExample 4 | // 5 | // Created by Michael on 6/12/15. 6 | // Copyright (c) 2015 Michael-lfx. All rights reserved. 7 | // 8 | 9 | #import "UIView+Transform3DAnimation.h" 10 | 11 | @implementation UIView (Transform3DAnimation) 12 | 13 | - (instancetype)transform3DAnimation { 14 | CATransform3D transform; 15 | transform = CATransform3DMakeRotation( (90.0 * M_PI) / 180, 0.0, 0.7, 0.4); 16 | transform.m34 = 1.0/ -600; 17 | 18 | self.layer.shadowColor = [[UIColor blackColor]CGColor]; 19 | self.layer.shadowOffset = CGSizeMake(10, 10); 20 | self.alpha = 0; 21 | 22 | self.layer.transform = transform; 23 | self.layer.anchorPoint = CGPointMake(0, 0.5); 24 | 25 | [UIView animateWithDuration:0.3 animations:^{ 26 | self.layer.transform = CATransform3DIdentity; 27 | self.alpha = 1; 28 | self.layer.shadowOffset = CGSizeMake(0, 0); 29 | self.frame = CGRectMake(0, self.frame.origin.y, self.frame.size.width, self.frame.size.height); 30 | 31 | }]; 32 | 33 | return self; 34 | } 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/UIKitExtensions/ViewFrame/UIView+Frame.h: -------------------------------------------------------------------------------- 1 | @import UIKit; 2 | 3 | @interface UIView (Frame) 4 | 5 | - (CGFloat)height; 6 | - (CGFloat)width; 7 | - (CGFloat)x; 8 | - (CGFloat)y; 9 | - (void)setHeight:(CGFloat)height; 10 | - (void)setWidth:(CGFloat)width; 11 | - (void)setX:(CGFloat)x; 12 | - (void)setY:(CGFloat)y; 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /Objective-CArmyKnife/UIKitExtensions/ViewFrame/UIView+Frame.m: -------------------------------------------------------------------------------- 1 | #import "UIView+Frame.h" 2 | 3 | 4 | @implementation UIView (Frame) 5 | 6 | - (CGFloat)x { 7 | return self.frame.origin.x; 8 | } 9 | 10 | - (void)setX:(CGFloat)newX { 11 | CGRect frame = self.frame; 12 | frame.origin.x = newX; 13 | self.frame = frame; 14 | } 15 | 16 | - (CGFloat)y { 17 | return self.frame.origin.y; 18 | } 19 | 20 | - (void)setY:(CGFloat)newY { 21 | CGRect frame = self.frame; 22 | frame.origin.y = newY; 23 | self.frame = frame; 24 | } 25 | 26 | - (CGFloat)width { 27 | return self.frame.size.width; 28 | } 29 | 30 | - (void)setWidth:(CGFloat)newWidth { 31 | CGRect frame = self.frame; 32 | frame.size.width = newWidth; 33 | self.frame = frame; 34 | } 35 | 36 | - (CGFloat)height { 37 | return self.frame.size.height; 38 | } 39 | 40 | - (void)setHeight:(CGFloat)newHeight { 41 | CGRect frame = self.frame; 42 | frame.size.height = newHeight; 43 | self.frame = frame; 44 | } 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /Objective-CArmyKnifeExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Objective-CArmyKnifeExample/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // Objective-CArmyKnifeExample 4 | // 5 | // Created by Michael on 6/8/15. 6 | // Copyright (c) 2015 Michael-lfx. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /Objective-CArmyKnifeExample/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // Objective-CArmyKnifeExample 4 | // 5 | // Created by Michael on 6/8/15. 6 | // Copyright (c) 2015 Michael-lfx. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | #import "NSDate+Week.h" 11 | 12 | @interface AppDelegate () 13 | 14 | @end 15 | 16 | @implementation AppDelegate 17 | 18 | 19 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 20 | // Override point for customization after application 21 | // [UIViewController printViewControllerHierarchySwitchOn]; 22 | return YES; 23 | } 24 | 25 | - (void)applicationWillResignActive:(UIApplication *)application { 26 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 27 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 28 | } 29 | 30 | - (void)applicationDidEnterBackground:(UIApplication *)application { 31 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 33 | // if (i % 2) { 34 | // [UIViewController printViewControllerHierarchySwitchOff]; 35 | // } else { 36 | // [UIViewController printViewControllerHierarchySwitchOn]; 37 | // } 38 | i++; 39 | } 40 | 41 | static int i = 0; 42 | 43 | - (void)applicationWillEnterForeground:(UIApplication *)application { 44 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 45 | } 46 | 47 | - (void)applicationDidBecomeActive:(UIApplication *)application { 48 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 49 | } 50 | 51 | - (void)applicationWillTerminate:(UIApplication *)application { 52 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 53 | } 54 | 55 | @end 56 | -------------------------------------------------------------------------------- /Objective-CArmyKnifeExample/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /Objective-CArmyKnifeExample/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 28 | 37 | 38 | 39 | 40 | 41 | 50 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 109 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | -------------------------------------------------------------------------------- /Objective-CArmyKnifeExample/GradientViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // GradientViewController.h 3 | // Objective-CArmyKnifeExample 4 | // 5 | // Created by Michael on 6/12/15. 6 | // Copyright (c) 2015 Michael-lfx. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface GradientViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Objective-CArmyKnifeExample/GradientViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // GradientViewController.m 3 | // Objective-CArmyKnifeExample 4 | // 5 | // Created by Michael on 6/12/15. 6 | // Copyright (c) 2015 Michael-lfx. All rights reserved. 7 | // 8 | 9 | #import "GradientViewController.h" 10 | 11 | @interface GradientViewController () 12 | 13 | @end 14 | 15 | @implementation GradientViewController 16 | 17 | - (void)viewDidLoad { 18 | [super viewDidLoad]; 19 | // Do any additional setup after loading the view. 20 | 21 | 22 | CAGradientLayer *gradientLayer = [CAGradientLayer layer]; 23 | gradientLayer.frame = self.view.bounds; 24 | gradientLayer.startPoint = CGPointMake(0.5, 0); 25 | gradientLayer.endPoint = CGPointMake(0.5, 1); 26 | 27 | gradientLayer.colors = @[(__bridge id)[UIColor blueColor].CGColor, (__bridge id)[UIColor redColor].CGColor]; 28 | 29 | gradientLayer.locations = @[@0.3, @0.8]; 30 | 31 | [self.view.layer addSublayer:gradientLayer]; 32 | } 33 | 34 | - (void)didReceiveMemoryWarning { 35 | [super didReceiveMemoryWarning]; 36 | // Dispose of any resources that can be recreated. 37 | } 38 | 39 | /* 40 | #pragma mark - Navigation 41 | 42 | // In a storyboard-based application, you will often want to do a little preparation before navigation 43 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 44 | // Get the new view controller using [segue destinationViewController]. 45 | // Pass the selected object to the new view controller. 46 | } 47 | */ 48 | 49 | @end 50 | -------------------------------------------------------------------------------- /Objective-CArmyKnifeExample/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "29x29", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "29x29", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "40x40", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "40x40", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "76x76", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "76x76", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /Objective-CArmyKnifeExample/Images.xcassets/loading_loop.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x", 10 | "filename" : "loading_loop@2x.png" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Objective-CArmyKnifeExample/Images.xcassets/loading_loop.imageset/loading_loop@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Michael-Lfx/Objective-CUtils/a8aa9261ed796745d0fd324bc94bdbc1ac632fd8/Objective-CArmyKnifeExample/Images.xcassets/loading_loop.imageset/loading_loop@2x.png -------------------------------------------------------------------------------- /Objective-CArmyKnifeExample/Images.xcassets/loading_monkey.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x", 10 | "filename" : "loading_monkey@2x.png" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Objective-CArmyKnifeExample/Images.xcassets/loading_monkey.imageset/loading_monkey@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Michael-Lfx/Objective-CUtils/a8aa9261ed796745d0fd324bc94bdbc1ac632fd8/Objective-CArmyKnifeExample/Images.xcassets/loading_monkey.imageset/loading_monkey@2x.png -------------------------------------------------------------------------------- /Objective-CArmyKnifeExample/SecondViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // SecondViewController.h 3 | // Objective-CArmyKnifeExample 4 | // 5 | // Created by Michael on 6/11/15. 6 | // Copyright (c) 2015 Michael-lfx. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface SecondViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Objective-CArmyKnifeExample/SecondViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // SecondViewController.m 3 | // Objective-CArmyKnifeExample 4 | // 5 | // Created by Michael on 6/11/15. 6 | // Copyright (c) 2015 Michael-lfx. All rights reserved. 7 | // 8 | 9 | #import "SecondViewController.h" 10 | #import "UIView+Frame.h" 11 | #import "UIView+Transform3DAnimation.h" 12 | 13 | @interface SecondViewController () 14 | 15 | @property (strong, nonatomic) UIRefreshControl *refreshControl; 16 | @property (strong, nonatomic) UITableView *tableView; 17 | @property (strong, nonatomic) NSArray *array; 18 | 19 | @end 20 | 21 | @implementation SecondViewController 22 | 23 | - (void)viewDidLoad { 24 | [super viewDidLoad]; 25 | 26 | self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds]; 27 | [self.view addSubview:self.tableView]; 28 | 29 | self.refreshControl = [UIRefreshControl new]; 30 | [self.refreshControl addTarget:self action:@selector(refreshView:) forControlEvents:UIControlEventValueChanged]; 31 | [self.refreshControl setAttributedTitle:[[NSAttributedString alloc] initWithString:@"松手更新数据"]]; 32 | [self.tableView addSubview:self.refreshControl]; 33 | self.tableView.dataSource = self; 34 | self.tableView.delegate = self; 35 | 36 | self.tableView.tableHeaderView = [UIView new]; 37 | 38 | self.array = @[@"hello", @"world", @"objc", @"programming", @"language",@"hello", @"world", @"objc", @"programming", @"language",@"hello", @"world", @"objc", @"programming", @"language",@"hello", @"world", @"objc", @"programming", @"language",@"hello", @"world", @"objc", @"programming", @"language",@"hello", @"world", @"objc", @"programming", @"language",@"hello", @"world", @"objc", @"programming", @"language",@"hello", @"world", @"objc", @"programming", @"language"]; 39 | 40 | UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(foregroundTapped:)]; 41 | tap.delegate = self; 42 | 43 | UIScrollView *view = self.tableView; 44 | [view addGestureRecognizer:tap]; 45 | } 46 | 47 | - (void)foregroundTapped:(UIGestureRecognizer *)reg { 48 | NSLog(@"%@", reg); 49 | } 50 | 51 | - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch 52 | { 53 | // 若为UITableViewCellContentView(即点击了tableViewCell),则不截获Touch事件 54 | if ([NSStringFromClass([touch.view class]) isEqualToString:@"UITableViewCellContentView"]) { 55 | return NO; 56 | } 57 | return YES; 58 | } 59 | 60 | 61 | - (void)refreshView:(UIRefreshControl *)refresh { 62 | refresh.attributedTitle = [[NSAttributedString alloc] initWithString:@"更新数据中..."]; 63 | 64 | NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; 65 | [formatter setDateFormat:@"MMM d, h:mm a"]; 66 | NSString *lastUpdated = [NSString stringWithFormat:@"上次更新日期 %@", 67 | [formatter stringFromDate:[NSDate date]]]; 68 | refresh.attributedTitle = [[NSAttributedString alloc] initWithString:lastUpdated]; 69 | 70 | [self.tableView reloadData]; 71 | [refresh endRefreshing]; 72 | } 73 | 74 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 75 | // Return the number of rows in the section. 76 | return self.array.count; 77 | } 78 | 79 | 80 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 81 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"TestCell"]; 82 | if (!cell) { 83 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"TestCell"]; 84 | } 85 | 86 | 87 | // Configure the cell... 88 | cell.textLabel 89 | .text = self.array[indexPath.row]; 90 | 91 | return cell; 92 | } 93 | 94 | - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath { 95 | [cell transform3DAnimation]; 96 | } 97 | 98 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 99 | NSLog(@"%@", NSStringFromSelector(_cmd)); 100 | } 101 | 102 | @end 103 | -------------------------------------------------------------------------------- /Objective-CArmyKnifeExample/Supporting Files/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | zh_CN 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | io.github.michael-lfx.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /Objective-CArmyKnifeExample/Supporting Files/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // Objective-CArmyKnifeExample 4 | // 5 | // Created by Michael on 6/8/15. 6 | // Copyright (c) 2015 Michael-lfx. All rights reserved. 7 | // 8 | #import 9 | #import "AppDelegate.h" 10 | 11 | int main(int argc, char * argv[]) { 12 | @autoreleasepool { 13 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Objective-CArmyKnifeExample/TableViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // TableViewController.h 3 | // Objective-CArmyKnifeExample 4 | // 5 | // Created by Michael on 6/10/15. 6 | // Copyright (c) 2015 Michael-lfx. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface TableViewController : UITableViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Objective-CArmyKnifeExample/TableViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // TableViewController.m 3 | // Objective-CArmyKnifeExample 4 | // 5 | // Created by Michael on 6/10/15. 6 | // Copyright (c) 2015 Michael-lfx. All rights reserved. 7 | // 8 | 9 | #import "TableViewController.h" 10 | #import "UITableView+Separator.h" 11 | #import "UITableView+MoveCell.h" 12 | 13 | @interface TableViewController () 14 | @property (strong, nonatomic) NSMutableArray *dataForTableView; 15 | @end 16 | 17 | @implementation TableViewController 18 | 19 | - (void)viewDidLoad { 20 | [super viewDidLoad]; 21 | 22 | // Uncomment the following line to preserve selection between presentations. 23 | // self.clearsSelectionOnViewWillAppear = NO; 24 | 25 | // Uncomment the following line to display an Edit button in the navigation bar for this view controller. 26 | // self.navigationItem.rightBarButtonItem = self.editButtonItem; 27 | NSArray *array = @[@"hello", @"world", @"objc", @"programming", @"language",@"hello", @"world", @"objc", @"programming", @"language",@"hello", @"world", @"objc", @"programming", @"language",@"hello", @"world", @"objc", @"programming", @"language",@"hello", @"world", @"objc", @"programming", @"language",@"hello", @"world", @"objc", @"programming", @"language",@"hello", @"world", @"objc", @"programming", @"language",@"hello", @"world", @"objc", @"programming", @"language"]; 28 | 29 | id x = [array mutableCopy]; 30 | NSLog(@"%p", x); 31 | self.dataForTableView = [array mutableCopy]; 32 | [self.tableView clearExtraSeparator]; 33 | __weak typeof(self) weakSelf = self; 34 | [self.tableView enableDragCellWithDataSourceUpdateBlock:^(NSIndexPath *dstIndexPath, NSIndexPath *srcIndexPath) { 35 | [weakSelf.dataForTableView exchangeObjectAtIndex:dstIndexPath.row withObjectAtIndex:srcIndexPath.row]; 36 | }]; 37 | 38 | } 39 | 40 | - (void)didReceiveMemoryWarning { 41 | [super didReceiveMemoryWarning]; 42 | // Dispose of any resources that can be recreated. 43 | } 44 | 45 | #pragma mark - Table view data source 46 | 47 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 48 | // Return the number of rows in the section. 49 | return self.dataForTableView.count; 50 | } 51 | 52 | 53 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 54 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"TestCell" forIndexPath:indexPath]; 55 | 56 | [tableView makeSeparatorEqualToScreenWidthWithCell:cell] 57 | // Configure the cell... 58 | .textLabel 59 | .text = self.dataForTableView[indexPath.row]; 60 | 61 | return cell; 62 | } 63 | 64 | 65 | /* 66 | // Override to support conditional editing of the table view. 67 | - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { 68 | // Return NO if you do not want the specified item to be editable. 69 | return YES; 70 | } 71 | */ 72 | 73 | /* 74 | // Override to support editing the table view. 75 | - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { 76 | if (editingStyle == UITableViewCellEditingStyleDelete) { 77 | // Delete the row from the data source 78 | [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade]; 79 | } else if (editingStyle == UITableViewCellEditingStyleInsert) { 80 | // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view 81 | } 82 | } 83 | */ 84 | 85 | /* 86 | // Override to support rearranging the table view. 87 | - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath { 88 | } 89 | */ 90 | 91 | /* 92 | // Override to support conditional rearranging of the table view. 93 | - (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath { 94 | // Return NO if you do not want the item to be re-orderable. 95 | return YES; 96 | } 97 | */ 98 | 99 | /* 100 | #pragma mark - Navigation 101 | 102 | // In a storyboard-based application, you will often want to do a little preparation before navigation 103 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 104 | // Get the new view controller using [segue destinationViewController]. 105 | // Pass the selected object to the new view controller. 106 | } 107 | */ 108 | 109 | @end 110 | -------------------------------------------------------------------------------- /Objective-CArmyKnifeExample/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // Objective-CArmyKnifeExample 4 | // 5 | // Created by Michael on 6/8/15. 6 | // Copyright (c) 2015 Michael-lfx. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /Objective-CArmyKnifeExample/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // Objective-CArmyKnifeExample 4 | // 5 | // Created by Michael on 6/8/15. 6 | // Copyright (c) 2015 Michael-lfx. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "OCKLoopLoadingView.h" 11 | #import "NavigationBar+Colorful.h" 12 | #import "UIView+BounceAnimation.h" 13 | 14 | @interface ViewController () 15 | 16 | @property (strong, nonatomic) OCKLoopLoadingView *loadingView; 17 | @property (weak, nonatomic) IBOutlet UIView *viewForBounceAnimation; 18 | @property (strong, nonatomic) NSString *hello; 19 | 20 | @end 21 | 22 | @implementation ViewController 23 | 24 | - (void)viewDidLoad { 25 | [super viewDidLoad]; 26 | // Do any additional setup after loading the view, typically from a nib. 27 | 28 | OCKLoopLoadingView *loading = [[OCKLoopLoadingView alloc] initWithFrame:CGRectMake(50, 100, 100, 100)]; 29 | [self.view addSubview:loading]; 30 | self.loadingView = loading; 31 | 32 | // 透明 33 | self.navigationController.navigationBar.soloColor = [UIColor clearColor]; 34 | // 渐变 35 | // UIColor *topColor = [[UIColor blueColor] colorWithAlphaComponent:1]; 36 | // UIColor *bottomColor = [[UIColor blueColor] colorWithAlphaComponent:0.2]; 37 | // self.navigationController.navigationBar.gradientColors = @[topColor, bottomColor]; 38 | self.title = @"我就是测试"; 39 | [self setHello:nil]; 40 | self.hello = nil; 41 | } 42 | 43 | - (void)viewDidAppear:(BOOL)animated { 44 | [super viewDidAppear:animated]; 45 | 46 | [self.loadingView setLoopImage:[UIImage imageNamed:@"loading_loop"]]; 47 | [self.loadingView setLogoImage:[UIImage imageNamed:@"loading_monkey"]]; 48 | [self.loadingView startAnimating]; 49 | } 50 | 51 | - (IBAction)tapBounceAnimationBtn:(id)sender { 52 | [self.viewForBounceAnimation defaultBounceAnimation]; 53 | [self.loadingView stopAnimating]; 54 | } 55 | 56 | @end 57 | 58 | 59 | -------------------------------------------------------------------------------- /Objective-CArmyKnifeExampleTests/Objective_CArmyKnifeExampleTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // Objective_CArmyKnifeExampleTests.m 3 | // Objective-CArmyKnifeExampleTests 4 | // 5 | // Created by Michael on 6/8/15. 6 | // Copyright (c) 2015 Michael-lfx. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface Objective_CArmyKnifeExampleTests : XCTestCase 13 | 14 | @end 15 | 16 | @implementation Objective_CArmyKnifeExampleTests 17 | 18 | - (void)setUp { 19 | [super setUp]; 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | - (void)tearDown { 24 | // Put teardown code here. This method is called after the invocation of each test method in the class. 25 | [super tearDown]; 26 | } 27 | 28 | - (void)testExample { 29 | // This is an example of a functional test case. 30 | XCTAssert(YES, @"Pass"); 31 | } 32 | 33 | - (void)testPerformanceExample { 34 | // This is an example of a performance test case. 35 | [self measureBlock:^{ 36 | // Put the code you want to measure the time of here. 37 | }]; 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /Objective-CArmyKnifeExampleTests/Supporting Files/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | io.github.michael-lfx.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | --------------------------------------------------------------------------------