├── .gitignore ├── LICENSE.md ├── PlayCornerRadius.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── PlayCornerRadius ├── 1.jpg ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Info.plist ├── ViewController.h ├── ViewController.m ├── YYCache │ └── YYCache │ │ ├── YYCache.h │ │ ├── YYCache.m │ │ ├── YYDiskCache.h │ │ ├── YYDiskCache.m │ │ ├── YYKVStorage.h │ │ ├── YYKVStorage.m │ │ ├── YYMemoryCache.h │ │ └── YYMemoryCache.m ├── YYFPSLabel │ ├── YYFPSLabel.h │ ├── YYFPSLabel.m │ ├── YYWeakProxy.h │ └── YYWeakProxy.m ├── YYImage │ └── YYImage │ │ ├── YYAnimatedImageView.h │ │ ├── YYAnimatedImageView.m │ │ ├── YYFrameImage.h │ │ ├── YYFrameImage.m │ │ ├── YYImage.h │ │ ├── YYImage.m │ │ ├── YYImageCoder.h │ │ ├── YYImageCoder.m │ │ ├── YYSpriteSheetImage.h │ │ └── YYSpriteSheetImage.m ├── YYWebImage │ └── YYWebImage │ │ ├── Categories │ │ ├── CALayer+YYWebImage.h │ │ ├── CALayer+YYWebImage.m │ │ ├── MKAnnotationView+YYWebImage.h │ │ ├── MKAnnotationView+YYWebImage.m │ │ ├── UIButton+YYWebImage.h │ │ ├── UIButton+YYWebImage.m │ │ ├── UIImage+YYWebImage.h │ │ ├── UIImage+YYWebImage.m │ │ ├── UIImageView+YYWebImage.h │ │ ├── UIImageView+YYWebImage.m │ │ ├── _YYWebImageSetter.h │ │ └── _YYWebImageSetter.m │ │ ├── YYImageCache.h │ │ ├── YYImageCache.m │ │ ├── YYWebImage.h │ │ ├── YYWebImageManager.h │ │ ├── YYWebImageManager.m │ │ ├── YYWebImageOperation.h │ │ └── YYWebImageOperation.m └── main.m ├── README.md └── XWCornerRadius ├── UIView+XWAddForRoundedCorner.h └── UIView+XWAddForRoundedCorner.m /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | .DS_Store 3 | .svn 4 | */build/* 5 | *.pbxuser 6 | !default.pbxuser 7 | *.mode1v3 8 | !default.mode1v3 9 | *.mode2v3 10 | !default.mode2v3 11 | *.perspectivev3 12 | !default.perspectivev3 13 | #*.xcworkspace 14 | xcuserdata 15 | *.moved-aside 16 | DerivedData 17 | .idea/ 18 | *.hmap 19 | *.xccheckout 20 | 21 | #CocoaPods 22 | #Pods 23 | 24 | 25 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /PlayCornerRadius.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /PlayCornerRadius/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wazrx/XWCornerRadius/1e68416d5d2593bcaf0851d59ce90dbf6dcfe436/PlayCornerRadius/1.jpg -------------------------------------------------------------------------------- /PlayCornerRadius/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // PlayCornerRadius 4 | // 5 | // Created by 肖文 on 2017/1/18. 6 | // Copyright © 2017年 肖文. 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 | -------------------------------------------------------------------------------- /PlayCornerRadius/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // PlayCornerRadius 4 | // 5 | // Created by 肖文 on 2017/1/18. 6 | // Copyright © 2017年 肖文. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | 24 | - (void)applicationWillResignActive:(UIApplication *)application { 25 | // 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. 26 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 27 | } 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 | } 34 | 35 | 36 | - (void)applicationWillEnterForeground:(UIApplication *)application { 37 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 38 | } 39 | 40 | 41 | - (void)applicationDidBecomeActive:(UIApplication *)application { 42 | // 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. 43 | } 44 | 45 | 46 | - (void)applicationWillTerminate:(UIApplication *)application { 47 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 48 | } 49 | 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /PlayCornerRadius/Assets.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 | } -------------------------------------------------------------------------------- /PlayCornerRadius/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /PlayCornerRadius/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /PlayCornerRadius/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /PlayCornerRadius/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // PlayCornerRadius 4 | // 5 | // Created by 肖文 on 2017/1/18. 6 | // Copyright © 2017年 肖文. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /PlayCornerRadius/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // PlayCornerRadius 4 | // 5 | // Created by 肖文 on 2017/1/18. 6 | // Copyright © 2017年 肖文. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "UIView+XWAddForRoundedCorner.h" 11 | #import "YYWebImage.h" 12 | #import "YYFPSLabel.h" 13 | 14 | CGFloat XWScreenWidthRatio(){ 15 | static CGFloat ratio; 16 | static dispatch_once_t onceToken; 17 | dispatch_once(&onceToken, ^{ 18 | ratio = [UIScreen mainScreen].bounds.size.width / 375.0f; 19 | }); 20 | return ratio; 21 | } 22 | 23 | #define widthRatio(_f_) (_f_) * XWScreenWidthRatio() 24 | 25 | static inline CGSize XWSizeMake(CGFloat width, CGFloat height){ 26 | CGSize size; size.width = widthRatio(width); size.height = widthRatio(height); return size; 27 | } 28 | 29 | static inline CGPoint XWPointMake(CGFloat x, CGFloat y){ 30 | CGPoint point; point.x = widthRatio(x); point.y = widthRatio(y); return point; 31 | } 32 | 33 | static inline CGRect XWRectMake(CGFloat x, CGFloat y, CGFloat width, CGFloat height){ 34 | CGRect rect; 35 | rect.origin.x = widthRatio(x); rect.origin.y = widthRatio(y); 36 | rect.size.width = widthRatio(width); rect.size.height = widthRatio(height); 37 | return rect; 38 | } 39 | 40 | @interface XWTestRoundedCell : UITableViewCell 41 | 42 | + (XWTestRoundedCell *)xw_cellWithTableView:(__weak UITableView *)tableView imageURL:(NSString *)imageURL; 43 | 44 | @end 45 | 46 | @implementation XWTestRoundedCell{ 47 | __weak UITableView *_tableView; 48 | UIView *_headerView; 49 | UIView *_nameLabel; 50 | UILabel *_aLabel; 51 | UIColor *_backColor; 52 | NSMutableArray *_circles; 53 | } 54 | 55 | + (XWTestRoundedCell *)xw_cellWithTableView:(UITableView *__weak)tableView imageURL:(NSString *)imageURL{ 56 | static NSString *identifier = @"XWTestRoundedCellIdentifier"; 57 | XWTestRoundedCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier]; 58 | if (!cell) { 59 | cell = [[XWTestRoundedCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier]; 60 | cell->_tableView = tableView; 61 | [cell _xw_initailizeUI]; 62 | } 63 | [cell _xw_updateWithURL:imageURL]; 64 | return cell; 65 | } 66 | 67 | - (void)_xw_initailizeUI{ 68 | UIColor *backColor = [UIColor whiteColor]; 69 | _backColor = backColor; 70 | self.contentView.backgroundColor = backColor; 71 | self.selectionStyle = UITableViewCellSelectionStyleNone; 72 | self.layer.opaque = YES; 73 | _headerView = ({ 74 | UIView *headerView = [UIView new]; 75 | headerView.layer.opaque = YES; 76 | headerView.backgroundColor = [UIColor whiteColor]; 77 | headerView.bounds = XWRectMake(0, 0, 100, 100); 78 | headerView.center = XWPointMake(55, 60); 79 | headerView.layer.contentsGravity = kCAGravityResizeAspectFill; 80 | headerView.layer.masksToBounds = YES; 81 | [headerView xw_roundedCornerWithCornerRadii:XWSizeMake(40, 40) cornerColor:backColor corners:UIRectCornerAllCorners borderColor:[UIColor redColor] borderWidth:widthRatio(2)]; 82 | [self.contentView addSubview:headerView]; 83 | headerView; 84 | }); 85 | 86 | _nameLabel = ({ 87 | UILabel *label = [UILabel new]; 88 | label.font = [UIFont systemFontOfSize:widthRatio(9)]; 89 | label.text = @"wazrx"; 90 | label.backgroundColor = [UIColor blackColor]; 91 | label.textColor = [UIColor whiteColor]; 92 | label.textAlignment = 1; 93 | label.layer.opaque = YES; 94 | label.layer.masksToBounds = YES; 95 | label.bounds = XWRectMake(0, 0, 80, 20); 96 | label.center = XWPointMake(50, 90); 97 | [_headerView addSubview:label]; 98 | label; 99 | }); 100 | _aLabel = ({ 101 | UILabel *label = [UILabel new]; 102 | label.font = [UIFont systemFontOfSize:widthRatio(14)]; 103 | label.text = @"这是测试文字"; 104 | label.backgroundColor = [UIColor redColor]; 105 | label.textColor = [UIColor blackColor]; 106 | label.textAlignment = 1; 107 | label.layer.masksToBounds = YES; 108 | label.layer.opaque = YES; 109 | label.bounds = XWRectMake(0, 0, 150, 30); 110 | label.center = XWPointMake(200, 60); 111 | [label xw_roundedCornerWithRadius:widthRatio(15) cornerColor:backColor corners:UIRectCornerTopLeft | UIRectCornerBottomRight]; 112 | [self.contentView addSubview:label]; 113 | label; 114 | }); 115 | 116 | _circles = [NSMutableArray arrayWithCapacity:10]; 117 | for (int i = 0; i < 10; i ++) { 118 | UIView *littleCircle = [UIView new]; 119 | littleCircle.layer.opaque = YES; 120 | littleCircle.backgroundColor = [UIColor blueColor]; 121 | littleCircle.bounds = XWRectMake(0, 0, 15, 15); 122 | littleCircle.center = XWPointMake(110 + 7.5 + 20 * i, 30); 123 | [littleCircle xw_roundedCornerWithRadius:widthRatio(7.5) cornerColor:backColor]; 124 | [self.contentView addSubview:littleCircle]; 125 | [_circles addObject:littleCircle]; 126 | } 127 | } 128 | 129 | - (void)_xw_updateWithURL:(NSString *)imageURL{ 130 | [_headerView.layer yy_setImageWithURL:[NSURL URLWithString:imageURL] options:YYWebImageOptionSetImageWithFadeAnimation]; 131 | } 132 | 133 | - (void)setSelected:(BOOL)selected animated:(BOOL)animated{ 134 | if (self.selected == selected) return; 135 | [self _xw_colorWithSelectedorHighlighted:selected]; 136 | [super setSelected:selected animated:animated]; 137 | } 138 | 139 | - (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated{ 140 | if (self.selected) return; 141 | if (self.highlighted == highlighted) return; 142 | [self _xw_colorWithSelectedorHighlighted:highlighted]; 143 | [super setHighlighted:highlighted animated:animated]; 144 | } 145 | 146 | - (void)_xw_colorWithSelectedorHighlighted:(BOOL)flag{ 147 | UIColor *color = flag ? [UIColor lightGrayColor] : _backColor; 148 | self.contentView.backgroundColor = color; 149 | [_headerView xw_roundedCornerWithCornerRadii:XWSizeMake(40, 40) cornerColor:color corners:UIRectCornerAllCorners borderColor:[UIColor redColor] borderWidth:widthRatio(2)]; 150 | [_aLabel xw_roundedCornerWithRadius:widthRatio(15) cornerColor:color corners:UIRectCornerTopLeft | UIRectCornerBottomRight]; 151 | [_circles enumerateObjectsUsingBlock:^(UIView * _Nonnull littleCircle, NSUInteger idx, BOOL * _Nonnull stop) { 152 | [littleCircle xw_roundedCornerWithRadius:widthRatio(7.5) cornerColor:color]; 153 | }]; 154 | } 155 | 156 | @end 157 | 158 | @interface ViewController () 159 | 160 | @end 161 | 162 | @implementation ViewController 163 | 164 | - (void)viewDidLoad { 165 | [super viewDidLoad]; 166 | UITableView *tableView = [UITableView new]; 167 | tableView.rowHeight = widthRatio(120); 168 | tableView.backgroundColor = [UIColor whiteColor]; 169 | tableView.dataSource = self; 170 | tableView.delegate = self; 171 | tableView.frame = self.view.bounds; 172 | [self.view addSubview:tableView]; 173 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 174 | [YYFPSLabel xw_addFPSLableOnWidnow]; 175 | }); 176 | } 177 | 178 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ 179 | return 200; 180 | } 181 | 182 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ 183 | return [XWTestRoundedCell xw_cellWithTableView:tableView imageURL:[NSString stringWithFormat:@"https://oepjvpu5g.qnssl.com/avatar%zd.jpg", indexPath.row % 20]]; 184 | } 185 | 186 | @end 187 | -------------------------------------------------------------------------------- /PlayCornerRadius/YYCache/YYCache/YYCache.h: -------------------------------------------------------------------------------- 1 | // 2 | // YYCache.h 3 | // YYCache 4 | // 5 | // Created by ibireme on 15/2/13. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | 14 | #if __has_include() 15 | FOUNDATION_EXPORT double YYCacheVersionNumber; 16 | FOUNDATION_EXPORT const unsigned char YYCacheVersionString[]; 17 | #import 18 | #import 19 | #import 20 | #elif __has_include() 21 | #import 22 | #import 23 | #import 24 | #else 25 | #import "YYMemoryCache.h" 26 | #import "YYDiskCache.h" 27 | #import "YYKVStorage.h" 28 | #endif 29 | 30 | NS_ASSUME_NONNULL_BEGIN 31 | 32 | 33 | /** 34 | `YYCache` is a thread safe key-value cache. 35 | 36 | It use `YYMemoryCache` to store objects in a small and fast memory cache, 37 | and use `YYDiskCache` to persisting objects to a large and slow disk cache. 38 | See `YYMemoryCache` and `YYDiskCache` for more information. 39 | */ 40 | @interface YYCache : NSObject 41 | 42 | /** The name of the cache, readonly. */ 43 | @property (copy, readonly) NSString *name; 44 | 45 | /** The underlying memory cache. see `YYMemoryCache` for more information.*/ 46 | @property (strong, readonly) YYMemoryCache *memoryCache; 47 | 48 | /** The underlying disk cache. see `YYDiskCache` for more information.*/ 49 | @property (strong, readonly) YYDiskCache *diskCache; 50 | 51 | /** 52 | Create a new instance with the specified name. 53 | Multiple instances with the same name will make the cache unstable. 54 | 55 | @param name The name of the cache. It will create a dictionary with the name in 56 | the app's caches dictionary for disk cache. Once initialized you should not 57 | read and write to this directory. 58 | @result A new cache object, or nil if an error occurs. 59 | */ 60 | - (nullable instancetype)initWithName:(NSString *)name; 61 | 62 | /** 63 | Create a new instance with the specified path. 64 | Multiple instances with the same name will make the cache unstable. 65 | 66 | @param path Full path of a directory in which the cache will write data. 67 | Once initialized you should not read and write to this directory. 68 | @result A new cache object, or nil if an error occurs. 69 | */ 70 | - (nullable instancetype)initWithPath:(NSString *)path NS_DESIGNATED_INITIALIZER; 71 | 72 | /** 73 | Convenience Initializers 74 | Create a new instance with the specified name. 75 | Multiple instances with the same name will make the cache unstable. 76 | 77 | @param name The name of the cache. It will create a dictionary with the name in 78 | the app's caches dictionary for disk cache. Once initialized you should not 79 | read and write to this directory. 80 | @result A new cache object, or nil if an error occurs. 81 | */ 82 | + (nullable instancetype)cacheWithName:(NSString *)name; 83 | 84 | /** 85 | Convenience Initializers 86 | Create a new instance with the specified path. 87 | Multiple instances with the same name will make the cache unstable. 88 | 89 | @param path Full path of a directory in which the cache will write data. 90 | Once initialized you should not read and write to this directory. 91 | @result A new cache object, or nil if an error occurs. 92 | */ 93 | + (nullable instancetype)cacheWithPath:(NSString *)path; 94 | 95 | - (instancetype)init UNAVAILABLE_ATTRIBUTE; 96 | + (instancetype)new UNAVAILABLE_ATTRIBUTE; 97 | 98 | #pragma mark - Access Methods 99 | ///============================================================================= 100 | /// @name Access Methods 101 | ///============================================================================= 102 | 103 | /** 104 | Returns a boolean value that indicates whether a given key is in cache. 105 | This method may blocks the calling thread until file read finished. 106 | 107 | @param key A string identifying the value. If nil, just return NO. 108 | @return Whether the key is in cache. 109 | */ 110 | - (BOOL)containsObjectForKey:(NSString *)key; 111 | 112 | /** 113 | Returns a boolean value with the block that indicates whether a given key is in cache. 114 | This method returns immediately and invoke the passed block in background queue 115 | when the operation finished. 116 | 117 | @param key A string identifying the value. If nil, just return NO. 118 | @param block A block which will be invoked in background queue when finished. 119 | */ 120 | - (void)containsObjectForKey:(NSString *)key withBlock:(nullable void(^)(NSString *key, BOOL contains))block; 121 | 122 | /** 123 | Returns the value associated with a given key. 124 | This method may blocks the calling thread until file read finished. 125 | 126 | @param key A string identifying the value. If nil, just return nil. 127 | @return The value associated with key, or nil if no value is associated with key. 128 | */ 129 | - (nullable id)objectForKey:(NSString *)key; 130 | 131 | /** 132 | Returns the value associated with a given key. 133 | This method returns immediately and invoke the passed block in background queue 134 | when the operation finished. 135 | 136 | @param key A string identifying the value. If nil, just return nil. 137 | @param block A block which will be invoked in background queue when finished. 138 | */ 139 | - (void)objectForKey:(NSString *)key withBlock:(nullable void(^)(NSString *key, id object))block; 140 | 141 | /** 142 | Sets the value of the specified key in the cache. 143 | This method may blocks the calling thread until file write finished. 144 | 145 | @param object The object to be stored in the cache. If nil, it calls `removeObjectForKey:`. 146 | @param key The key with which to associate the value. If nil, this method has no effect. 147 | */ 148 | - (void)setObject:(nullable id)object forKey:(NSString *)key; 149 | 150 | /** 151 | Sets the value of the specified key in the cache. 152 | This method returns immediately and invoke the passed block in background queue 153 | when the operation finished. 154 | 155 | @param object The object to be stored in the cache. If nil, it calls `removeObjectForKey:`. 156 | @param block A block which will be invoked in background queue when finished. 157 | */ 158 | - (void)setObject:(nullable id)object forKey:(NSString *)key withBlock:(nullable void(^)(void))block; 159 | 160 | /** 161 | Removes the value of the specified key in the cache. 162 | This method may blocks the calling thread until file delete finished. 163 | 164 | @param key The key identifying the value to be removed. If nil, this method has no effect. 165 | */ 166 | - (void)removeObjectForKey:(NSString *)key; 167 | 168 | /** 169 | Removes the value of the specified key in the cache. 170 | This method returns immediately and invoke the passed block in background queue 171 | when the operation finished. 172 | 173 | @param key The key identifying the value to be removed. If nil, this method has no effect. 174 | @param block A block which will be invoked in background queue when finished. 175 | */ 176 | - (void)removeObjectForKey:(NSString *)key withBlock:(nullable void(^)(NSString *key))block; 177 | 178 | /** 179 | Empties the cache. 180 | This method may blocks the calling thread until file delete finished. 181 | */ 182 | - (void)removeAllObjects; 183 | 184 | /** 185 | Empties the cache. 186 | This method returns immediately and invoke the passed block in background queue 187 | when the operation finished. 188 | 189 | @param block A block which will be invoked in background queue when finished. 190 | */ 191 | - (void)removeAllObjectsWithBlock:(void(^)(void))block; 192 | 193 | /** 194 | Empties the cache with block. 195 | This method returns immediately and executes the clear operation with block in background. 196 | 197 | @warning You should not send message to this instance in these blocks. 198 | @param progress This block will be invoked during removing, pass nil to ignore. 199 | @param end This block will be invoked at the end, pass nil to ignore. 200 | */ 201 | - (void)removeAllObjectsWithProgressBlock:(nullable void(^)(int removedCount, int totalCount))progress 202 | endBlock:(nullable void(^)(BOOL error))end; 203 | 204 | @end 205 | 206 | NS_ASSUME_NONNULL_END 207 | -------------------------------------------------------------------------------- /PlayCornerRadius/YYCache/YYCache/YYCache.m: -------------------------------------------------------------------------------- 1 | // 2 | // YYCache.m 3 | // YYCache 4 | // 5 | // Created by ibireme on 15/2/13. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import "YYCache.h" 13 | #import "YYMemoryCache.h" 14 | #import "YYDiskCache.h" 15 | 16 | @implementation YYCache 17 | 18 | - (instancetype) init { 19 | NSLog(@"Use \"initWithName\" or \"initWithPath\" to create YYCache instance."); 20 | return [self initWithPath:@""]; 21 | } 22 | 23 | - (instancetype)initWithName:(NSString *)name { 24 | if (name.length == 0) return nil; 25 | NSString *cacheFolder = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject]; 26 | NSString *path = [cacheFolder stringByAppendingPathComponent:name]; 27 | return [self initWithPath:path]; 28 | } 29 | 30 | - (instancetype)initWithPath:(NSString *)path { 31 | if (path.length == 0) return nil; 32 | YYDiskCache *diskCache = [[YYDiskCache alloc] initWithPath:path]; 33 | if (!diskCache) return nil; 34 | NSString *name = [path lastPathComponent]; 35 | YYMemoryCache *memoryCache = [YYMemoryCache new]; 36 | memoryCache.name = name; 37 | 38 | self = [super init]; 39 | _name = name; 40 | _diskCache = diskCache; 41 | _memoryCache = memoryCache; 42 | return self; 43 | } 44 | 45 | + (instancetype)cacheWithName:(NSString *)name { 46 | return [[self alloc] initWithName:name]; 47 | } 48 | 49 | + (instancetype)cacheWithPath:(NSString *)path { 50 | return [[self alloc] initWithPath:path]; 51 | } 52 | 53 | - (BOOL)containsObjectForKey:(NSString *)key { 54 | return [_memoryCache containsObjectForKey:key] || [_diskCache containsObjectForKey:key]; 55 | } 56 | 57 | - (void)containsObjectForKey:(NSString *)key withBlock:(void (^)(NSString *key, BOOL contains))block { 58 | if (!block) return; 59 | 60 | if ([_memoryCache containsObjectForKey:key]) { 61 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 62 | block(key, YES); 63 | }); 64 | } else { 65 | [_diskCache containsObjectForKey:key withBlock:block]; 66 | } 67 | } 68 | 69 | - (id)objectForKey:(NSString *)key { 70 | id object = [_memoryCache objectForKey:key]; 71 | if (!object) { 72 | object = [_diskCache objectForKey:key]; 73 | if (object) { 74 | [_memoryCache setObject:object forKey:key]; 75 | } 76 | } 77 | return object; 78 | } 79 | 80 | - (void)objectForKey:(NSString *)key withBlock:(void (^)(NSString *key, id object))block { 81 | if (!block) return; 82 | id object = [_memoryCache objectForKey:key]; 83 | if (object) { 84 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 85 | block(key, object); 86 | }); 87 | } else { 88 | [_diskCache objectForKey:key withBlock:^(NSString *key, id object) { 89 | if (object && ![_memoryCache objectForKey:key]) { 90 | [_memoryCache setObject:object forKey:key]; 91 | } 92 | block(key, object); 93 | }]; 94 | } 95 | } 96 | 97 | - (void)setObject:(id)object forKey:(NSString *)key { 98 | [_memoryCache setObject:object forKey:key]; 99 | [_diskCache setObject:object forKey:key]; 100 | } 101 | 102 | - (void)setObject:(id)object forKey:(NSString *)key withBlock:(void (^)(void))block { 103 | [_memoryCache setObject:object forKey:key]; 104 | [_diskCache setObject:object forKey:key withBlock:block]; 105 | } 106 | 107 | - (void)removeObjectForKey:(NSString *)key { 108 | [_memoryCache removeObjectForKey:key]; 109 | [_diskCache removeObjectForKey:key]; 110 | } 111 | 112 | - (void)removeObjectForKey:(NSString *)key withBlock:(void (^)(NSString *key))block { 113 | [_memoryCache removeObjectForKey:key]; 114 | [_diskCache removeObjectForKey:key withBlock:block]; 115 | } 116 | 117 | - (void)removeAllObjects { 118 | [_memoryCache removeAllObjects]; 119 | [_diskCache removeAllObjects]; 120 | } 121 | 122 | - (void)removeAllObjectsWithBlock:(void(^)(void))block { 123 | [_memoryCache removeAllObjects]; 124 | [_diskCache removeAllObjectsWithBlock:block]; 125 | } 126 | 127 | - (void)removeAllObjectsWithProgressBlock:(void(^)(int removedCount, int totalCount))progress 128 | endBlock:(void(^)(BOOL error))end { 129 | [_memoryCache removeAllObjects]; 130 | [_diskCache removeAllObjectsWithProgressBlock:progress endBlock:end]; 131 | 132 | } 133 | 134 | - (NSString *)description { 135 | if (_name) return [NSString stringWithFormat:@"<%@: %p> (%@)", self.class, self, _name]; 136 | else return [NSString stringWithFormat:@"<%@: %p>", self.class, self]; 137 | } 138 | 139 | @end 140 | -------------------------------------------------------------------------------- /PlayCornerRadius/YYCache/YYCache/YYMemoryCache.h: -------------------------------------------------------------------------------- 1 | // 2 | // YYMemoryCache.h 3 | // YYCache 4 | // 5 | // Created by ibireme on 15/2/7. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | 14 | NS_ASSUME_NONNULL_BEGIN 15 | 16 | /** 17 | YYMemoryCache is a fast in-memory cache that stores key-value pairs. 18 | In contrast to NSDictionary, keys are retained and not copied. 19 | The API and performance is similar to `NSCache`, all methods are thread-safe. 20 | 21 | YYMemoryCache objects differ from NSCache in a few ways: 22 | 23 | * It uses LRU (least-recently-used) to remove objects; NSCache's eviction method 24 | is non-deterministic. 25 | * It can be controlled by cost, count and age; NSCache's limits are imprecise. 26 | * It can be configured to automatically evict objects when receive memory 27 | warning or app enter background. 28 | 29 | The time of `Access Methods` in YYMemoryCache is typically in constant time (O(1)). 30 | */ 31 | @interface YYMemoryCache : NSObject 32 | 33 | #pragma mark - Attribute 34 | ///============================================================================= 35 | /// @name Attribute 36 | ///============================================================================= 37 | 38 | /** The name of the cache. Default is nil. */ 39 | @property (nullable, copy) NSString *name; 40 | 41 | /** The number of objects in the cache (read-only) */ 42 | @property (readonly) NSUInteger totalCount; 43 | 44 | /** The total cost of objects in the cache (read-only). */ 45 | @property (readonly) NSUInteger totalCost; 46 | 47 | 48 | #pragma mark - Limit 49 | ///============================================================================= 50 | /// @name Limit 51 | ///============================================================================= 52 | 53 | /** 54 | The maximum number of objects the cache should hold. 55 | 56 | @discussion The default value is NSUIntegerMax, which means no limit. 57 | This is not a strict limit—if the cache goes over the limit, some objects in the 58 | cache could be evicted later in backgound thread. 59 | */ 60 | @property NSUInteger countLimit; 61 | 62 | /** 63 | The maximum total cost that the cache can hold before it starts evicting objects. 64 | 65 | @discussion The default value is NSUIntegerMax, which means no limit. 66 | This is not a strict limit—if the cache goes over the limit, some objects in the 67 | cache could be evicted later in backgound thread. 68 | */ 69 | @property NSUInteger costLimit; 70 | 71 | /** 72 | The maximum expiry time of objects in cache. 73 | 74 | @discussion The default value is DBL_MAX, which means no limit. 75 | This is not a strict limit—if an object goes over the limit, the object could 76 | be evicted later in backgound thread. 77 | */ 78 | @property NSTimeInterval ageLimit; 79 | 80 | /** 81 | The auto trim check time interval in seconds. Default is 5.0. 82 | 83 | @discussion The cache holds an internal timer to check whether the cache reaches 84 | its limits, and if the limit is reached, it begins to evict objects. 85 | */ 86 | @property NSTimeInterval autoTrimInterval; 87 | 88 | /** 89 | If `YES`, the cache will remove all objects when the app receives a memory warning. 90 | The default value is `YES`. 91 | */ 92 | @property BOOL shouldRemoveAllObjectsOnMemoryWarning; 93 | 94 | /** 95 | If `YES`, The cache will remove all objects when the app enter background. 96 | The default value is `YES`. 97 | */ 98 | @property BOOL shouldRemoveAllObjectsWhenEnteringBackground; 99 | 100 | /** 101 | A block to be executed when the app receives a memory warning. 102 | The default value is nil. 103 | */ 104 | @property (nullable, copy) void(^didReceiveMemoryWarningBlock)(YYMemoryCache *cache); 105 | 106 | /** 107 | A block to be executed when the app enter background. 108 | The default value is nil. 109 | */ 110 | @property (nullable, copy) void(^didEnterBackgroundBlock)(YYMemoryCache *cache); 111 | 112 | /** 113 | If `YES`, the key-value pair will be released on main thread, otherwise on 114 | background thread. Default is NO. 115 | 116 | @discussion You may set this value to `YES` if the key-value object contains 117 | the instance which should be released in main thread (such as UIView/CALayer). 118 | */ 119 | @property BOOL releaseOnMainThread; 120 | 121 | /** 122 | If `YES`, the key-value pair will be released asynchronously to avoid blocking 123 | the access methods, otherwise it will be released in the access method 124 | (such as removeObjectForKey:). Default is YES. 125 | */ 126 | @property BOOL releaseAsynchronously; 127 | 128 | 129 | #pragma mark - Access Methods 130 | ///============================================================================= 131 | /// @name Access Methods 132 | ///============================================================================= 133 | 134 | /** 135 | Returns a Boolean value that indicates whether a given key is in cache. 136 | 137 | @param key An object identifying the value. If nil, just return `NO`. 138 | @return Whether the key is in cache. 139 | */ 140 | - (BOOL)containsObjectForKey:(id)key; 141 | 142 | /** 143 | Returns the value associated with a given key. 144 | 145 | @param key An object identifying the value. If nil, just return nil. 146 | @return The value associated with key, or nil if no value is associated with key. 147 | */ 148 | - (nullable id)objectForKey:(id)key; 149 | 150 | /** 151 | Sets the value of the specified key in the cache (0 cost). 152 | 153 | @param object The object to be stored in the cache. If nil, it calls `removeObjectForKey:`. 154 | @param key The key with which to associate the value. If nil, this method has no effect. 155 | @discussion Unlike an NSMutableDictionary object, a cache does not copy the key 156 | objects that are put into it. 157 | */ 158 | - (void)setObject:(nullable id)object forKey:(id)key; 159 | 160 | /** 161 | Sets the value of the specified key in the cache, and associates the key-value 162 | pair with the specified cost. 163 | 164 | @param object The object to store in the cache. If nil, it calls `removeObjectForKey`. 165 | @param key The key with which to associate the value. If nil, this method has no effect. 166 | @param cost The cost with which to associate the key-value pair. 167 | @discussion Unlike an NSMutableDictionary object, a cache does not copy the key 168 | objects that are put into it. 169 | */ 170 | - (void)setObject:(nullable id)object forKey:(id)key withCost:(NSUInteger)cost; 171 | 172 | /** 173 | Removes the value of the specified key in the cache. 174 | 175 | @param key The key identifying the value to be removed. If nil, this method has no effect. 176 | */ 177 | - (void)removeObjectForKey:(id)key; 178 | 179 | /** 180 | Empties the cache immediately. 181 | */ 182 | - (void)removeAllObjects; 183 | 184 | 185 | #pragma mark - Trim 186 | ///============================================================================= 187 | /// @name Trim 188 | ///============================================================================= 189 | 190 | /** 191 | Removes objects from the cache with LRU, until the `totalCount` is below or equal to 192 | the specified value. 193 | @param count The total count allowed to remain after the cache has been trimmed. 194 | */ 195 | - (void)trimToCount:(NSUInteger)count; 196 | 197 | /** 198 | Removes objects from the cache with LRU, until the `totalCost` is or equal to 199 | the specified value. 200 | @param cost The total cost allowed to remain after the cache has been trimmed. 201 | */ 202 | - (void)trimToCost:(NSUInteger)cost; 203 | 204 | /** 205 | Removes objects from the cache with LRU, until all expiry objects removed by the 206 | specified value. 207 | @param age The maximum age (in seconds) of objects. 208 | */ 209 | - (void)trimToAge:(NSTimeInterval)age; 210 | 211 | @end 212 | 213 | NS_ASSUME_NONNULL_END 214 | -------------------------------------------------------------------------------- /PlayCornerRadius/YYFPSLabel/YYFPSLabel.h: -------------------------------------------------------------------------------- 1 | // 2 | // YYFPSLabel.h 3 | // YYKitExample 4 | // 5 | // Created by ibireme on 15/9/3. 6 | // Copyright (c) 2015 ibireme. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | /** 12 | Show Screen FPS... 13 | 14 | The maximum fps in OSX/iOS Simulator is 60.00. 15 | The maximum fps on iPhone is 59.97. 16 | The maxmium fps on iPad is 60.0. 17 | */ 18 | @interface YYFPSLabel : UILabel 19 | 20 | + (void)xw_addFPSLableOnWidnow; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /PlayCornerRadius/YYFPSLabel/YYFPSLabel.m: -------------------------------------------------------------------------------- 1 | // 2 | // YYFPSLabel.m 3 | // YYKitExample 4 | // 5 | // Created by ibireme on 15/9/3. 6 | // Copyright (c) 2015 ibireme. All rights reserved. 7 | // 8 | 9 | #import "YYFPSLabel.h" 10 | #import "YYWeakProxy.h" 11 | 12 | #define kSize CGSizeMake(55, 20) 13 | 14 | @implementation YYFPSLabel { 15 | CADisplayLink *_link; 16 | NSUInteger _count; 17 | NSTimeInterval _lastTime; 18 | UIFont *_font; 19 | UIFont *_subFont; 20 | 21 | NSTimeInterval _llll; 22 | } 23 | 24 | - (instancetype)initWithFrame:(CGRect)frame { 25 | if (frame.size.width == 0 && frame.size.height == 0) { 26 | frame.size = kSize; 27 | } 28 | self = [super initWithFrame:frame]; 29 | 30 | self.layer.cornerRadius = 5; 31 | self.clipsToBounds = YES; 32 | self.textAlignment = NSTextAlignmentCenter; 33 | self.userInteractionEnabled = NO; 34 | self.backgroundColor = [UIColor colorWithWhite:0.000 alpha:0.700]; 35 | 36 | _font = [UIFont fontWithName:@"Menlo" size:14]; 37 | if (_font) { 38 | _subFont = [UIFont fontWithName:@"Menlo" size:4]; 39 | } else { 40 | _font = [UIFont fontWithName:@"Courier" size:14]; 41 | _subFont = [UIFont fontWithName:@"Courier" size:4]; 42 | } 43 | 44 | _link = [CADisplayLink displayLinkWithTarget:[YYWeakProxy proxyWithTarget:self] selector:@selector(tick:)]; 45 | [_link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes]; 46 | return self; 47 | } 48 | 49 | - (void)dealloc { 50 | [_link invalidate]; 51 | } 52 | 53 | - (CGSize)sizeThatFits:(CGSize)size { 54 | return kSize; 55 | } 56 | 57 | - (void)tick:(CADisplayLink *)link { 58 | if (_lastTime == 0) { 59 | _lastTime = link.timestamp; 60 | return; 61 | } 62 | 63 | _count++; 64 | NSTimeInterval delta = link.timestamp - _lastTime; 65 | if (delta < 1) return; 66 | _lastTime = link.timestamp; 67 | float fps = _count / delta; 68 | _count = 0; 69 | 70 | CGFloat progress = fps / 60.0; 71 | UIColor *color = [UIColor colorWithHue:0.27 * (progress - 0.2) saturation:1 brightness:0.9 alpha:1]; 72 | 73 | NSMutableAttributedString *text = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"%d FPS",(int)round(fps)] attributes:@{NSFontAttributeName : _font}]; 74 | [text setAttributes:@{NSForegroundColorAttributeName : color} range:NSMakeRange(0, text.length - 3)]; 75 | [text setAttributes:@{NSForegroundColorAttributeName : [UIColor whiteColor]} range:NSMakeRange(text.length - 3, 3)]; 76 | [text setAttributes:@{NSFontAttributeName : _subFont} range:NSMakeRange(text.length - 4, 1)]; 77 | 78 | self.attributedText = text; 79 | } 80 | 81 | + (void)xw_addFPSLableOnWidnow { 82 | #ifdef DEBUG 83 | YYFPSLabel *fpsLabel = [YYFPSLabel new]; 84 | UIWindow *window = [[UIApplication sharedApplication].delegate window]; 85 | fpsLabel.frame = CGRectMake(5, CGRectGetHeight(window.frame) - 80, 60, 20); 86 | [window addSubview:fpsLabel]; 87 | #endif 88 | } 89 | 90 | @end 91 | -------------------------------------------------------------------------------- /PlayCornerRadius/YYFPSLabel/YYWeakProxy.h: -------------------------------------------------------------------------------- 1 | // 2 | // YYWeakProxy.h 3 | // YYKit 4 | // 5 | // Created by ibireme on 14/10/18. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | 14 | NS_ASSUME_NONNULL_BEGIN 15 | 16 | /** 17 | A proxy used to hold a weak object. 18 | It can be used to avoid retain cycles, such as the target in NSTimer or CADisplayLink. 19 | 20 | sample code: 21 | 22 | @implementation MyView { 23 | NSTimer *_timer; 24 | } 25 | 26 | - (void)initTimer { 27 | YYWeakProxy *proxy = [YYWeakProxy proxyWithTarget:self]; 28 | _timer = [NSTimer timerWithTimeInterval:0.1 target:proxy selector:@selector(tick:) userInfo:nil repeats:YES]; 29 | } 30 | 31 | - (void)tick:(NSTimer *)timer {...} 32 | @end 33 | */ 34 | @interface YYWeakProxy : NSProxy 35 | 36 | /** 37 | The proxy target. 38 | */ 39 | @property (nullable, nonatomic, weak, readonly) id target; 40 | 41 | /** 42 | Creates a new weak proxy for target. 43 | 44 | @param target Target object. 45 | 46 | @return A new proxy object. 47 | */ 48 | - (instancetype)initWithTarget:(id)target; 49 | 50 | /** 51 | Creates a new weak proxy for target. 52 | 53 | @param target Target object. 54 | 55 | @return A new proxy object. 56 | */ 57 | + (instancetype)proxyWithTarget:(id)target; 58 | 59 | @end 60 | 61 | NS_ASSUME_NONNULL_END 62 | -------------------------------------------------------------------------------- /PlayCornerRadius/YYFPSLabel/YYWeakProxy.m: -------------------------------------------------------------------------------- 1 | // 2 | // YYWeakProxy.m 3 | // YYKit 4 | // 5 | // Created by ibireme on 14/10/18. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import "YYWeakProxy.h" 13 | 14 | 15 | @implementation YYWeakProxy 16 | 17 | - (instancetype)initWithTarget:(id)target { 18 | _target = target; 19 | return self; 20 | } 21 | 22 | + (instancetype)proxyWithTarget:(id)target { 23 | return [[YYWeakProxy alloc] initWithTarget:target]; 24 | } 25 | 26 | - (id)forwardingTargetForSelector:(SEL)selector { 27 | return _target; 28 | } 29 | 30 | - (void)forwardInvocation:(NSInvocation *)invocation { 31 | void *null = NULL; 32 | [invocation setReturnValue:&null]; 33 | } 34 | 35 | - (NSMethodSignature *)methodSignatureForSelector:(SEL)selector { 36 | return [NSObject instanceMethodSignatureForSelector:@selector(init)]; 37 | } 38 | 39 | - (BOOL)respondsToSelector:(SEL)aSelector { 40 | return [_target respondsToSelector:aSelector]; 41 | } 42 | 43 | - (BOOL)isEqual:(id)object { 44 | return [_target isEqual:object]; 45 | } 46 | 47 | - (NSUInteger)hash { 48 | return [_target hash]; 49 | } 50 | 51 | - (Class)superclass { 52 | return [_target superclass]; 53 | } 54 | 55 | - (Class)class { 56 | return [_target class]; 57 | } 58 | 59 | - (BOOL)isKindOfClass:(Class)aClass { 60 | return [_target isKindOfClass:aClass]; 61 | } 62 | 63 | - (BOOL)isMemberOfClass:(Class)aClass { 64 | return [_target isMemberOfClass:aClass]; 65 | } 66 | 67 | - (BOOL)conformsToProtocol:(Protocol *)aProtocol { 68 | return [_target conformsToProtocol:aProtocol]; 69 | } 70 | 71 | - (BOOL)isProxy { 72 | return YES; 73 | } 74 | 75 | - (NSString *)description { 76 | return [_target description]; 77 | } 78 | 79 | - (NSString *)debugDescription { 80 | return [_target debugDescription]; 81 | } 82 | 83 | @end 84 | -------------------------------------------------------------------------------- /PlayCornerRadius/YYImage/YYImage/YYAnimatedImageView.h: -------------------------------------------------------------------------------- 1 | // 2 | // YYAnimatedImageView.h 3 | // YYImage 4 | // 5 | // Created by ibireme on 14/10/19. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | 14 | NS_ASSUME_NONNULL_BEGIN 15 | 16 | /** 17 | An image view for displaying animated image. 18 | 19 | @discussion It is a fully compatible `UIImageView` subclass. 20 | If the `image` or `highlightedImage` property adopt to the `YYAnimatedImage` protocol, 21 | then it can be used to play the multi-frame animation. The animation can also be 22 | controlled with the UIImageView methods `-startAnimating`, `-stopAnimating` and `-isAnimating`. 23 | 24 | This view request the frame data just in time. When the device has enough free memory, 25 | this view may cache some or all future frames in an inner buffer for lower CPU cost. 26 | Buffer size is dynamically adjusted based on the current state of the device memory. 27 | 28 | Sample Code: 29 | 30 | // ani@3x.gif 31 | YYImage *image = [YYImage imageNamed:@"ani"]; 32 | YYAnimatedImageView *imageView = [YYAnimatedImageView alloc] initWithImage:image]; 33 | [view addSubView:imageView]; 34 | */ 35 | @interface YYAnimatedImageView : UIImageView 36 | 37 | /** 38 | If the image has more than one frame, set this value to `YES` will automatically 39 | play/stop the animation when the view become visible/invisible. 40 | 41 | The default value is `YES`. 42 | */ 43 | @property (nonatomic) BOOL autoPlayAnimatedImage; 44 | 45 | /** 46 | Index of the currently displayed frame (index from 0). 47 | 48 | Set a new value to this property will cause to display the new frame immediately. 49 | If the new value is invalid, this method has no effect. 50 | 51 | You can add an observer to this property to observe the playing status. 52 | */ 53 | @property (nonatomic) NSUInteger currentAnimatedImageIndex; 54 | 55 | /** 56 | Whether the image view is playing animation currently. 57 | 58 | You can add an observer to this property to observe the playing status. 59 | */ 60 | @property (nonatomic, readonly) BOOL currentIsPlayingAnimation; 61 | 62 | /** 63 | The animation timer's runloop mode, default is `NSRunLoopCommonModes`. 64 | 65 | Set this property to `NSDefaultRunLoopMode` will make the animation pause during 66 | UIScrollView scrolling. 67 | */ 68 | @property (nonatomic, copy) NSString *runloopMode; 69 | 70 | /** 71 | The max size (in bytes) for inner frame buffer size, default is 0 (dynamically). 72 | 73 | When the device has enough free memory, this view will request and decode some or 74 | all future frame image into an inner buffer. If this property's value is 0, then 75 | the max buffer size will be dynamically adjusted based on the current state of 76 | the device free memory. Otherwise, the buffer size will be limited by this value. 77 | 78 | When receive memory warning or app enter background, the buffer will be released 79 | immediately, and may grow back at the right time. 80 | */ 81 | @property (nonatomic) NSUInteger maxBufferSize; 82 | 83 | @end 84 | 85 | 86 | 87 | /** 88 | The YYAnimatedImage protocol declares the required methods for animated image 89 | display with YYAnimatedImageView. 90 | 91 | Subclass a UIImage and implement this protocol, so that instances of that class 92 | can be set to YYAnimatedImageView.image or YYAnimatedImageView.highlightedImage 93 | to display animation. 94 | 95 | See `YYImage` and `YYFrameImage` for example. 96 | */ 97 | @protocol YYAnimatedImage 98 | @required 99 | /// Total animated frame count. 100 | /// It the frame count is less than 1, then the methods below will be ignored. 101 | - (NSUInteger)animatedImageFrameCount; 102 | 103 | /// Animation loop count, 0 means infinite looping. 104 | - (NSUInteger)animatedImageLoopCount; 105 | 106 | /// Bytes per frame (in memory). It may used to optimize memory buffer size. 107 | - (NSUInteger)animatedImageBytesPerFrame; 108 | 109 | /// Returns the frame image from a specified index. 110 | /// This method may be called on background thread. 111 | /// @param index Frame index (zero based). 112 | - (nullable UIImage *)animatedImageFrameAtIndex:(NSUInteger)index; 113 | 114 | /// Returns the frames's duration from a specified index. 115 | /// @param index Frame index (zero based). 116 | - (NSTimeInterval)animatedImageDurationAtIndex:(NSUInteger)index; 117 | 118 | @optional 119 | /// A rectangle in image coordinates defining the subrectangle of the image that 120 | /// will be displayed. The rectangle should not outside the image's bounds. 121 | /// It may used to display sprite animation with a single image (sprite sheet). 122 | - (CGRect)animatedImageContentsRectAtIndex:(NSUInteger)index; 123 | @end 124 | 125 | NS_ASSUME_NONNULL_END 126 | -------------------------------------------------------------------------------- /PlayCornerRadius/YYImage/YYImage/YYFrameImage.h: -------------------------------------------------------------------------------- 1 | // 2 | // YYFrameImage.h 3 | // YYImage 4 | // 5 | // Created by ibireme on 14/12/9. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | 14 | #if __has_include() 15 | #import 16 | #elif __has_include() 17 | #import 18 | #else 19 | #import "YYAnimatedImageView.h" 20 | #endif 21 | 22 | NS_ASSUME_NONNULL_BEGIN 23 | 24 | /** 25 | An image to display frame-based animation. 26 | 27 | @discussion It is a fully compatible `UIImage` subclass. 28 | It only support system image format such as png and jpeg. 29 | The animation can be played by YYAnimatedImageView. 30 | 31 | Sample Code: 32 | 33 | NSArray *paths = @[@"/ani/frame1.png", @"/ani/frame2.png", @"/ani/frame3.png"]; 34 | NSArray *times = @[@0.1, @0.2, @0.1]; 35 | YYFrameImage *image = [YYFrameImage alloc] initWithImagePaths:paths frameDurations:times repeats:YES]; 36 | YYAnimatedImageView *imageView = [YYAnimatedImageView alloc] initWithImage:image]; 37 | [view addSubView:imageView]; 38 | */ 39 | @interface YYFrameImage : UIImage 40 | 41 | /** 42 | Create a frame animated image from files. 43 | 44 | @param paths An array of NSString objects, contains the full or 45 | partial path to each image file. 46 | e.g. @[@"/ani/1.png",@"/ani/2.png",@"/ani/3.png"] 47 | 48 | @param oneFrameDuration The duration (in seconds) per frame. 49 | 50 | @param loopCount The animation loop count, 0 means infinite. 51 | 52 | @return An initialized YYFrameImage object, or nil when an error occurs. 53 | */ 54 | - (nullable instancetype)initWithImagePaths:(NSArray *)paths 55 | oneFrameDuration:(NSTimeInterval)oneFrameDuration 56 | loopCount:(NSUInteger)loopCount; 57 | 58 | /** 59 | Create a frame animated image from files. 60 | 61 | @param paths An array of NSString objects, contains the full or 62 | partial path to each image file. 63 | e.g. @[@"/ani/frame1.png",@"/ani/frame2.png",@"/ani/frame3.png"] 64 | 65 | @param frameDurations An array of NSNumber objects, contains the duration (in seconds) per frame. 66 | e.g. @[@0.1, @0.2, @0.3]; 67 | 68 | @param loopCount The animation loop count, 0 means infinite. 69 | 70 | @return An initialized YYFrameImage object, or nil when an error occurs. 71 | */ 72 | - (nullable instancetype)initWithImagePaths:(NSArray *)paths 73 | frameDurations:(NSArray *)frameDurations 74 | loopCount:(NSUInteger)loopCount; 75 | 76 | /** 77 | Create a frame animated image from an array of data. 78 | 79 | @param dataArray An array of NSData objects. 80 | 81 | @param oneFrameDuration The duration (in seconds) per frame. 82 | 83 | @param loopCount The animation loop count, 0 means infinite. 84 | 85 | @return An initialized YYFrameImage object, or nil when an error occurs. 86 | */ 87 | - (nullable instancetype)initWithImageDataArray:(NSArray *)dataArray 88 | oneFrameDuration:(NSTimeInterval)oneFrameDuration 89 | loopCount:(NSUInteger)loopCount; 90 | 91 | /** 92 | Create a frame animated image from an array of data. 93 | 94 | @param dataArray An array of NSData objects. 95 | 96 | @param frameDurations An array of NSNumber objects, contains the duration (in seconds) per frame. 97 | e.g. @[@0.1, @0.2, @0.3]; 98 | 99 | @param loopCount The animation loop count, 0 means infinite. 100 | 101 | @return An initialized YYFrameImage object, or nil when an error occurs. 102 | */ 103 | - (nullable instancetype)initWithImageDataArray:(NSArray *)dataArray 104 | frameDurations:(NSArray *)frameDurations 105 | loopCount:(NSUInteger)loopCount; 106 | 107 | @end 108 | 109 | NS_ASSUME_NONNULL_END 110 | -------------------------------------------------------------------------------- /PlayCornerRadius/YYImage/YYImage/YYFrameImage.m: -------------------------------------------------------------------------------- 1 | // 2 | // YYFrameImage.m 3 | // YYImage 4 | // 5 | // Created by ibireme on 14/12/9. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import "YYFrameImage.h" 13 | #import "YYImageCoder.h" 14 | 15 | 16 | /** 17 | Return the path scale. 18 | 19 | e.g. 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 |
Path Scale
"icon.png" 1
"icon@2x.png" 2
"icon@2.5x.png" 2.5
"icon@2x" 1
"icon@2x..png" 1
"icon@2x.png/" 1
29 | */ 30 | static CGFloat _NSStringPathScale(NSString *string) { 31 | if (string.length == 0 || [string hasSuffix:@"/"]) return 1; 32 | NSString *name = string.stringByDeletingPathExtension; 33 | __block CGFloat scale = 1; 34 | 35 | NSRegularExpression *pattern = [NSRegularExpression regularExpressionWithPattern:@"@[0-9]+\\.?[0-9]*x$" options:NSRegularExpressionAnchorsMatchLines error:nil]; 36 | [pattern enumerateMatchesInString:name options:kNilOptions range:NSMakeRange(0, name.length) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) { 37 | if (result.range.location >= 3) { 38 | scale = [string substringWithRange:NSMakeRange(result.range.location + 1, result.range.length - 2)].doubleValue; 39 | } 40 | }]; 41 | 42 | return scale; 43 | } 44 | 45 | 46 | 47 | @implementation YYFrameImage { 48 | NSUInteger _loopCount; 49 | NSUInteger _oneFrameBytes; 50 | NSArray *_imagePaths; 51 | NSArray *_imageDatas; 52 | NSArray *_frameDurations; 53 | } 54 | 55 | - (instancetype)initWithImagePaths:(NSArray *)paths oneFrameDuration:(NSTimeInterval)oneFrameDuration loopCount:(NSUInteger)loopCount { 56 | NSMutableArray *durations = [NSMutableArray new]; 57 | for (int i = 0, max = (int)paths.count; i < max; i++) { 58 | [durations addObject:@(oneFrameDuration)]; 59 | } 60 | return [self initWithImagePaths:paths frameDurations:durations loopCount:loopCount]; 61 | } 62 | 63 | - (instancetype)initWithImagePaths:(NSArray *)paths frameDurations:(NSArray *)frameDurations loopCount:(NSUInteger)loopCount { 64 | if (paths.count == 0) return nil; 65 | if (paths.count != frameDurations.count) return nil; 66 | 67 | NSString *firstPath = paths[0]; 68 | NSData *firstData = [NSData dataWithContentsOfFile:firstPath]; 69 | CGFloat scale = _NSStringPathScale(firstPath); 70 | UIImage *firstCG = [[[UIImage alloc] initWithData:firstData] yy_imageByDecoded]; 71 | self = [self initWithCGImage:firstCG.CGImage scale:scale orientation:UIImageOrientationUp]; 72 | if (!self) return nil; 73 | long frameByte = CGImageGetBytesPerRow(firstCG.CGImage) * CGImageGetHeight(firstCG.CGImage); 74 | _oneFrameBytes = (NSUInteger)frameByte; 75 | _imagePaths = paths.copy; 76 | _frameDurations = frameDurations.copy; 77 | _loopCount = loopCount; 78 | 79 | return self; 80 | } 81 | 82 | - (instancetype)initWithImageDataArray:(NSArray *)dataArray oneFrameDuration:(NSTimeInterval)oneFrameDuration loopCount:(NSUInteger)loopCount { 83 | NSMutableArray *durations = [NSMutableArray new]; 84 | for (int i = 0, max = (int)dataArray.count; i < max; i++) { 85 | [durations addObject:@(oneFrameDuration)]; 86 | } 87 | return [self initWithImageDataArray:dataArray frameDurations:durations loopCount:loopCount]; 88 | } 89 | 90 | - (instancetype)initWithImageDataArray:(NSArray *)dataArray frameDurations:(NSArray *)frameDurations loopCount:(NSUInteger)loopCount { 91 | if (dataArray.count == 0) return nil; 92 | if (dataArray.count != frameDurations.count) return nil; 93 | 94 | NSData *firstData = dataArray[0]; 95 | CGFloat scale = [UIScreen mainScreen].scale; 96 | UIImage *firstCG = [[[UIImage alloc] initWithData:firstData] yy_imageByDecoded]; 97 | self = [self initWithCGImage:firstCG.CGImage scale:scale orientation:UIImageOrientationUp]; 98 | if (!self) return nil; 99 | long frameByte = CGImageGetBytesPerRow(firstCG.CGImage) * CGImageGetHeight(firstCG.CGImage); 100 | _oneFrameBytes = (NSUInteger)frameByte; 101 | _imageDatas = dataArray.copy; 102 | _frameDurations = frameDurations.copy; 103 | _loopCount = loopCount; 104 | 105 | return self; 106 | } 107 | 108 | #pragma mark - YYAnimtedImage 109 | 110 | - (NSUInteger)animatedImageFrameCount { 111 | if (_imagePaths) { 112 | return _imagePaths.count; 113 | } else if (_imageDatas) { 114 | return _imageDatas.count; 115 | } else { 116 | return 1; 117 | } 118 | } 119 | 120 | - (NSUInteger)animatedImageLoopCount { 121 | return _loopCount; 122 | } 123 | 124 | - (NSUInteger)animatedImageBytesPerFrame { 125 | return _oneFrameBytes; 126 | } 127 | 128 | - (UIImage *)animatedImageFrameAtIndex:(NSUInteger)index { 129 | if (_imagePaths) { 130 | if (index >= _imagePaths.count) return nil; 131 | NSString *path = _imagePaths[index]; 132 | CGFloat scale = _NSStringPathScale(path); 133 | NSData *data = [NSData dataWithContentsOfFile:path]; 134 | return [[UIImage imageWithData:data scale:scale] yy_imageByDecoded]; 135 | } else if (_imageDatas) { 136 | if (index >= _imageDatas.count) return nil; 137 | NSData *data = _imageDatas[index]; 138 | return [[UIImage imageWithData:data scale:[UIScreen mainScreen].scale] yy_imageByDecoded]; 139 | } else { 140 | return index == 0 ? self : nil; 141 | } 142 | } 143 | 144 | - (NSTimeInterval)animatedImageDurationAtIndex:(NSUInteger)index { 145 | if (index >= _frameDurations.count) return 0; 146 | NSNumber *num = _frameDurations[index]; 147 | return [num doubleValue]; 148 | } 149 | 150 | @end 151 | -------------------------------------------------------------------------------- /PlayCornerRadius/YYImage/YYImage/YYImage.h: -------------------------------------------------------------------------------- 1 | // 2 | // YYImage.h 3 | // YYImage 4 | // 5 | // Created by ibireme on 14/10/20. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | 14 | #if __has_include() 15 | FOUNDATION_EXPORT double YYImageVersionNumber; 16 | FOUNDATION_EXPORT const unsigned char YYImageVersionString[]; 17 | #import 18 | #import 19 | #import 20 | #import 21 | #elif __has_include() 22 | #import 23 | #import 24 | #import 25 | #import 26 | #else 27 | #import "YYFrameImage.h" 28 | #import "YYSpriteSheetImage.h" 29 | #import "YYImageCoder.h" 30 | #import "YYAnimatedImageView.h" 31 | #endif 32 | 33 | NS_ASSUME_NONNULL_BEGIN 34 | 35 | 36 | /** 37 | A YYImage object is a high-level way to display animated image data. 38 | 39 | @discussion It is a fully compatible `UIImage` subclass. It extends the UIImage 40 | to support animated WebP, APNG and GIF format image data decoding. It also 41 | support NSCoding protocol to archive and unarchive multi-frame image data. 42 | 43 | If the image is created from multi-frame image data, and you want to play the 44 | animation, try replace UIImageView with `YYAnimatedImageView`. 45 | 46 | Sample Code: 47 | 48 | // animation@3x.webp 49 | YYImage *image = [YYImage imageNamed:@"animation.webp"]; 50 | YYAnimatedImageView *imageView = [YYAnimatedImageView alloc] initWithImage:image]; 51 | [view addSubView:imageView]; 52 | 53 | */ 54 | @interface YYImage : UIImage 55 | 56 | + (nullable YYImage *)imageNamed:(NSString *)name; // no cache! 57 | + (nullable YYImage *)imageWithContentsOfFile:(NSString *)path; 58 | + (nullable YYImage *)imageWithData:(NSData *)data; 59 | + (nullable YYImage *)imageWithData:(NSData *)data scale:(CGFloat)scale; 60 | 61 | /** 62 | If the image is created from data or file, then the value indicates the data type. 63 | */ 64 | @property (nonatomic, readonly) YYImageType animatedImageType; 65 | 66 | /** 67 | If the image is created from animated image data (multi-frame GIF/APNG/WebP), 68 | this property stores the original image data. 69 | */ 70 | @property (nullable, nonatomic, readonly) NSData *animatedImageData; 71 | 72 | /** 73 | The total memory usage (in bytes) if all frame images was loaded into memory. 74 | The value is 0 if the image is not created from a multi-frame image data. 75 | */ 76 | @property (nonatomic, readonly) NSUInteger animatedImageMemorySize; 77 | 78 | /** 79 | Preload all frame image to memory. 80 | 81 | @discussion Set this property to `YES` will block the calling thread to decode 82 | all animation frame image to memory, set to `NO` will release the preloaded frames. 83 | If the image is shared by lots of image views (such as emoticon), preload all 84 | frames will reduce the CPU cost. 85 | 86 | See `animatedImageMemorySize` for memory cost. 87 | */ 88 | @property (nonatomic) BOOL preloadAllAnimatedImageFrames; 89 | 90 | @end 91 | 92 | NS_ASSUME_NONNULL_END 93 | -------------------------------------------------------------------------------- /PlayCornerRadius/YYImage/YYImage/YYImage.m: -------------------------------------------------------------------------------- 1 | // 2 | // YYImage.m 3 | // YYImage 4 | // 5 | // Created by ibireme on 14/10/20. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import "YYImage.h" 13 | 14 | /** 15 | An array of NSNumber objects, shows the best order for path scale search. 16 | e.g. iPhone3GS:@[@1,@2,@3] iPhone5:@[@2,@3,@1] iPhone6 Plus:@[@3,@2,@1] 17 | */ 18 | static NSArray *_NSBundlePreferredScales() { 19 | static NSArray *scales; 20 | static dispatch_once_t onceToken; 21 | dispatch_once(&onceToken, ^{ 22 | CGFloat screenScale = [UIScreen mainScreen].scale; 23 | if (screenScale <= 1) { 24 | scales = @[@1,@2,@3]; 25 | } else if (screenScale <= 2) { 26 | scales = @[@2,@3,@1]; 27 | } else { 28 | scales = @[@3,@2,@1]; 29 | } 30 | }); 31 | return scales; 32 | } 33 | 34 | /** 35 | Add scale modifier to the file name (without path extension), 36 | From @"name" to @"name@2x". 37 | 38 | e.g. 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 |
Before After(scale:2)
"icon" "icon@2x"
"icon " "icon @2x"
"icon.top" "icon.top@2x"
"/p/name" "/p/name@2x"
"/path/" "/path/"
47 | 48 | @param scale Resource scale. 49 | @return String by add scale modifier, or just return if it's not end with file name. 50 | */ 51 | static NSString *_NSStringByAppendingNameScale(NSString *string, CGFloat scale) { 52 | if (!string) return nil; 53 | if (fabs(scale - 1) <= __FLT_EPSILON__ || string.length == 0 || [string hasSuffix:@"/"]) return string.copy; 54 | return [string stringByAppendingFormat:@"@%@x", @(scale)]; 55 | } 56 | 57 | /** 58 | Return the path scale. 59 | 60 | e.g. 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 |
Path Scale
"icon.png" 1
"icon@2x.png" 2
"icon@2.5x.png" 2.5
"icon@2x" 1
"icon@2x..png" 1
"icon@2x.png/" 1
70 | */ 71 | static CGFloat _NSStringPathScale(NSString *string) { 72 | if (string.length == 0 || [string hasSuffix:@"/"]) return 1; 73 | NSString *name = string.stringByDeletingPathExtension; 74 | __block CGFloat scale = 1; 75 | 76 | NSRegularExpression *pattern = [NSRegularExpression regularExpressionWithPattern:@"@[0-9]+\\.?[0-9]*x$" options:NSRegularExpressionAnchorsMatchLines error:nil]; 77 | [pattern enumerateMatchesInString:name options:kNilOptions range:NSMakeRange(0, name.length) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) { 78 | if (result.range.location >= 3) { 79 | scale = [string substringWithRange:NSMakeRange(result.range.location + 1, result.range.length - 2)].doubleValue; 80 | } 81 | }]; 82 | 83 | return scale; 84 | } 85 | 86 | 87 | @implementation YYImage { 88 | YYImageDecoder *_decoder; 89 | NSArray *_preloadedFrames; 90 | dispatch_semaphore_t _preloadedLock; 91 | NSUInteger _bytesPerFrame; 92 | } 93 | 94 | + (YYImage *)imageNamed:(NSString *)name { 95 | if (name.length == 0) return nil; 96 | if ([name hasSuffix:@"/"]) return nil; 97 | 98 | NSString *res = name.stringByDeletingPathExtension; 99 | NSString *ext = name.pathExtension; 100 | NSString *path = nil; 101 | CGFloat scale = 1; 102 | 103 | // If no extension, guess by system supported (same as UIImage). 104 | NSArray *exts = ext.length > 0 ? @[ext] : @[@"", @"png", @"jpeg", @"jpg", @"gif", @"webp", @"apng"]; 105 | NSArray *scales = _NSBundlePreferredScales(); 106 | for (int s = 0; s < scales.count; s++) { 107 | scale = ((NSNumber *)scales[s]).floatValue; 108 | NSString *scaledName = _NSStringByAppendingNameScale(res, scale); 109 | for (NSString *e in exts) { 110 | path = [[NSBundle mainBundle] pathForResource:scaledName ofType:e]; 111 | if (path) break; 112 | } 113 | if (path) break; 114 | } 115 | if (path.length == 0) return nil; 116 | 117 | NSData *data = [NSData dataWithContentsOfFile:path]; 118 | if (data.length == 0) return nil; 119 | 120 | return [[self alloc] initWithData:data scale:scale]; 121 | } 122 | 123 | + (YYImage *)imageWithContentsOfFile:(NSString *)path { 124 | return [[self alloc] initWithContentsOfFile:path]; 125 | } 126 | 127 | + (YYImage *)imageWithData:(NSData *)data { 128 | return [[self alloc] initWithData:data]; 129 | } 130 | 131 | + (YYImage *)imageWithData:(NSData *)data scale:(CGFloat)scale { 132 | return [[self alloc] initWithData:data scale:scale]; 133 | } 134 | 135 | - (instancetype)initWithContentsOfFile:(NSString *)path { 136 | NSData *data = [NSData dataWithContentsOfFile:path]; 137 | return [self initWithData:data scale:_NSStringPathScale(path)]; 138 | } 139 | 140 | - (instancetype)initWithData:(NSData *)data { 141 | return [self initWithData:data scale:1]; 142 | } 143 | 144 | - (instancetype)initWithData:(NSData *)data scale:(CGFloat)scale { 145 | if (data.length == 0) return nil; 146 | if (scale <= 0) scale = [UIScreen mainScreen].scale; 147 | _preloadedLock = dispatch_semaphore_create(1); 148 | @autoreleasepool { 149 | YYImageDecoder *decoder = [YYImageDecoder decoderWithData:data scale:scale]; 150 | YYImageFrame *frame = [decoder frameAtIndex:0 decodeForDisplay:YES]; 151 | UIImage *image = frame.image; 152 | if (!image) return nil; 153 | self = [self initWithCGImage:image.CGImage scale:decoder.scale orientation:image.imageOrientation]; 154 | if (!self) return nil; 155 | _animatedImageType = decoder.type; 156 | if (decoder.frameCount > 1) { 157 | _decoder = decoder; 158 | _bytesPerFrame = CGImageGetBytesPerRow(image.CGImage) * CGImageGetHeight(image.CGImage); 159 | _animatedImageMemorySize = _bytesPerFrame * decoder.frameCount; 160 | } 161 | self.yy_isDecodedForDisplay = YES; 162 | } 163 | return self; 164 | } 165 | 166 | - (NSData *)animatedImageData { 167 | return _decoder.data; 168 | } 169 | 170 | - (void)setPreloadAllAnimatedImageFrames:(BOOL)preloadAllAnimatedImageFrames { 171 | if (_preloadAllAnimatedImageFrames != preloadAllAnimatedImageFrames) { 172 | if (preloadAllAnimatedImageFrames && _decoder.frameCount > 0) { 173 | NSMutableArray *frames = [NSMutableArray new]; 174 | for (NSUInteger i = 0, max = _decoder.frameCount; i < max; i++) { 175 | UIImage *img = [self animatedImageFrameAtIndex:i]; 176 | if (img) { 177 | [frames addObject:img]; 178 | } else { 179 | [frames addObject:[NSNull null]]; 180 | } 181 | } 182 | dispatch_semaphore_wait(_preloadedLock, DISPATCH_TIME_FOREVER); 183 | _preloadedFrames = frames; 184 | dispatch_semaphore_signal(_preloadedLock); 185 | } else { 186 | dispatch_semaphore_wait(_preloadedLock, DISPATCH_TIME_FOREVER); 187 | _preloadedFrames = nil; 188 | dispatch_semaphore_signal(_preloadedLock); 189 | } 190 | } 191 | } 192 | 193 | #pragma mark - protocol NSCoding 194 | 195 | - (instancetype)initWithCoder:(NSCoder *)aDecoder { 196 | NSNumber *scale = [aDecoder decodeObjectForKey:@"YYImageScale"]; 197 | NSData *data = [aDecoder decodeObjectForKey:@"YYImageData"]; 198 | if (data.length) { 199 | self = [self initWithData:data scale:scale.doubleValue]; 200 | } else { 201 | self = [super initWithCoder:aDecoder]; 202 | } 203 | return self; 204 | } 205 | 206 | - (void)encodeWithCoder:(NSCoder *)aCoder { 207 | if (_decoder.data.length) { 208 | [aCoder encodeObject:@(self.scale) forKey:@"YYImageScale"]; 209 | [aCoder encodeObject:_decoder.data forKey:@"YYImageData"]; 210 | } else { 211 | [super encodeWithCoder:aCoder]; // Apple use UIImagePNGRepresentation() to encode UIImage. 212 | } 213 | } 214 | 215 | #pragma mark - protocol YYAnimatedImage 216 | 217 | - (NSUInteger)animatedImageFrameCount { 218 | return _decoder.frameCount; 219 | } 220 | 221 | - (NSUInteger)animatedImageLoopCount { 222 | return _decoder.loopCount; 223 | } 224 | 225 | - (NSUInteger)animatedImageBytesPerFrame { 226 | return _bytesPerFrame; 227 | } 228 | 229 | - (UIImage *)animatedImageFrameAtIndex:(NSUInteger)index { 230 | if (index >= _decoder.frameCount) return nil; 231 | dispatch_semaphore_wait(_preloadedLock, DISPATCH_TIME_FOREVER); 232 | UIImage *image = _preloadedFrames[index]; 233 | dispatch_semaphore_signal(_preloadedLock); 234 | if (image) return image == (id)[NSNull null] ? nil : image; 235 | return [_decoder frameAtIndex:index decodeForDisplay:YES].image; 236 | } 237 | 238 | - (NSTimeInterval)animatedImageDurationAtIndex:(NSUInteger)index { 239 | NSTimeInterval duration = [_decoder frameDurationAtIndex:index]; 240 | 241 | /* 242 | http://opensource.apple.com/source/WebCore/WebCore-7600.1.25/platform/graphics/cg/ImageSourceCG.cpp 243 | Many annoying ads specify a 0 duration to make an image flash as quickly as 244 | possible. We follow Safari and Firefox's behavior and use a duration of 100 ms 245 | for any frames that specify a duration of <= 10 ms. 246 | See and for more information. 247 | 248 | See also: http://nullsleep.tumblr.com/post/16524517190/animated-gif-minimum-frame-delay-browser. 249 | */ 250 | if (duration < 0.011f) return 0.100f; 251 | return duration; 252 | } 253 | 254 | @end 255 | -------------------------------------------------------------------------------- /PlayCornerRadius/YYImage/YYImage/YYSpriteSheetImage.h: -------------------------------------------------------------------------------- 1 | // 2 | // YYSpriteImage.h 3 | // YYImage 4 | // 5 | // Created by ibireme on 15/4/21. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | 14 | #if __has_include() 15 | #import 16 | #elif __has_include() 17 | #import 18 | #else 19 | #import "YYAnimatedImageView.h" 20 | #endif 21 | 22 | NS_ASSUME_NONNULL_BEGIN 23 | 24 | /** 25 | An image to display sprite sheet animation. 26 | 27 | @discussion It is a fully compatible `UIImage` subclass. 28 | The animation can be played by YYAnimatedImageView. 29 | 30 | Sample Code: 31 | 32 | // 8 * 12 sprites in a single sheet image 33 | UIImage *spriteSheet = [UIImage imageNamed:@"sprite-sheet"]; 34 | NSMutableArray *contentRects = [NSMutableArray new]; 35 | NSMutableArray *durations = [NSMutableArray new]; 36 | for (int j = 0; j < 12; j++) { 37 | for (int i = 0; i < 8; i++) { 38 | CGRect rect; 39 | rect.size = CGSizeMake(img.size.width / 8, img.size.height / 12); 40 | rect.origin.x = img.size.width / 8 * i; 41 | rect.origin.y = img.size.height / 12 * j; 42 | [contentRects addObject:[NSValue valueWithCGRect:rect]]; 43 | [durations addObject:@(1 / 60.0)]; 44 | } 45 | } 46 | YYSpriteSheetImage *sprite; 47 | sprite = [[YYSpriteSheetImage alloc] initWithSpriteSheetImage:img 48 | contentRects:contentRects 49 | frameDurations:durations 50 | loopCount:0]; 51 | YYAnimatedImageView *imgView = [YYAnimatedImageView new]; 52 | imgView.size = CGSizeMake(img.size.width / 8, img.size.height / 12); 53 | imgView.image = sprite; 54 | 55 | 56 | 57 | @discussion It can also be used to display single frame in sprite sheet image. 58 | Sample Code: 59 | 60 | YYSpriteSheetImage *sheet = ...; 61 | UIImageView *imageView = ...; 62 | imageView.image = sheet; 63 | imageView.layer.contentsRect = [sheet contentsRectForCALayerAtIndex:6]; 64 | 65 | */ 66 | @interface YYSpriteSheetImage : UIImage 67 | 68 | /** 69 | Creates and returns an image object. 70 | 71 | @param image The sprite sheet image (contains all frames). 72 | 73 | @param contentRects The sprite sheet image frame rects in the image coordinates. 74 | The rectangle should not outside the image's bounds. The objects in this array 75 | should be created with [NSValue valueWithCGRect:]. 76 | 77 | @param frameDurations The sprite sheet image frame's durations in seconds. 78 | The objects in this array should be NSNumber. 79 | 80 | @param loopCount Animation loop count, 0 means infinite looping. 81 | 82 | @return An image object, or nil if an error occurs. 83 | */ 84 | - (nullable instancetype)initWithSpriteSheetImage:(UIImage *)image 85 | contentRects:(NSArray *)contentRects 86 | frameDurations:(NSArray *)frameDurations 87 | loopCount:(NSUInteger)loopCount; 88 | 89 | @property (nonatomic, readonly) NSArray *contentRects; 90 | @property (nonatomic, readonly) NSArray *frameDurations; 91 | @property (nonatomic, readonly) NSUInteger loopCount; 92 | 93 | /** 94 | Get the contents rect for CALayer. 95 | See "contentsRect" property in CALayer for more information. 96 | 97 | @param index Index of frame. 98 | @return Contents Rect. 99 | */ 100 | - (CGRect)contentsRectForCALayerAtIndex:(NSUInteger)index; 101 | 102 | @end 103 | 104 | NS_ASSUME_NONNULL_END 105 | -------------------------------------------------------------------------------- /PlayCornerRadius/YYImage/YYImage/YYSpriteSheetImage.m: -------------------------------------------------------------------------------- 1 | // 2 | // YYSpriteImage.m 3 | // YYImage 4 | // 5 | // Created by ibireme on 15/4/21. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import "YYSpriteSheetImage.h" 13 | 14 | @implementation YYSpriteSheetImage 15 | 16 | - (instancetype)initWithSpriteSheetImage:(UIImage *)image 17 | contentRects:(NSArray *)contentRects 18 | frameDurations:(NSArray *)frameDurations 19 | loopCount:(NSUInteger)loopCount { 20 | if (!image.CGImage) return nil; 21 | if (contentRects.count < 1 || frameDurations.count < 1) return nil; 22 | if (contentRects.count != frameDurations.count) return nil; 23 | 24 | self = [super initWithCGImage:image.CGImage scale:image.scale orientation:image.imageOrientation]; 25 | if (!self) return nil; 26 | 27 | _contentRects = contentRects.copy; 28 | _frameDurations = frameDurations.copy; 29 | _loopCount = loopCount; 30 | return self; 31 | } 32 | 33 | - (CGRect)contentsRectForCALayerAtIndex:(NSUInteger)index { 34 | CGRect layerRect = CGRectMake(0, 0, 1, 1); 35 | if (index >= _contentRects.count) return layerRect; 36 | 37 | CGSize imageSize = self.size; 38 | CGRect rect = [self animatedImageContentsRectAtIndex:index]; 39 | if (imageSize.width > 0.01 && imageSize.height > 0.01) { 40 | layerRect.origin.x = rect.origin.x / imageSize.width; 41 | layerRect.origin.y = rect.origin.y / imageSize.height; 42 | layerRect.size.width = rect.size.width / imageSize.width; 43 | layerRect.size.height = rect.size.height / imageSize.height; 44 | layerRect = CGRectIntersection(layerRect, CGRectMake(0, 0, 1, 1)); 45 | if (CGRectIsNull(layerRect) || CGRectIsEmpty(layerRect)) { 46 | layerRect = CGRectMake(0, 0, 1, 1); 47 | } 48 | } 49 | return layerRect; 50 | } 51 | 52 | #pragma mark @protocol YYAnimatedImage 53 | 54 | - (NSUInteger)animatedImageFrameCount { 55 | return _contentRects.count; 56 | } 57 | 58 | - (NSUInteger)animatedImageLoopCount { 59 | return _loopCount; 60 | } 61 | 62 | - (NSUInteger)animatedImageBytesPerFrame { 63 | return 0; 64 | } 65 | 66 | - (UIImage *)animatedImageFrameAtIndex:(NSUInteger)index { 67 | return self; 68 | } 69 | 70 | - (NSTimeInterval)animatedImageDurationAtIndex:(NSUInteger)index { 71 | if (index >= _frameDurations.count) return 0; 72 | return ((NSNumber *)_frameDurations[index]).doubleValue; 73 | } 74 | 75 | - (CGRect)animatedImageContentsRectAtIndex:(NSUInteger)index { 76 | if (index >= _contentRects.count) return CGRectZero; 77 | return ((NSValue *)_contentRects[index]).CGRectValue; 78 | } 79 | 80 | @end 81 | -------------------------------------------------------------------------------- /PlayCornerRadius/YYWebImage/YYWebImage/Categories/CALayer+YYWebImage.h: -------------------------------------------------------------------------------- 1 | // 2 | // CALayer+YYWebImage.h 3 | // YYWebImage 4 | // 5 | // Created by ibireme on 15/2/23. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | #import 14 | 15 | #if __has_include() 16 | #import 17 | #else 18 | #import "YYWebImageManager.h" 19 | #endif 20 | 21 | NS_ASSUME_NONNULL_BEGIN 22 | 23 | /** 24 | Web image methods for CALayer. 25 | It will set image to layer.contents. 26 | */ 27 | @interface CALayer (YYWebImage) 28 | 29 | #pragma mark - image 30 | 31 | /** 32 | Current image URL. 33 | 34 | @discussion Set a new value to this property will cancel the previous request 35 | operation and create a new request operation to fetch image. Set nil to clear 36 | the image and image URL. 37 | */ 38 | @property (nullable, nonatomic, strong) NSURL *yy_imageURL; 39 | 40 | /** 41 | Set the view's `image` with a specified URL. 42 | 43 | @param imageURL The image url (remote or local file path). 44 | @param placeholder The image to be set initially, until the image request finishes. 45 | */ 46 | - (void)yy_setImageWithURL:(nullable NSURL *)imageURL placeholder:(nullable UIImage *)placeholder; 47 | 48 | /** 49 | Set the view's `image` with a specified URL. 50 | 51 | @param imageURL The image url (remote or local file path). 52 | @param options The options to use when request the image. 53 | */ 54 | - (void)yy_setImageWithURL:(nullable NSURL *)imageURL options:(YYWebImageOptions)options; 55 | 56 | /** 57 | Set the view's `image` with a specified URL. 58 | 59 | @param imageURL The image url (remote or local file path). 60 | @param placeholder The image to be set initially, until the image request finishes. 61 | @param options The options to use when request the image. 62 | @param completion The block invoked (on main thread) when image request completed. 63 | */ 64 | - (void)yy_setImageWithURL:(nullable NSURL *)imageURL 65 | placeholder:(nullable UIImage *)placeholder 66 | options:(YYWebImageOptions)options 67 | completion:(nullable YYWebImageCompletionBlock)completion; 68 | 69 | /** 70 | Set the view's `image` with a specified URL. 71 | 72 | @param imageURL The image url (remote or local file path). 73 | @param placeholder The image to be set initially, until the image request finishes. 74 | @param options The options to use when request the image. 75 | @param progress The block invoked (on main thread) during image request. 76 | @param transform The block invoked (on background thread) to do additional image process. 77 | @param transformKey 转换key,链接相同但key不同会有不同的缓存 78 | @param completion The block invoked (on main thread) when image request completed. 79 | */ 80 | - (void)yy_setImageWithURL:(nullable NSURL *)imageURL 81 | placeholder:(nullable UIImage *)placeholder 82 | options:(YYWebImageOptions)options 83 | progress:(nullable YYWebImageProgressBlock)progress 84 | transform:(nullable YYWebImageTransformBlock)transform 85 | transformKey:(nullable NSString *)transformKey 86 | completion:(nullable YYWebImageCompletionBlock)completion; 87 | 88 | /** 89 | Set the view's `image` with a specified URL. 90 | 91 | @param imageURL The image url (remote or local file path). 92 | @param placeholder he image to be set initially, until the image request finishes. 93 | @param options The options to use when request the image. 94 | @param manager The manager to create image request operation. 95 | @param progress The block invoked (on main thread) during image request. 96 | @param transform The block invoked (on background thread) to do additional image process. 97 | @param transformKey 转换key,链接相同但key不同会有不同的缓存 98 | @param completion The block invoked (on main thread) when image request completed. 99 | */ 100 | - (void)yy_setImageWithURL:(nullable NSURL *)imageURL 101 | placeholder:(nullable UIImage *)placeholder 102 | options:(YYWebImageOptions)options 103 | manager:(nullable YYWebImageManager *)manager 104 | progress:(nullable YYWebImageProgressBlock)progress 105 | transform:(nullable YYWebImageTransformBlock)transform 106 | transformKey:(nullable NSString *)transformKey 107 | completion:(nullable YYWebImageCompletionBlock)completion; 108 | 109 | /** 110 | Cancel the current image request. 111 | */ 112 | - (void)yy_cancelCurrentImageRequest; 113 | 114 | @end 115 | 116 | NS_ASSUME_NONNULL_END 117 | -------------------------------------------------------------------------------- /PlayCornerRadius/YYWebImage/YYWebImage/Categories/CALayer+YYWebImage.m: -------------------------------------------------------------------------------- 1 | // 2 | // CALayer+YYWebImage.m 3 | // YYWebImage 4 | // 5 | // Created by ibireme on 15/2/23. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import "CALayer+YYWebImage.h" 13 | #import "YYWebImageOperation.h" 14 | #import "_YYWebImageSetter.h" 15 | #import 16 | 17 | // Dummy class for category 18 | @interface CALayer_YYWebImage : NSObject @end 19 | @implementation CALayer_YYWebImage @end 20 | 21 | 22 | static int _YYWebImageSetterKey; 23 | 24 | @implementation CALayer (YYWebImage) 25 | 26 | - (NSURL *)yy_imageURL { 27 | _YYWebImageSetter *setter = objc_getAssociatedObject(self, &_YYWebImageSetterKey); 28 | return setter.imageURL; 29 | } 30 | 31 | - (void)setYy_imageURL:(NSURL *)imageURL { 32 | [self yy_setImageWithURL:imageURL 33 | placeholder:nil 34 | options:kNilOptions 35 | manager:nil 36 | progress:nil 37 | transform:nil 38 | transformKey:nil 39 | completion:nil]; 40 | } 41 | 42 | - (void)yy_setImageWithURL:(NSURL *)imageURL placeholder:(UIImage *)placeholder { 43 | [self yy_setImageWithURL:imageURL 44 | placeholder:placeholder 45 | options:kNilOptions 46 | manager:nil 47 | progress:nil 48 | transform:nil 49 | transformKey:nil 50 | completion:nil]; 51 | } 52 | 53 | - (void)yy_setImageWithURL:(NSURL *)imageURL options:(YYWebImageOptions)options { 54 | [self yy_setImageWithURL:imageURL 55 | placeholder:nil 56 | options:options 57 | manager:nil 58 | progress:nil 59 | transform:nil 60 | transformKey:nil 61 | completion:nil]; 62 | } 63 | 64 | - (void)yy_setImageWithURL:(NSURL *)imageURL 65 | placeholder:(UIImage *)placeholder 66 | options:(YYWebImageOptions)options 67 | completion:(YYWebImageCompletionBlock)completion { 68 | [self yy_setImageWithURL:imageURL 69 | placeholder:placeholder 70 | options:options 71 | manager:nil 72 | progress:nil 73 | transform:nil 74 | transformKey:nil 75 | completion:completion]; 76 | } 77 | 78 | - (void)yy_setImageWithURL:(NSURL *)imageURL 79 | placeholder:(UIImage *)placeholder 80 | options:(YYWebImageOptions)options 81 | progress:(YYWebImageProgressBlock)progress 82 | transform:(YYWebImageTransformBlock)transform 83 | transformKey:(nullable NSString *)transformKey 84 | completion:(YYWebImageCompletionBlock)completion { 85 | [self yy_setImageWithURL:imageURL 86 | placeholder:placeholder 87 | options:options 88 | manager:nil 89 | progress:progress 90 | transform:transform 91 | transformKey:transformKey 92 | completion:completion]; 93 | } 94 | 95 | - (void)yy_setImageWithURL:(NSURL *)imageURL 96 | placeholder:(UIImage *)placeholder 97 | options:(YYWebImageOptions)options 98 | manager:(YYWebImageManager *)manager 99 | progress:(YYWebImageProgressBlock)progress 100 | transform:(YYWebImageTransformBlock)transform 101 | transformKey:(nullable NSString *)transformKey 102 | completion:(YYWebImageCompletionBlock)completion { 103 | if ([imageURL isKindOfClass:[NSString class]]) imageURL = [NSURL URLWithString:(id)imageURL]; 104 | manager = manager ? manager : [YYWebImageManager sharedManager]; 105 | 106 | 107 | _YYWebImageSetter *setter = objc_getAssociatedObject(self, &_YYWebImageSetterKey); 108 | if (!setter) { 109 | setter = [_YYWebImageSetter new]; 110 | objc_setAssociatedObject(self, &_YYWebImageSetterKey, setter, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 111 | } 112 | int32_t sentinel = [setter cancelWithNewURL:imageURL]; 113 | 114 | _yy_dispatch_sync_on_main_queue(^{ 115 | if ((options & YYWebImageOptionSetImageWithFadeAnimation) && 116 | !(options & YYWebImageOptionAvoidSetImage)) { 117 | [self removeAnimationForKey:_YYWebImageFadeAnimationKey]; 118 | } 119 | 120 | if (!imageURL) { 121 | if (!(options & YYWebImageOptionIgnorePlaceHolder)) { 122 | self.contents = (id)placeholder.CGImage; 123 | } 124 | return; 125 | } 126 | 127 | // get the image from memory as quickly as possible 128 | UIImage *imageFromMemory = nil; 129 | if (manager.cache && 130 | !(options & YYWebImageOptionUseNSURLCache) && 131 | !(options & YYWebImageOptionRefreshImageCache)) { 132 | imageFromMemory = [manager.cache getImageForKey:[manager cacheKeyForURL:imageURL transformKey:transformKey 133 | ] withType:YYImageCacheTypeMemory]; 134 | } 135 | if (imageFromMemory) { 136 | if (!(options & YYWebImageOptionAvoidSetImage)) { 137 | self.contents = (id)imageFromMemory.CGImage; 138 | } 139 | if(completion) completion(imageFromMemory, imageURL, YYWebImageFromMemoryCacheFast, YYWebImageStageFinished, nil); 140 | return; 141 | } 142 | 143 | if (!(options & YYWebImageOptionIgnorePlaceHolder)) { 144 | self.contents = (id)placeholder.CGImage; 145 | } 146 | 147 | __weak typeof(self) _self = self; 148 | dispatch_async([_YYWebImageSetter setterQueue], ^{ 149 | YYWebImageProgressBlock _progress = nil; 150 | if (progress) _progress = ^(NSInteger receivedSize, NSInteger expectedSize) { 151 | dispatch_async(dispatch_get_main_queue(), ^{ 152 | progress(receivedSize, expectedSize); 153 | }); 154 | }; 155 | 156 | __block int32_t newSentinel = 0; 157 | __block __weak typeof(setter) weakSetter = nil; 158 | YYWebImageCompletionBlock _completion = ^(UIImage *image, NSURL *url, YYWebImageFromType from, YYWebImageStage stage, NSError *error) { 159 | __strong typeof(_self) self = _self; 160 | BOOL setImage = (stage == YYWebImageStageFinished || stage == YYWebImageStageProgress) && image && !(options & YYWebImageOptionAvoidSetImage); 161 | BOOL showFade = (options & YYWebImageOptionSetImageWithFadeAnimation); 162 | dispatch_async(dispatch_get_main_queue(), ^{ 163 | BOOL sentinelChanged = weakSetter && weakSetter.sentinel != newSentinel; 164 | if (setImage && self && !sentinelChanged) { 165 | if (showFade) { 166 | CATransition *transition = [CATransition animation]; 167 | transition.duration = stage == YYWebImageStageFinished ? _YYWebImageFadeTime : _YYWebImageProgressiveFadeTime; 168 | transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; 169 | transition.type = kCATransitionFade; 170 | [self addAnimation:transition forKey:_YYWebImageFadeAnimationKey]; 171 | } 172 | self.contents = (id)image.CGImage; 173 | } 174 | if (completion) { 175 | if (sentinelChanged) { 176 | completion(nil, url, YYWebImageFromNone, YYWebImageStageCancelled, nil); 177 | } else { 178 | completion(image, url, from, stage, error); 179 | } 180 | } 181 | }); 182 | }; 183 | 184 | newSentinel = [setter setOperationWithSentinel:sentinel url:imageURL options:options manager:manager progress:_progress transform:transform transformKey:transformKey completion:_completion]; 185 | weakSetter = setter; 186 | }); 187 | 188 | 189 | }); 190 | } 191 | 192 | - (void)yy_cancelCurrentImageRequest { 193 | _YYWebImageSetter *setter = objc_getAssociatedObject(self, &_YYWebImageSetterKey); 194 | if (setter) [setter cancel]; 195 | } 196 | 197 | @end 198 | -------------------------------------------------------------------------------- /PlayCornerRadius/YYWebImage/YYWebImage/Categories/MKAnnotationView+YYWebImage.h: -------------------------------------------------------------------------------- 1 | // 2 | // MKAnnotationView+YYWebImage.h 3 | // YYWebImage 4 | // 5 | // Created by ibireme on 15/2/23. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | #import 14 | 15 | #if __has_include() 16 | #import 17 | #else 18 | #import "YYWebImageManager.h" 19 | #endif 20 | 21 | NS_ASSUME_NONNULL_BEGIN 22 | 23 | /** 24 | Web image methods for MKAnnotationView. 25 | */ 26 | @interface MKAnnotationView (YYWebImage) 27 | 28 | /** 29 | Current image URL. 30 | 31 | @discussion Set a new value to this property will cancel the previous request 32 | operation and create a new request operation to fetch image. Set nil to clear 33 | the image and image URL. 34 | */ 35 | @property (nullable, nonatomic, strong) NSURL *yy_imageURL; 36 | 37 | /** 38 | Set the view's `image` with a specified URL. 39 | 40 | @param imageURL The image url (remote or local file path). 41 | @param placeholder The image to be set initially, until the image request finishes. 42 | */ 43 | - (void)yy_setImageWithURL:(nullable NSURL *)imageURL placeholder:(nullable UIImage *)placeholder; 44 | 45 | /** 46 | Set the view's `image` with a specified URL. 47 | 48 | @param imageURL The image url (remote or local file path). 49 | @param options The options to use when request the image. 50 | */ 51 | - (void)yy_setImageWithURL:(nullable NSURL *)imageURL options:(YYWebImageOptions)options; 52 | 53 | /** 54 | Set the view's `image` with a specified URL. 55 | 56 | @param imageURL The image url (remote or local file path). 57 | @param placeholder The image to be set initially, until the image request finishes. 58 | @param options The options to use when request the image. 59 | @param completion The block invoked (on main thread) when image request completed. 60 | */ 61 | - (void)yy_setImageWithURL:(nullable NSURL *)imageURL 62 | placeholder:(nullable UIImage *)placeholder 63 | options:(YYWebImageOptions)options 64 | completion:(nullable YYWebImageCompletionBlock)completion; 65 | 66 | /** 67 | Set the view's `image` with a specified URL. 68 | 69 | @param imageURL The image url (remote or local file path). 70 | @param placeholder The image to be set initially, until the image request finishes. 71 | @param options The options to use when request the image. 72 | @param progress The block invoked (on main thread) during image request. 73 | @param transform The block invoked (on background thread) to do additional image process. 74 | @param transformKey 转换key,链接相同但key不同会有不同的缓存 75 | @param completion The block invoked (on main thread) when image request completed. 76 | */ 77 | - (void)yy_setImageWithURL:(nullable NSURL *)imageURL 78 | placeholder:(nullable UIImage *)placeholder 79 | options:(YYWebImageOptions)options 80 | progress:(nullable YYWebImageProgressBlock)progress 81 | transform:(nullable YYWebImageTransformBlock)transform 82 | transformKey:(nullable NSString *)transformKey 83 | completion:(nullable YYWebImageCompletionBlock)completion; 84 | 85 | /** 86 | Set the view's `image` with a specified URL. 87 | 88 | @param imageURL The image url (remote or local file path). 89 | @param placeholder he image to be set initially, until the image request finishes. 90 | @param options The options to use when request the image. 91 | @param manager The manager to create image request operation. 92 | @param progress The block invoked (on main thread) during image request. 93 | @param transform The block invoked (on background thread) to do additional image process. 94 | @param transformKey 转换key,链接相同但key不同会有不同的缓存 95 | @param completion The block invoked (on main thread) when image request completed. 96 | */ 97 | - (void)yy_setImageWithURL:(nullable NSURL *)imageURL 98 | placeholder:(nullable UIImage *)placeholder 99 | options:(YYWebImageOptions)options 100 | manager:(nullable YYWebImageManager *)manager 101 | progress:(nullable YYWebImageProgressBlock)progress 102 | transform:(nullable YYWebImageTransformBlock)transform 103 | transformKey:(nullable NSString *)transformKey 104 | completion:(nullable YYWebImageCompletionBlock)completion; 105 | 106 | /** 107 | Cancel the current image request. 108 | */ 109 | - (void)yy_cancelCurrentImageRequest; 110 | 111 | @end 112 | 113 | NS_ASSUME_NONNULL_END 114 | -------------------------------------------------------------------------------- /PlayCornerRadius/YYWebImage/YYWebImage/Categories/MKAnnotationView+YYWebImage.m: -------------------------------------------------------------------------------- 1 | // 2 | // MKAnnotationView+YYWebImage.m 3 | // YYWebImage 4 | // 5 | // Created by ibireme on 15/2/23. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import "MKAnnotationView+YYWebImage.h" 13 | #import "YYWebImageOperation.h" 14 | #import "_YYWebImageSetter.h" 15 | #import 16 | 17 | // Dummy class for category 18 | @interface MKAnnotationView_YYWebImage : NSObject @end 19 | @implementation MKAnnotationView_YYWebImage @end 20 | 21 | 22 | static int _YYWebImageSetterKey; 23 | 24 | @implementation MKAnnotationView (YYWebImage) 25 | 26 | - (NSURL *)yy_imageURL { 27 | _YYWebImageSetter *setter = objc_getAssociatedObject(self, &_YYWebImageSetterKey); 28 | return setter.imageURL; 29 | } 30 | 31 | - (void)setYy_imageURL:(NSURL *)imageURL { 32 | [self yy_setImageWithURL:imageURL 33 | placeholder:nil 34 | options:kNilOptions 35 | manager:nil 36 | progress:nil 37 | transform:nil 38 | transformKey:nil 39 | completion:nil]; 40 | } 41 | 42 | - (void)yy_setImageWithURL:(NSURL *)imageURL placeholder:(UIImage *)placeholder { 43 | [self yy_setImageWithURL:imageURL 44 | placeholder:placeholder 45 | options:kNilOptions 46 | manager:nil 47 | progress:nil 48 | transform:nil 49 | transformKey:nil 50 | completion:nil]; 51 | } 52 | 53 | - (void)yy_setImageWithURL:(NSURL *)imageURL options:(YYWebImageOptions)options { 54 | [self yy_setImageWithURL:imageURL 55 | placeholder:nil 56 | options:options 57 | manager:nil 58 | progress:nil 59 | transform:nil 60 | transformKey:nil 61 | completion:nil]; 62 | } 63 | 64 | - (void)yy_setImageWithURL:(NSURL *)imageURL 65 | placeholder:(UIImage *)placeholder 66 | options:(YYWebImageOptions)options 67 | completion:(YYWebImageCompletionBlock)completion { 68 | [self yy_setImageWithURL:imageURL 69 | placeholder:placeholder 70 | options:options 71 | manager:nil 72 | progress:nil 73 | transform:nil 74 | transformKey:nil 75 | completion:completion]; 76 | } 77 | 78 | - (void)yy_setImageWithURL:(NSURL *)imageURL 79 | placeholder:(UIImage *)placeholder 80 | options:(YYWebImageOptions)options 81 | progress:(YYWebImageProgressBlock)progress 82 | transform:(YYWebImageTransformBlock)transform 83 | transformKey:(nullable NSString *)transformKey 84 | completion:(YYWebImageCompletionBlock)completion { 85 | [self yy_setImageWithURL:imageURL 86 | placeholder:placeholder 87 | options:options 88 | manager:nil 89 | progress:progress 90 | transform:transform 91 | transformKey:transformKey 92 | completion:completion]; 93 | } 94 | 95 | - (void)yy_setImageWithURL:(NSURL *)imageURL 96 | placeholder:(UIImage *)placeholder 97 | options:(YYWebImageOptions)options 98 | manager:(YYWebImageManager *)manager 99 | progress:(YYWebImageProgressBlock)progress 100 | transform:(YYWebImageTransformBlock)transform 101 | transformKey:(nullable NSString *)transformKey 102 | completion:(YYWebImageCompletionBlock)completion { 103 | if ([imageURL isKindOfClass:[NSString class]]) imageURL = [NSURL URLWithString:(id)imageURL]; 104 | manager = manager ? manager : [YYWebImageManager sharedManager]; 105 | 106 | _YYWebImageSetter *setter = objc_getAssociatedObject(self, &_YYWebImageSetterKey); 107 | if (!setter) { 108 | setter = [_YYWebImageSetter new]; 109 | objc_setAssociatedObject(self, &_YYWebImageSetterKey, setter, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 110 | } 111 | int32_t sentinel = [setter cancelWithNewURL:imageURL]; 112 | 113 | _yy_dispatch_sync_on_main_queue(^{ 114 | if ((options & YYWebImageOptionSetImageWithFadeAnimation) && 115 | !(options & YYWebImageOptionAvoidSetImage)) { 116 | if (!self.highlighted) { 117 | [self.layer removeAnimationForKey:_YYWebImageFadeAnimationKey]; 118 | } 119 | } 120 | if (!imageURL) { 121 | if (!(options & YYWebImageOptionIgnorePlaceHolder)) { 122 | self.image = placeholder; 123 | } 124 | return; 125 | } 126 | 127 | // get the image from memory as quickly as possible 128 | UIImage *imageFromMemory = nil; 129 | if (manager.cache && 130 | !(options & YYWebImageOptionUseNSURLCache) && 131 | !(options & YYWebImageOptionRefreshImageCache)) { 132 | imageFromMemory = [manager.cache getImageForKey:[manager cacheKeyForURL:imageURL transformKey:transformKey] withType:YYImageCacheTypeMemory]; 133 | } 134 | if (imageFromMemory) { 135 | if (!(options & YYWebImageOptionAvoidSetImage)) { 136 | self.image = imageFromMemory; 137 | } 138 | if(completion) completion(imageFromMemory, imageURL, YYWebImageFromMemoryCacheFast, YYWebImageStageFinished, nil); 139 | return; 140 | } 141 | 142 | if (!(options & YYWebImageOptionIgnorePlaceHolder)) { 143 | self.image = placeholder; 144 | } 145 | 146 | __weak typeof(self) _self = self; 147 | dispatch_async([_YYWebImageSetter setterQueue], ^{ 148 | YYWebImageProgressBlock _progress = nil; 149 | if (progress) _progress = ^(NSInteger receivedSize, NSInteger expectedSize) { 150 | dispatch_async(dispatch_get_main_queue(), ^{ 151 | progress(receivedSize, expectedSize); 152 | }); 153 | }; 154 | 155 | __block int32_t newSentinel = 0; 156 | __block __weak typeof(setter) weakSetter = nil; 157 | YYWebImageCompletionBlock _completion = ^(UIImage *image, NSURL *url, YYWebImageFromType from, YYWebImageStage stage, NSError *error) { 158 | __strong typeof(_self) self = _self; 159 | BOOL setImage = (stage == YYWebImageStageFinished || stage == YYWebImageStageProgress) && image && !(options & YYWebImageOptionAvoidSetImage); 160 | BOOL showFade = ((options & YYWebImageOptionSetImageWithFadeAnimation) && !self.highlighted); 161 | dispatch_async(dispatch_get_main_queue(), ^{ 162 | BOOL sentinelChanged = weakSetter && weakSetter.sentinel != newSentinel; 163 | if (setImage && self && !sentinelChanged) { 164 | if (showFade) { 165 | CATransition *transition = [CATransition animation]; 166 | transition.duration = stage == YYWebImageStageFinished ? _YYWebImageFadeTime : _YYWebImageProgressiveFadeTime; 167 | transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; 168 | transition.type = kCATransitionFade; 169 | [self.layer addAnimation:transition forKey:_YYWebImageFadeAnimationKey]; 170 | } 171 | self.image = image; 172 | } 173 | if (completion) { 174 | if (sentinelChanged) { 175 | completion(nil, url, YYWebImageFromNone, YYWebImageStageCancelled, nil); 176 | } else { 177 | completion(image, url, from, stage, error); 178 | } 179 | } 180 | }); 181 | }; 182 | 183 | newSentinel = [setter setOperationWithSentinel:sentinel url:imageURL options:options manager:manager progress:_progress transform:transform transformKey:transformKey completion:_completion]; 184 | weakSetter = setter; 185 | }); 186 | }); 187 | } 188 | 189 | - (void)yy_cancelCurrentImageRequest { 190 | _YYWebImageSetter *setter = objc_getAssociatedObject(self, &_YYWebImageSetterKey); 191 | if (setter) [setter cancel]; 192 | } 193 | 194 | @end 195 | -------------------------------------------------------------------------------- /PlayCornerRadius/YYWebImage/YYWebImage/Categories/UIButton+YYWebImage.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIButton+YYWebImage.h 3 | // YYWebImage 4 | // 5 | // Created by ibireme on 15/2/23. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | 14 | #if __has_include() 15 | #import 16 | #else 17 | #import "YYWebImageManager.h" 18 | #endif 19 | 20 | NS_ASSUME_NONNULL_BEGIN 21 | 22 | /** 23 | Web image methods for UIButton. 24 | */ 25 | @interface UIButton (YYWebImage) 26 | 27 | #pragma mark - image 28 | 29 | /** 30 | Current image URL for the specified state. 31 | @return The image URL, or nil. 32 | */ 33 | - (nullable NSURL *)yy_imageURLForState:(UIControlState)state; 34 | 35 | /** 36 | Set the button's image with a specified URL for the specified state. 37 | 38 | @param imageURL The image url (remote or local file path). 39 | @param state The state that uses the specified image. 40 | @param placeholder The image to be set initially, until the image request finishes. 41 | */ 42 | - (void)yy_setImageWithURL:(nullable NSURL *)imageURL 43 | forState:(UIControlState)state 44 | placeholder:(nullable UIImage *)placeholder; 45 | 46 | /** 47 | Set the button's image with a specified URL for the specified state. 48 | 49 | @param imageURL The image url (remote or local file path). 50 | @param state The state that uses the specified image. 51 | @param options The options to use when request the image. 52 | */ 53 | - (void)yy_setImageWithURL:(nullable NSURL *)imageURL 54 | forState:(UIControlState)state 55 | options:(YYWebImageOptions)options; 56 | 57 | /** 58 | Set the button's image with a specified URL for the specified state. 59 | 60 | @param imageURL The image url (remote or local file path). 61 | @param state The state that uses the specified image. 62 | @param placeholder The image to be set initially, until the image request finishes. 63 | @param options The options to use when request the image. 64 | @param completion The block invoked (on main thread) when image request completed. 65 | */ 66 | - (void)yy_setImageWithURL:(nullable NSURL *)imageURL 67 | forState:(UIControlState)state 68 | placeholder:(nullable UIImage *)placeholder 69 | options:(YYWebImageOptions)options 70 | completion:(nullable YYWebImageCompletionBlock)completion; 71 | 72 | /** 73 | Set the button's image with a specified URL for the specified state. 74 | 75 | @param imageURL The image url (remote or local file path). 76 | @param state The state that uses the specified image. 77 | @param placeholder The image to be set initially, until the image request finishes. 78 | @param options The options to use when request the image. 79 | @param progress The block invoked (on main thread) during image request. 80 | @param transform The block invoked (on background thread) to do additional image process. 81 | @param transformKey 转换key,链接相同但key不同会有不同的缓存 82 | @param completion The block invoked (on main thread) when image request completed. 83 | */ 84 | - (void)yy_setImageWithURL:(nullable NSURL *)imageURL 85 | forState:(UIControlState)state 86 | placeholder:(nullable UIImage *)placeholder 87 | options:(YYWebImageOptions)options 88 | progress:(nullable YYWebImageProgressBlock)progress 89 | transform:(nullable YYWebImageTransformBlock)transform 90 | transformKey:(nullable NSString *)transformKey 91 | completion:(nullable YYWebImageCompletionBlock)completion; 92 | 93 | /** 94 | Set the button's image with a specified URL for the specified state. 95 | 96 | @param imageURL The image url (remote or local file path). 97 | @param state The state that uses the specified image. 98 | @param placeholder The image to be set initially, until the image request finishes. 99 | @param options The options to use when request the image. 100 | @param manager The manager to create image request operation. 101 | @param progress The block invoked (on main thread) during image request. 102 | @param transform The block invoked (on background thread) to do additional image process. 103 | @param transformKey 转换key,链接相同但key不同会有不同的缓存 104 | @param completion The block invoked (on main thread) when image request completed. 105 | */ 106 | - (void)yy_setImageWithURL:(nullable NSURL *)imageURL 107 | forState:(UIControlState)state 108 | placeholder:(nullable UIImage *)placeholder 109 | options:(YYWebImageOptions)options 110 | manager:(nullable YYWebImageManager *)manager 111 | progress:(nullable YYWebImageProgressBlock)progress 112 | transform:(nullable YYWebImageTransformBlock)transform 113 | transformKey:(nullable NSString *)transformKey 114 | completion:(nullable YYWebImageCompletionBlock)completion; 115 | 116 | /** 117 | Cancel the current image request for a specified state. 118 | @param state The state that uses the specified image. 119 | */ 120 | - (void)yy_cancelImageRequestForState:(UIControlState)state; 121 | 122 | 123 | 124 | #pragma mark - background image 125 | 126 | /** 127 | Current backgroundImage URL for the specified state. 128 | @return The image URL, or nil. 129 | */ 130 | - (nullable NSURL *)yy_backgroundImageURLForState:(UIControlState)state; 131 | 132 | /** 133 | Set the button's backgroundImage with a specified URL for the specified state. 134 | 135 | @param imageURL The image url (remote or local file path). 136 | @param state The state that uses the specified image. 137 | @param placeholder The image to be set initially, until the image request finishes. 138 | */ 139 | - (void)yy_setBackgroundImageWithURL:(nullable NSURL *)imageURL 140 | forState:(UIControlState)state 141 | placeholder:(nullable UIImage *)placeholder; 142 | 143 | /** 144 | Set the button's backgroundImage with a specified URL for the specified state. 145 | 146 | @param imageURL The image url (remote or local file path). 147 | @param state The state that uses the specified image. 148 | @param options The options to use when request the image. 149 | */ 150 | - (void)yy_setBackgroundImageWithURL:(nullable NSURL *)imageURL 151 | forState:(UIControlState)state 152 | options:(YYWebImageOptions)options; 153 | 154 | /** 155 | Set the button's backgroundImage with a specified URL for the specified state. 156 | 157 | @param imageURL The image url (remote or local file path). 158 | @param state The state that uses the specified image. 159 | @param placeholder The image to be set initially, until the image request finishes. 160 | @param options The options to use when request the image. 161 | @param completion The block invoked (on main thread) when image request completed. 162 | */ 163 | - (void)yy_setBackgroundImageWithURL:(nullable NSURL *)imageURL 164 | forState:(UIControlState)state 165 | placeholder:(nullable UIImage *)placeholder 166 | options:(YYWebImageOptions)options 167 | completion:(nullable YYWebImageCompletionBlock)completion; 168 | 169 | /** 170 | Set the button's backgroundImage with a specified URL for the specified state. 171 | 172 | @param imageURL The image url (remote or local file path). 173 | @param state The state that uses the specified image. 174 | @param placeholder The image to be set initially, until the image request finishes. 175 | @param options The options to use when request the image. 176 | @param progress The block invoked (on main thread) during image request. 177 | @param transform The block invoked (on background thread) to do additional image process. 178 | @param transformKey 转换key,链接相同但key不同会有不同的缓存 179 | @param completion The block invoked (on main thread) when image request completed. 180 | */ 181 | - (void)yy_setBackgroundImageWithURL:(nullable NSURL *)imageURL 182 | forState:(UIControlState)state 183 | placeholder:(nullable UIImage *)placeholder 184 | options:(YYWebImageOptions)options 185 | progress:(nullable YYWebImageProgressBlock)progress 186 | transform:(nullable YYWebImageTransformBlock)transform 187 | transformKey:(nullable NSString *)transformKey 188 | completion:(nullable YYWebImageCompletionBlock)completion; 189 | 190 | /** 191 | Set the button's backgroundImage with a specified URL for the specified state. 192 | 193 | @param imageURL The image url (remote or local file path). 194 | @param state The state that uses the specified image. 195 | @param placeholder The image to be set initially, until the image request finishes. 196 | @param options The options to use when request the image. 197 | @param manager The manager to create image request operation. 198 | @param progress The block invoked (on main thread) during image request. 199 | @param transform The block invoked (on background thread) to do additional image process. 200 | @param transformKey 转换key,链接相同但key不同会有不同的缓存 201 | @param completion The block invoked (on main thread) when image request completed. 202 | */ 203 | - (void)yy_setBackgroundImageWithURL:(nullable NSURL *)imageURL 204 | forState:(UIControlState)state 205 | placeholder:(nullable UIImage *)placeholder 206 | options:(YYWebImageOptions)options 207 | manager:(nullable YYWebImageManager *)manager 208 | progress:(nullable YYWebImageProgressBlock)progress 209 | transform:(nullable YYWebImageTransformBlock)transform 210 | transformKey:(nullable NSString *)transformKey 211 | completion:(nullable YYWebImageCompletionBlock)completion; 212 | 213 | /** 214 | Cancel the current backgroundImage request for a specified state. 215 | @param state The state that uses the specified image. 216 | */ 217 | - (void)yy_cancelBackgroundImageRequestForState:(UIControlState)state; 218 | 219 | @end 220 | 221 | NS_ASSUME_NONNULL_END 222 | -------------------------------------------------------------------------------- /PlayCornerRadius/YYWebImage/YYWebImage/Categories/UIImage+YYWebImage.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+YYWebImage.h 3 | // YYWebImage 4 | // 5 | // Created by ibireme on 13/4/4. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | 14 | NS_ASSUME_NONNULL_BEGIN 15 | 16 | /** 17 | Provide some commen method for `UIImage`. 18 | Image process is based on CoreGraphic and vImage. 19 | */ 20 | @interface UIImage (YYWebImage) 21 | 22 | #pragma mark - Create image 23 | ///============================================================================= 24 | /// @name Create image 25 | ///============================================================================= 26 | 27 | /** 28 | Create an animated image with GIF data. After created, you can access 29 | the images via property '.images'. If the data is not animated gif, this 30 | function is same as [UIImage imageWithData:data scale:scale]; 31 | 32 | @discussion It has a better display performance, but costs more memory 33 | (width * height * frames Bytes). It only suited to display small 34 | gif such as animated emoticon. If you want to display large gif, 35 | see `YYImage`. 36 | 37 | @param data GIF data. 38 | 39 | @param scale The scale factor 40 | 41 | @return A new image created from GIF, or nil when an error occurs. 42 | */ 43 | + (nullable UIImage *)yy_imageWithSmallGIFData:(NSData *)data scale:(CGFloat)scale; 44 | 45 | /** 46 | Create and return a 1x1 point size image with the given color. 47 | 48 | @param color The color. 49 | */ 50 | + (nullable UIImage *)yy_imageWithColor:(UIColor *)color; 51 | 52 | /** 53 | Create and return a pure color image with the given color and size. 54 | 55 | @param color The color. 56 | @param size New image's type. 57 | */ 58 | + (nullable UIImage *)yy_imageWithColor:(UIColor *)color size:(CGSize)size; 59 | 60 | /** 61 | Create and return an image with custom draw code. 62 | 63 | @param size The image size. 64 | @param drawBlock The draw block. 65 | 66 | @return The new image. 67 | */ 68 | + (nullable UIImage *)yy_imageWithSize:(CGSize)size drawBlock:(void (^)(CGContextRef context))drawBlock; 69 | 70 | #pragma mark - Image Info 71 | ///============================================================================= 72 | /// @name Image Info 73 | ///============================================================================= 74 | 75 | /** 76 | Whether this image has alpha channel. 77 | */ 78 | - (BOOL)yy_hasAlphaChannel; 79 | 80 | 81 | #pragma mark - Modify Image 82 | ///============================================================================= 83 | /// @name Modify Image 84 | ///============================================================================= 85 | 86 | /** 87 | Draws the entire image in the specified rectangle, content changed with 88 | the contentMode. 89 | 90 | @discussion This method draws the entire image in the current graphics context, 91 | respecting the image's orientation setting. In the default coordinate system, 92 | images are situated down and to the right of the origin of the specified 93 | rectangle. This method respects any transforms applied to the current graphics 94 | context, however. 95 | 96 | @param rect The rectangle in which to draw the image. 97 | 98 | @param contentMode Draw content mode 99 | 100 | @param clips A Boolean value that determines whether content are confined to the rect. 101 | */ 102 | - (void)yy_drawInRect:(CGRect)rect withContentMode:(UIViewContentMode)contentMode clipsToBounds:(BOOL)clips; 103 | 104 | /** 105 | Returns a new image which is scaled from this image. 106 | The image will be stretched as needed. 107 | 108 | @param size The new size to be scaled, values should be positive. 109 | 110 | @return The new image with the given size. 111 | */ 112 | - (nullable UIImage *)yy_imageByResizeToSize:(CGSize)size; 113 | 114 | /** 115 | Returns a new image which is scaled from this image. 116 | The image content will be changed with thencontentMode. 117 | 118 | @param size The new size to be scaled, values should be positive. 119 | 120 | @param contentMode The content mode for image content. 121 | 122 | @return The new image with the given size. 123 | */ 124 | - (nullable UIImage *)yy_imageByResizeToSize:(CGSize)size contentMode:(UIViewContentMode)contentMode; 125 | 126 | /** 127 | Returns a new image which is cropped from this image. 128 | 129 | @param rect Image's inner rect. 130 | 131 | @return The new image, or nil if an error occurs. 132 | */ 133 | - (nullable UIImage *)yy_imageByCropToRect:(CGRect)rect; 134 | 135 | /** 136 | Returns a new image which is edge inset from this image. 137 | 138 | @param insets Inset (positive) for each of the edges, values can be negative to 'outset'. 139 | 140 | @param color Extend edge's fill color, nil means clear color. 141 | 142 | @return The new image, or nil if an error occurs. 143 | */ 144 | - (nullable UIImage *)yy_imageByInsetEdge:(UIEdgeInsets)insets withColor:(nullable UIColor *)color; 145 | 146 | /** 147 | Rounds a new image with a given corner size. 148 | 149 | @param radius The radius of each corner oval. Values larger than half the 150 | rectangle's width or height are clamped appropriately to half 151 | the width or height. 152 | */ 153 | - (nullable UIImage *)yy_imageByRoundCornerRadius:(CGFloat)radius; 154 | 155 | /** 156 | Rounds a new image with a given corner size. 157 | 158 | @param radius The radius of each corner oval. Values larger than half the 159 | rectangle's width or height are clamped appropriately to 160 | half the width or height. 161 | 162 | @param borderWidth The inset border line width. Values larger than half the rectangle's 163 | width or height are clamped appropriately to half the width 164 | or height. 165 | 166 | @param borderColor The border stroke color. nil means clear color. 167 | */ 168 | - (nullable UIImage *)yy_imageByRoundCornerRadius:(CGFloat)radius 169 | borderWidth:(CGFloat)borderWidth 170 | borderColor:(nullable UIColor *)borderColor; 171 | 172 | /** 173 | Rounds a new image with a given corner size. 174 | 175 | @param radius The radius of each corner oval. Values larger than half the 176 | rectangle's width or height are clamped appropriately to 177 | half the width or height. 178 | 179 | @param corners A bitmask value that identifies the corners that you want 180 | rounded. You can use this parameter to round only a subset 181 | of the corners of the rectangle. 182 | 183 | @param borderWidth The inset border line width. Values larger than half the rectangle's 184 | width or height are clamped appropriately to half the width 185 | or height. 186 | 187 | @param borderColor The border stroke color. nil means clear color. 188 | 189 | @param borderLineJoin The border line join. 190 | */ 191 | - (nullable UIImage *)yy_imageByRoundCornerRadius:(CGFloat)radius 192 | corners:(UIRectCorner)corners 193 | borderWidth:(CGFloat)borderWidth 194 | borderColor:(nullable UIColor *)borderColor 195 | borderLineJoin:(CGLineJoin)borderLineJoin; 196 | 197 | /** 198 | Returns a new rotated image (relative to the center). 199 | 200 | @param radians Rotated radians in counterclockwise.⟲ 201 | 202 | @param fitSize YES: new image's size is extend to fit all content. 203 | NO: image's size will not change, content may be clipped. 204 | */ 205 | - (nullable UIImage *)yy_imageByRotate:(CGFloat)radians fitSize:(BOOL)fitSize; 206 | 207 | /** 208 | Returns a new image rotated counterclockwise by a quarter‑turn (90°). ⤺ 209 | The width and height will be exchanged. 210 | */ 211 | - (nullable UIImage *)yy_imageByRotateLeft90; 212 | 213 | /** 214 | Returns a new image rotated clockwise by a quarter‑turn (90°). ⤼ 215 | The width and height will be exchanged. 216 | */ 217 | - (nullable UIImage *)yy_imageByRotateRight90; 218 | 219 | /** 220 | Returns a new image rotated 180° . ↻ 221 | */ 222 | - (nullable UIImage *)yy_imageByRotate180; 223 | 224 | /** 225 | Returns a vertically flipped image. ⥯ 226 | */ 227 | - (nullable UIImage *)yy_imageByFlipVertical; 228 | 229 | /** 230 | Returns a horizontally flipped image. ⇋ 231 | */ 232 | - (nullable UIImage *)yy_imageByFlipHorizontal; 233 | 234 | 235 | #pragma mark - Image Effect 236 | ///============================================================================= 237 | /// @name Image Effect 238 | ///============================================================================= 239 | 240 | /** 241 | Tint the image in alpha channel with the given color. 242 | 243 | @param color The color. 244 | */ 245 | - (nullable UIImage *)yy_imageByTintColor:(UIColor *)color; 246 | 247 | /** 248 | Returns a grayscaled image. 249 | */ 250 | - (nullable UIImage *)yy_imageByGrayscale; 251 | 252 | /** 253 | Applies a blur effect to this image. Suitable for blur any content. 254 | */ 255 | - (nullable UIImage *)yy_imageByBlurSoft; 256 | 257 | /** 258 | Applies a blur effect to this image. Suitable for blur any content except pure white. 259 | (same as iOS Control Panel) 260 | */ 261 | - (nullable UIImage *)yy_imageByBlurLight; 262 | 263 | /** 264 | Applies a blur effect to this image. Suitable for displaying black text. 265 | (same as iOS Navigation Bar White) 266 | */ 267 | - (nullable UIImage *)yy_imageByBlurExtraLight; 268 | 269 | /** 270 | Applies a blur effect to this image. Suitable for displaying white text. 271 | (same as iOS Notification Center) 272 | */ 273 | - (nullable UIImage *)yy_imageByBlurDark; 274 | 275 | /** 276 | Applies a blur and tint color to this image. 277 | 278 | @param tintColor The tint color. 279 | */ 280 | - (nullable UIImage *)yy_imageByBlurWithTint:(UIColor *)tintColor; 281 | 282 | /** 283 | Applies a blur, tint color, and saturation adjustment to this image, 284 | optionally within the area specified by @a maskImage. 285 | 286 | @param blurRadius The radius of the blur in points, 0 means no blur effect. 287 | 288 | @param tintColor An optional UIColor object that is uniformly blended with 289 | the result of the blur and saturation operations. The 290 | alpha channel of this color determines how strong the 291 | tint is. nil means no tint. 292 | 293 | @param tintBlendMode The @a tintColor blend mode. Default is kCGBlendModeNormal (0). 294 | 295 | @param saturation A value of 1.0 produces no change in the resulting image. 296 | Values less than 1.0 will desaturation the resulting image 297 | while values greater than 1.0 will have the opposite effect. 298 | 0 means gray scale. 299 | 300 | @param maskImage If specified, @a inputImage is only modified in the area(s) 301 | defined by this mask. This must be an image mask or it 302 | must meet the requirements of the mask parameter of 303 | CGContextClipToMask. 304 | 305 | @return image with effect, or nil if an error occurs (e.g. no 306 | enough memory). 307 | */ 308 | - (nullable UIImage *)yy_imageByBlurRadius:(CGFloat)blurRadius 309 | tintColor:(nullable UIColor *)tintColor 310 | tintMode:(CGBlendMode)tintBlendMode 311 | saturation:(CGFloat)saturation 312 | maskImage:(nullable UIImage *)maskImage; 313 | 314 | @end 315 | 316 | NS_ASSUME_NONNULL_END 317 | -------------------------------------------------------------------------------- /PlayCornerRadius/YYWebImage/YYWebImage/Categories/UIImageView+YYWebImage.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIImageView+YYWebImage.h 3 | // YYWebImage 4 | // 5 | // Created by ibireme on 15/2/23. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | 14 | #if __has_include() 15 | #import 16 | #else 17 | #import "YYWebImageManager.h" 18 | #endif 19 | 20 | NS_ASSUME_NONNULL_BEGIN 21 | 22 | /** 23 | Web image methods for UIImageView. 24 | */ 25 | @interface UIImageView (YYWebImage) 26 | 27 | #pragma mark - image 28 | 29 | /** 30 | Current image URL. 31 | 32 | @discussion Set a new value to this property will cancel the previous request 33 | operation and create a new request operation to fetch image. Set nil to clear 34 | the image and image URL. 35 | */ 36 | @property (nullable, nonatomic, strong) NSURL *yy_imageURL; 37 | 38 | /** 39 | Set the view's `image` with a specified URL. 40 | 41 | @param imageURL The image url (remote or local file path). 42 | @param placeholder The image to be set initially, until the image request finishes. 43 | */ 44 | - (void)yy_setImageWithURL:(nullable NSURL *)imageURL placeholder:(nullable UIImage *)placeholder; 45 | 46 | /** 47 | Set the view's `image` with a specified URL. 48 | 49 | @param imageURL The image url (remote or local file path). 50 | @param options The options to use when request the image. 51 | */ 52 | - (void)yy_setImageWithURL:(nullable NSURL *)imageURL options:(YYWebImageOptions)options; 53 | 54 | /** 55 | Set the view's `image` with a specified URL. 56 | 57 | @param imageURL The image url (remote or local file path). 58 | @param placeholder The image to be set initially, until the image request finishes. 59 | @param options The options to use when request the image. 60 | @param completion The block invoked (on main thread) when image request completed. 61 | */ 62 | - (void)yy_setImageWithURL:(nullable NSURL *)imageURL 63 | placeholder:(nullable UIImage *)placeholder 64 | options:(YYWebImageOptions)options 65 | completion:(nullable YYWebImageCompletionBlock)completion; 66 | 67 | /** 68 | Set the view's `image` with a specified URL. 69 | 70 | @param imageURL The image url (remote or local file path). 71 | @param placeholder The image to be set initially, until the image request finishes. 72 | @param options The options to use when request the image. 73 | @param progress The block invoked (on main thread) during image request. 74 | @param transform The block invoked (on background thread) to do additional image process. 75 | @param transformKey 转换key,链接相同但key不同会有不同的缓存 76 | @param completion The block invoked (on main thread) when image request completed. 77 | */ 78 | - (void)yy_setImageWithURL:(nullable NSURL *)imageURL 79 | placeholder:(nullable UIImage *)placeholder 80 | options:(YYWebImageOptions)options 81 | progress:(nullable YYWebImageProgressBlock)progress 82 | transform:(nullable YYWebImageTransformBlock)transform 83 | transformKey:(nullable NSString *)transformKey 84 | completion:(nullable YYWebImageCompletionBlock)completion; 85 | 86 | /** 87 | Set the view's `image` with a specified URL. 88 | 89 | @param imageURL The image url (remote or local file path). 90 | @param placeholder he image to be set initially, until the image request finishes. 91 | @param options The options to use when request the image. 92 | @param manager The manager to create image request operation. 93 | @param progress The block invoked (on main thread) during image request. 94 | @param transform The block invoked (on background thread) to do additional image process. 95 | @param transformKey 转换key,链接相同但key不同会有不同的缓存 96 | @param completion The block invoked (on main thread) when image request completed. 97 | */ 98 | - (void)yy_setImageWithURL:(nullable NSURL *)imageURL 99 | placeholder:(nullable UIImage *)placeholder 100 | options:(YYWebImageOptions)options 101 | manager:(nullable YYWebImageManager *)manager 102 | progress:(nullable YYWebImageProgressBlock)progress 103 | transform:(nullable YYWebImageTransformBlock)transform 104 | transformKey:(nullable NSString *)transformKey 105 | completion:(nullable YYWebImageCompletionBlock)completion; 106 | 107 | /** 108 | Cancel the current image request. 109 | */ 110 | - (void)yy_cancelCurrentImageRequest; 111 | 112 | 113 | 114 | #pragma mark - highlight image 115 | 116 | /** 117 | Current highlighted image URL. 118 | 119 | @discussion Set a new value to this property will cancel the previous request 120 | operation and create a new request operation to fetch image. Set nil to clear 121 | the highlighted image and image URL. 122 | */ 123 | @property (nullable, nonatomic, strong) NSURL *yy_highlightedImageURL; 124 | 125 | /** 126 | Set the view's `highlightedImage` with a specified URL. 127 | 128 | @param imageURL The image url (remote or local file path). 129 | @param placeholder The image to be set initially, until the image request finishes. 130 | */ 131 | - (void)yy_setHighlightedImageWithURL:(nullable NSURL *)imageURL placeholder:(nullable UIImage *)placeholder; 132 | 133 | /** 134 | Set the view's `highlightedImage` with a specified URL. 135 | 136 | @param imageURL The image url (remote or local file path). 137 | @param options The options to use when request the image. 138 | */ 139 | - (void)yy_setHighlightedImageWithURL:(nullable NSURL *)imageURL options:(YYWebImageOptions)options; 140 | 141 | /** 142 | Set the view's `highlightedImage` with a specified URL. 143 | 144 | @param imageURL The image url (remote or local file path). 145 | @param placeholder The image to be set initially, until the image request finishes. 146 | @param options The options to use when request the image. 147 | @param completion The block invoked (on main thread) when image request completed. 148 | */ 149 | - (void)yy_setHighlightedImageWithURL:(nullable NSURL *)imageURL 150 | placeholder:(nullable UIImage *)placeholder 151 | options:(YYWebImageOptions)options 152 | completion:(nullable YYWebImageCompletionBlock)completion; 153 | 154 | /** 155 | Set the view's `highlightedImage` with a specified URL. 156 | 157 | @param imageURL The image url (remote or local file path). 158 | @param placeholder The image to be set initially, until the image request finishes. 159 | @param options The options to use when request the image. 160 | @param progress The block invoked (on main thread) during image request. 161 | @param transform The block invoked (on background thread) to do additional image process. 162 | @param transformKey 转换key,链接相同但key不同会有不同的缓存 163 | @param completion The block invoked (on main thread) when image request completed. 164 | */ 165 | - (void)yy_setHighlightedImageWithURL:(nullable NSURL *)imageURL 166 | placeholder:(nullable UIImage *)placeholder 167 | options:(YYWebImageOptions)options 168 | progress:(nullable YYWebImageProgressBlock)progress 169 | transform:(nullable YYWebImageTransformBlock)transform 170 | transformKey:(nullable NSString *)transformKey 171 | completion:(nullable YYWebImageCompletionBlock)completion; 172 | 173 | /** 174 | Set the view's `highlightedImage` with a specified URL. 175 | 176 | @param imageURL The image url (remote or local file path). 177 | @param placeholder The image to be set initially, until the image request finishes. 178 | @param options The options to use when request the image. 179 | @param manager The manager to create image request operation. 180 | @param progress The block invoked (on main thread) during image request. 181 | @param transform The block invoked (on background thread) to do additional image process. 182 | @param transformKey 转换key,链接相同但key不同会有不同的缓存 183 | @param completion The block invoked (on main thread) when image request completed. 184 | */ 185 | - (void)yy_setHighlightedImageWithURL:(nullable NSURL *)imageURL 186 | placeholder:(nullable UIImage *)placeholder 187 | options:(YYWebImageOptions)options 188 | manager:(nullable YYWebImageManager *)manager 189 | progress:(nullable YYWebImageProgressBlock)progress 190 | transform:(nullable YYWebImageTransformBlock)transform 191 | transformKey:(nullable NSString *)transformKey 192 | completion:(nullable YYWebImageCompletionBlock)completion; 193 | 194 | /** 195 | Cancel the current highlighed image request. 196 | */ 197 | - (void)yy_cancelCurrentHighlightedImageRequest; 198 | 199 | @end 200 | 201 | NS_ASSUME_NONNULL_END 202 | -------------------------------------------------------------------------------- /PlayCornerRadius/YYWebImage/YYWebImage/Categories/_YYWebImageSetter.h: -------------------------------------------------------------------------------- 1 | // 2 | // _YYWebImageSetter.h 3 | // YYWebImage 4 | // 5 | // Created by ibireme on 15/7/15. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | #import 12 | #import 13 | 14 | #if __has_include() 15 | #import 16 | #else 17 | #import "YYWebImageManager.h" 18 | #endif 19 | 20 | NS_ASSUME_NONNULL_BEGIN 21 | 22 | /** 23 | Submits a block for execution on a main queue and waits until the block completes. 24 | */ 25 | static inline void _yy_dispatch_sync_on_main_queue(void (^block)()) { 26 | if (pthread_main_np()) { 27 | block(); 28 | } else { 29 | dispatch_sync(dispatch_get_main_queue(), block); 30 | } 31 | } 32 | 33 | extern NSString *const _YYWebImageFadeAnimationKey; 34 | extern const NSTimeInterval _YYWebImageFadeTime; 35 | extern const NSTimeInterval _YYWebImageProgressiveFadeTime; 36 | 37 | /** 38 | Private class used by web image categories. 39 | Typically, you should not use this class directly. 40 | */ 41 | @interface _YYWebImageSetter : NSObject 42 | /// Current image url. 43 | @property (nullable, nonatomic, readonly) NSURL *imageURL; 44 | /// Current sentinel. 45 | @property (nonatomic, readonly) int32_t sentinel; 46 | 47 | /// Create new operation for web image and return a sentinel value. 48 | - (int32_t)setOperationWithSentinel:(int32_t)sentinel 49 | url:(nullable NSURL *)imageURL 50 | options:(YYWebImageOptions)options 51 | manager:(YYWebImageManager *)manager 52 | progress:(nullable YYWebImageProgressBlock)progress 53 | transform:(nullable YYWebImageTransformBlock)transform 54 | transformKey:(nullable NSString *)transformKey 55 | completion:(nullable YYWebImageCompletionBlock)completion; 56 | 57 | /// Cancel and return a sentinel value. The imageURL will be set to nil. 58 | - (int32_t)cancel; 59 | 60 | /// Cancel and return a sentinel value. The imageURL will be set to new value. 61 | - (int32_t)cancelWithNewURL:(nullable NSURL *)imageURL; 62 | 63 | /// A queue to set operation. 64 | + (dispatch_queue_t)setterQueue; 65 | 66 | @end 67 | 68 | NS_ASSUME_NONNULL_END 69 | -------------------------------------------------------------------------------- /PlayCornerRadius/YYWebImage/YYWebImage/Categories/_YYWebImageSetter.m: -------------------------------------------------------------------------------- 1 | // 2 | // _YYWebImageSetter.m 3 | // YYWebImage 4 | // 5 | // Created by ibireme on 15/7/15. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import "_YYWebImageSetter.h" 13 | #import "YYWebImageOperation.h" 14 | #import 15 | 16 | NSString *const _YYWebImageFadeAnimationKey = @"YYWebImageFade"; 17 | const NSTimeInterval _YYWebImageFadeTime = 0.2; 18 | const NSTimeInterval _YYWebImageProgressiveFadeTime = 0.4; 19 | 20 | 21 | @implementation _YYWebImageSetter { 22 | dispatch_semaphore_t _lock; 23 | NSURL *_imageURL; 24 | NSOperation *_operation; 25 | int32_t _sentinel; 26 | } 27 | 28 | - (instancetype)init { 29 | self = [super init]; 30 | _lock = dispatch_semaphore_create(1); 31 | return self; 32 | } 33 | 34 | - (NSURL *)imageURL { 35 | dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER); 36 | NSURL *imageURL = _imageURL; 37 | dispatch_semaphore_signal(_lock); 38 | return imageURL; 39 | } 40 | 41 | - (void)dealloc { 42 | OSAtomicIncrement32(&_sentinel); 43 | [_operation cancel]; 44 | } 45 | 46 | - (int32_t)setOperationWithSentinel:(int32_t)sentinel 47 | url:(NSURL *)imageURL 48 | options:(YYWebImageOptions)options 49 | manager:(YYWebImageManager *)manager 50 | progress:(YYWebImageProgressBlock)progress 51 | transform:(YYWebImageTransformBlock)transform 52 | transformKey:(nullable NSString *)transformKey 53 | completion:(YYWebImageCompletionBlock)completion { 54 | if (sentinel != _sentinel) { 55 | if (completion) completion(nil, imageURL, YYWebImageFromNone, YYWebImageStageCancelled, nil); 56 | return _sentinel; 57 | } 58 | 59 | NSOperation *operation = [manager requestImageWithURL:imageURL options:options progress:progress transform:transform transformKey:transformKey completion:completion]; 60 | if (!operation && completion) { 61 | NSDictionary *userInfo = @{ NSLocalizedDescriptionKey : @"YYWebImageOperation create failed." }; 62 | completion(nil, imageURL, YYWebImageFromNone, YYWebImageStageFinished, [NSError errorWithDomain:@"com.ibireme.webimage" code:-1 userInfo:userInfo]); 63 | } 64 | 65 | dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER); 66 | if (sentinel == _sentinel) { 67 | if (_operation) [_operation cancel]; 68 | _operation = operation; 69 | sentinel = OSAtomicIncrement32(&_sentinel); 70 | } else { 71 | [operation cancel]; 72 | } 73 | dispatch_semaphore_signal(_lock); 74 | return sentinel; 75 | } 76 | 77 | - (int32_t)cancel { 78 | return [self cancelWithNewURL:nil]; 79 | } 80 | 81 | - (int32_t)cancelWithNewURL:(NSURL *)imageURL { 82 | int32_t sentinel; 83 | dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER); 84 | if (_operation) { 85 | [_operation cancel]; 86 | _operation = nil; 87 | } 88 | _imageURL = imageURL; 89 | sentinel = OSAtomicIncrement32(&_sentinel); 90 | dispatch_semaphore_signal(_lock); 91 | return sentinel; 92 | } 93 | 94 | + (dispatch_queue_t)setterQueue { 95 | static dispatch_queue_t queue; 96 | static dispatch_once_t onceToken; 97 | dispatch_once(&onceToken, ^{ 98 | queue = dispatch_queue_create("com.ibireme.webimage.setter", DISPATCH_QUEUE_SERIAL); 99 | dispatch_set_target_queue(queue, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)); 100 | }); 101 | return queue; 102 | } 103 | 104 | @end 105 | -------------------------------------------------------------------------------- /PlayCornerRadius/YYWebImage/YYWebImage/YYImageCache.h: -------------------------------------------------------------------------------- 1 | // 2 | // YYImageCache.h 3 | // YYWebImage 4 | // 5 | // Created by ibireme on 15/2/15. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | 14 | @class YYMemoryCache, YYDiskCache; 15 | 16 | NS_ASSUME_NONNULL_BEGIN 17 | 18 | /// Image cache type 19 | typedef NS_OPTIONS(NSUInteger, YYImageCacheType) { 20 | /// No value. 21 | YYImageCacheTypeNone = 0, 22 | 23 | /// Get/store image with memory cache. 24 | YYImageCacheTypeMemory = 1 << 0, 25 | 26 | /// Get/store image with disk cache. 27 | YYImageCacheTypeDisk = 1 << 1, 28 | 29 | /// Get/store image with both memory cache and disk cache. 30 | YYImageCacheTypeAll = YYImageCacheTypeMemory | YYImageCacheTypeDisk, 31 | }; 32 | 33 | 34 | /** 35 | YYImageCache is a cache that stores UIImage and image data based on memory cache and disk cache. 36 | 37 | @discussion The disk cache will try to protect the original image data: 38 | 39 | * If the original image is still image, it will be saved as png/jpeg file based on alpha information. 40 | * If the original image is animated gif, apng or webp, it will be saved as original format. 41 | * If the original image's scale is not 1, the scale value will be saved as extended data. 42 | 43 | Although UIImage can be serialized with NSCoding protocol, but it's not a good idea: 44 | Apple actually use UIImagePNGRepresentation() to encode all kind of image, it may 45 | lose the original multi-frame data. The result is packed to plist file and cannot 46 | view with photo viewer directly. If the image has no alpha channel, using JPEG 47 | instead of PNG can save more disk size and encoding/decoding time. 48 | */ 49 | @interface YYImageCache : NSObject 50 | 51 | #pragma mark - Attribute 52 | ///============================================================================= 53 | /// @name Attribute 54 | ///============================================================================= 55 | 56 | /** The name of the cache. Default is nil. */ 57 | @property (nullable, copy) NSString *name; 58 | 59 | /** The underlying memory cache. see `YYMemoryCache` for more information.*/ 60 | @property (strong, readonly) YYMemoryCache *memoryCache; 61 | 62 | /** The underlying disk cache. see `YYDiskCache` for more information.*/ 63 | @property (strong, readonly) YYDiskCache *diskCache; 64 | 65 | /** 66 | Whether decode animated image when fetch image from disk cache. Default is YES. 67 | 68 | @discussion When fetch image from disk cache, it will use 'YYImage' to decode 69 | animated image such as WebP/APNG/GIF. Set to 'NO' to ignore animated image. 70 | */ 71 | @property BOOL allowAnimatedImage; 72 | 73 | /** 74 | Whether decode the image to memory bitmap. Default is YES. 75 | 76 | @discussion If the value is YES, then the image will be decoded to memory bitmap 77 | for better display performance, but may cost more memory. 78 | */ 79 | @property BOOL decodeForDisplay; 80 | 81 | 82 | #pragma mark - Initializer 83 | ///============================================================================= 84 | /// @name Initializer 85 | ///============================================================================= 86 | - (instancetype)init UNAVAILABLE_ATTRIBUTE; 87 | + (instancetype)new UNAVAILABLE_ATTRIBUTE; 88 | 89 | /** 90 | Returns global shared image cache instance. 91 | @return The singleton YYImageCache instance. 92 | */ 93 | + (instancetype)sharedCache; 94 | 95 | /** 96 | The designated initializer. Multiple instances with the same path will make the 97 | cache unstable. 98 | 99 | @param path Full path of a directory in which the cache will write data. 100 | Once initialized you should not read and write to this directory. 101 | @result A new cache object, or nil if an error occurs. 102 | */ 103 | - (nullable instancetype)initWithPath:(NSString *)path NS_DESIGNATED_INITIALIZER; 104 | 105 | 106 | #pragma mark - Access Methods 107 | ///============================================================================= 108 | /// @name Access Methods 109 | ///============================================================================= 110 | 111 | /** 112 | Sets the image with the specified key in the cache (both memory and disk). 113 | This method returns immediately and executes the store operation in background. 114 | 115 | @param image The image to be stored in the cache. If nil, this method has no effect. 116 | @param key The key with which to associate the image. If nil, this method has no effect. 117 | */ 118 | - (void)setImage:(UIImage *)image forKey:(NSString *)key; 119 | 120 | /** 121 | Sets the image with the specified key in the cache. 122 | This method returns immediately and executes the store operation in background. 123 | 124 | @discussion If the `type` contain `YYImageCacheTypeMemory`, then the `image` will 125 | be stored in the memory cache; `imageData` will be used instead if `image` is nil. 126 | If the `type` contain `YYImageCacheTypeDisk`, then the `imageData` will 127 | be stored in the disk cache; `image` will be used instead if `imageData` is nil. 128 | 129 | @param image The image to be stored in the cache. 130 | @param imageData The image data to be stored in the cache. 131 | @param key The key with which to associate the image. If nil, this method has no effect. 132 | @param type The cache type to store image. 133 | */ 134 | - (void)setImage:(nullable UIImage *)image 135 | imageData:(nullable NSData *)imageData 136 | forKey:(NSString *)key 137 | withType:(YYImageCacheType)type; 138 | 139 | /** 140 | Removes the image of the specified key in the cache (both memory and disk). 141 | This method returns immediately and executes the remove operation in background. 142 | 143 | @param key The key identifying the image to be removed. If nil, this method has no effect. 144 | */ 145 | - (void)removeImageForKey:(NSString *)key; 146 | 147 | /** 148 | Removes the image of the specified key in the cache. 149 | This method returns immediately and executes the remove operation in background. 150 | 151 | @param key The key identifying the image to be removed. If nil, this method has no effect. 152 | @param type The cache type to remove image. 153 | */ 154 | - (void)removeImageForKey:(NSString *)key withType:(YYImageCacheType)type; 155 | 156 | /** 157 | Returns a Boolean value that indicates whether a given key is in cache. 158 | If the image is not in memory, this method may blocks the calling thread until 159 | file read finished. 160 | 161 | @param key A string identifying the image. If nil, just return NO. 162 | @return Whether the image is in cache. 163 | */ 164 | - (BOOL)containsImageForKey:(NSString *)key; 165 | 166 | /** 167 | Returns a Boolean value that indicates whether a given key is in cache. 168 | If the image is not in memory and the `type` contains `YYImageCacheTypeDisk`, 169 | this method may blocks the calling thread until file read finished. 170 | 171 | @param key A string identifying the image. If nil, just return NO. 172 | @param type The cache type. 173 | @return Whether the image is in cache. 174 | */ 175 | - (BOOL)containsImageForKey:(NSString *)key withType:(YYImageCacheType)type; 176 | 177 | /** 178 | Returns the image associated with a given key. 179 | If the image is not in memory, this method may blocks the calling thread until 180 | file read finished. 181 | 182 | @param key A string identifying the image. If nil, just return nil. 183 | @return The image associated with key, or nil if no image is associated with key. 184 | */ 185 | - (nullable UIImage *)getImageForKey:(NSString *)key; 186 | 187 | /** 188 | Returns the image associated with a given key. 189 | If the image is not in memory and the `type` contains `YYImageCacheTypeDisk`, 190 | this method may blocks the calling thread until file read finished. 191 | 192 | @param key A string identifying the image. If nil, just return nil. 193 | @return The image associated with key, or nil if no image is associated with key. 194 | */ 195 | - (nullable UIImage *)getImageForKey:(NSString *)key withType:(YYImageCacheType)type; 196 | 197 | /** 198 | Asynchronously get the image associated with a given key. 199 | 200 | @param key A string identifying the image. If nil, just return nil. 201 | @param type The cache type. 202 | @param block A completion block which will be called on main thread. 203 | */ 204 | - (void)getImageForKey:(NSString *)key 205 | withType:(YYImageCacheType)type 206 | withBlock:(void(^)(UIImage * _Nullable image, YYImageCacheType type))block; 207 | 208 | /** 209 | Returns the image data associated with a given key. 210 | This method may blocks the calling thread until file read finished. 211 | 212 | @param key A string identifying the image. If nil, just return nil. 213 | @return The image data associated with key, or nil if no image is associated with key. 214 | */ 215 | - (nullable NSData *)getImageDataForKey:(NSString *)key; 216 | 217 | /** 218 | Asynchronously get the image data associated with a given key. 219 | 220 | @param key A string identifying the image. If nil, just return nil. 221 | @param block A completion block which will be called on main thread. 222 | */ 223 | - (void)getImageDataForKey:(NSString *)key 224 | withBlock:(void(^)(NSData * _Nullable imageData))block; 225 | 226 | @end 227 | 228 | NS_ASSUME_NONNULL_END 229 | -------------------------------------------------------------------------------- /PlayCornerRadius/YYWebImage/YYWebImage/YYImageCache.m: -------------------------------------------------------------------------------- 1 | // 2 | // YYImageCache.m 3 | // YYWebImage 4 | // 5 | // Created by ibireme on 15/2/15. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import "YYImageCache.h" 13 | #import "YYImage.h" 14 | #import "UIImage+YYWebImage.h" 15 | 16 | #if __has_include() 17 | #import 18 | #else 19 | #import "YYImage.h" 20 | #endif 21 | 22 | #if __has_include() 23 | #import 24 | #else 25 | #import "YYCache.h" 26 | #endif 27 | 28 | 29 | 30 | static inline dispatch_queue_t YYImageCacheIOQueue() { 31 | return dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 32 | } 33 | 34 | static inline dispatch_queue_t YYImageCacheDecodeQueue() { 35 | return dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0); 36 | } 37 | 38 | 39 | @interface YYImageCache () 40 | - (NSUInteger)imageCost:(UIImage *)image; 41 | - (UIImage *)imageFromData:(NSData *)data; 42 | @end 43 | 44 | 45 | @implementation YYImageCache 46 | 47 | - (NSUInteger)imageCost:(UIImage *)image { 48 | CGImageRef cgImage = image.CGImage; 49 | if (!cgImage) return 1; 50 | CGFloat height = CGImageGetHeight(cgImage); 51 | size_t bytesPerRow = CGImageGetBytesPerRow(cgImage); 52 | NSUInteger cost = bytesPerRow * height; 53 | if (cost == 0) cost = 1; 54 | return cost; 55 | } 56 | 57 | - (UIImage *)imageFromData:(NSData *)data { 58 | NSData *scaleData = [YYDiskCache getExtendedDataFromObject:data]; 59 | CGFloat scale = 0; 60 | if (scaleData) { 61 | scale = ((NSNumber *)[NSKeyedUnarchiver unarchiveObjectWithData:scaleData]).doubleValue; 62 | } 63 | if (scale <= 0) scale = [UIScreen mainScreen].scale; 64 | UIImage *image; 65 | if (_allowAnimatedImage) { 66 | image = [[YYImage alloc] initWithData:data scale:scale]; 67 | if (_decodeForDisplay) image = [image yy_imageByDecoded]; 68 | } else { 69 | YYImageDecoder *decoder = [YYImageDecoder decoderWithData:data scale:scale]; 70 | image = [decoder frameAtIndex:0 decodeForDisplay:_decodeForDisplay].image; 71 | } 72 | return image; 73 | } 74 | 75 | #pragma mark Public 76 | 77 | + (instancetype)sharedCache { 78 | static YYImageCache *cache = nil; 79 | static dispatch_once_t onceToken; 80 | dispatch_once(&onceToken, ^{ 81 | NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, 82 | NSUserDomainMask, YES) firstObject]; 83 | cachePath = [cachePath stringByAppendingPathComponent:@"com.ibireme.yykit"]; 84 | cachePath = [cachePath stringByAppendingPathComponent:@"images"]; 85 | cache = [[self alloc] initWithPath:cachePath]; 86 | }); 87 | return cache; 88 | } 89 | 90 | - (instancetype)init { 91 | @throw [NSException exceptionWithName:@"YYImageCache init error" reason:@"YYImageCache must be initialized with a path. Use 'initWithPath:' instead." userInfo:nil]; 92 | return [self initWithPath:@""]; 93 | } 94 | 95 | - (instancetype)initWithPath:(NSString *)path { 96 | YYMemoryCache *memoryCache = [YYMemoryCache new]; 97 | memoryCache.shouldRemoveAllObjectsOnMemoryWarning = YES; 98 | memoryCache.shouldRemoveAllObjectsWhenEnteringBackground = YES; 99 | memoryCache.countLimit = NSUIntegerMax; 100 | memoryCache.costLimit = NSUIntegerMax; 101 | memoryCache.ageLimit = 12 * 60 * 60; 102 | 103 | YYDiskCache *diskCache = [[YYDiskCache alloc] initWithPath:path]; 104 | diskCache.customArchiveBlock = ^(id object) { return (NSData *)object; }; 105 | diskCache.customUnarchiveBlock = ^(NSData *data) { return (id)data; }; 106 | if (!memoryCache || !diskCache) return nil; 107 | 108 | self = [super init]; 109 | _memoryCache = memoryCache; 110 | _diskCache = diskCache; 111 | _allowAnimatedImage = YES; 112 | _decodeForDisplay = YES; 113 | return self; 114 | } 115 | 116 | - (void)setImage:(UIImage *)image forKey:(NSString *)key { 117 | [self setImage:image imageData:nil forKey:key withType:YYImageCacheTypeAll]; 118 | } 119 | 120 | - (void)setImage:(UIImage *)image imageData:(NSData *)imageData forKey:(NSString *)key withType:(YYImageCacheType)type { 121 | if (!key || (image == nil && imageData.length == 0)) return; 122 | 123 | __weak typeof(self) _self = self; 124 | if (type & YYImageCacheTypeMemory) { // add to memory cache 125 | if (image) { 126 | if (image.yy_isDecodedForDisplay) { 127 | [_memoryCache setObject:image forKey:key withCost:[_self imageCost:image]]; 128 | } else { 129 | dispatch_async(YYImageCacheDecodeQueue(), ^{ 130 | __strong typeof(_self) self = _self; 131 | if (!self) return; 132 | [self.memoryCache setObject:[image yy_imageByDecoded] forKey:key withCost:[self imageCost:image]]; 133 | }); 134 | } 135 | } else if (imageData) { 136 | dispatch_async(YYImageCacheDecodeQueue(), ^{ 137 | __strong typeof(_self) self = _self; 138 | if (!self) return; 139 | UIImage *newImage = [self imageFromData:imageData]; 140 | [self.memoryCache setObject:newImage forKey:key withCost:[self imageCost:newImage]]; 141 | }); 142 | } 143 | } 144 | if (type & YYImageCacheTypeDisk) { // add to disk cache 145 | if (imageData) { 146 | if (image) { 147 | [YYDiskCache setExtendedData:[NSKeyedArchiver archivedDataWithRootObject:@(image.scale)] toObject:imageData]; 148 | } 149 | [_diskCache setObject:imageData forKey:key]; 150 | } else if (image) { 151 | dispatch_async(YYImageCacheIOQueue(), ^{ 152 | __strong typeof(_self) self = _self; 153 | if (!self) return; 154 | NSData *data = [image yy_imageDataRepresentation]; 155 | [YYDiskCache setExtendedData:[NSKeyedArchiver archivedDataWithRootObject:@(image.scale)] toObject:data]; 156 | [self.diskCache setObject:data forKey:key]; 157 | }); 158 | } 159 | } 160 | } 161 | 162 | - (void)removeImageForKey:(NSString *)key { 163 | [self removeImageForKey:key withType:YYImageCacheTypeAll]; 164 | } 165 | 166 | - (void)removeImageForKey:(NSString *)key withType:(YYImageCacheType)type { 167 | if (type & YYImageCacheTypeMemory) [_memoryCache removeObjectForKey:key]; 168 | if (type & YYImageCacheTypeDisk) [_diskCache removeObjectForKey:key]; 169 | } 170 | 171 | - (BOOL)containsImageForKey:(NSString *)key { 172 | return [self containsImageForKey:key withType:YYImageCacheTypeAll]; 173 | } 174 | 175 | - (BOOL)containsImageForKey:(NSString *)key withType:(YYImageCacheType)type { 176 | if (type & YYImageCacheTypeMemory) { 177 | if ([_memoryCache containsObjectForKey:key]) return YES; 178 | } 179 | if (type & YYImageCacheTypeDisk) { 180 | if ([_diskCache containsObjectForKey:key]) return YES; 181 | } 182 | return NO; 183 | } 184 | 185 | - (UIImage *)getImageForKey:(NSString *)key { 186 | return [self getImageForKey:key withType:YYImageCacheTypeAll]; 187 | } 188 | 189 | - (UIImage *)getImageForKey:(NSString *)key withType:(YYImageCacheType)type { 190 | if (!key) return nil; 191 | if (type & YYImageCacheTypeMemory) { 192 | UIImage *image = [_memoryCache objectForKey:key]; 193 | if (image) return image; 194 | } 195 | if (type & YYImageCacheTypeDisk) { 196 | NSData *data = (id)[_diskCache objectForKey:key]; 197 | UIImage *image = [self imageFromData:data]; 198 | if (image && (type & YYImageCacheTypeMemory)) { 199 | [_memoryCache setObject:image forKey:key withCost:[self imageCost:image]]; 200 | } 201 | return image; 202 | } 203 | return nil; 204 | } 205 | 206 | - (void)getImageForKey:(NSString *)key withType:(YYImageCacheType)type withBlock:(void (^)(UIImage *image, YYImageCacheType type))block { 207 | if (!block) return; 208 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 209 | UIImage *image = nil; 210 | 211 | if (type & YYImageCacheTypeMemory) { 212 | image = [_memoryCache objectForKey:key]; 213 | if (image) { 214 | dispatch_async(dispatch_get_main_queue(), ^{ 215 | block(image, YYImageCacheTypeMemory); 216 | }); 217 | return; 218 | } 219 | } 220 | 221 | if (type & YYImageCacheTypeDisk) { 222 | NSData *data = (id)[_diskCache objectForKey:key]; 223 | image = [self imageFromData:data]; 224 | if (image) { 225 | [_memoryCache setObject:image forKey:key]; 226 | dispatch_async(dispatch_get_main_queue(), ^{ 227 | block(image, YYImageCacheTypeDisk); 228 | }); 229 | return; 230 | } 231 | } 232 | 233 | dispatch_async(dispatch_get_main_queue(), ^{ 234 | block(nil, YYImageCacheTypeNone); 235 | }); 236 | }); 237 | } 238 | 239 | - (NSData *)getImageDataForKey:(NSString *)key { 240 | return (id)[_diskCache objectForKey:key]; 241 | } 242 | 243 | - (void)getImageDataForKey:(NSString *)key withBlock:(void (^)(NSData *imageData))block { 244 | if (!block) return; 245 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 246 | NSData *data = (id)[_diskCache objectForKey:key]; 247 | dispatch_async(dispatch_get_main_queue(), ^{ 248 | block(data); 249 | }); 250 | }); 251 | } 252 | 253 | @end 254 | -------------------------------------------------------------------------------- /PlayCornerRadius/YYWebImage/YYWebImage/YYWebImage.h: -------------------------------------------------------------------------------- 1 | // 2 | // YYWebImage.h 3 | // YYWebImage 4 | // 5 | // Created by ibireme on 15/2/23. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | 14 | #if __has_include() 15 | FOUNDATION_EXPORT double YYWebImageVersionNumber; 16 | FOUNDATION_EXPORT const unsigned char YYWebImageVersionString[]; 17 | #import 18 | #import 19 | #import 20 | #import 21 | #import 22 | #import 23 | #import 24 | #import 25 | #else 26 | #import "YYImageCache.h" 27 | #import "YYWebImageOperation.h" 28 | #import "YYWebImageManager.h" 29 | #import "UIImage+YYWebImage.h" 30 | #import "UIImageView+YYWebImage.h" 31 | #import "UIButton+YYWebImage.h" 32 | #import "CALayer+YYWebImage.h" 33 | #import "MKAnnotationView+YYWebImage.h" 34 | #endif 35 | 36 | #if __has_include() 37 | #import 38 | #elif __has_include() 39 | #import 40 | #import 41 | #import 42 | #import 43 | #import 44 | #else 45 | #import "YYImage.h" 46 | #import "YYFrameImage.h" 47 | #import "YYSpriteSheetImage.h" 48 | #import "YYImageCoder.h" 49 | #import "YYAnimatedImageView.h" 50 | #endif 51 | 52 | #if __has_include() 53 | #import 54 | #elif __has_include() 55 | #import 56 | #import 57 | #import 58 | #import 59 | #else 60 | #import "YYCache.h" 61 | #import "YYMemoryCache.h" 62 | #import "YYDiskCache.h" 63 | #import "YYKVStorage.h" 64 | #endif 65 | 66 | -------------------------------------------------------------------------------- /PlayCornerRadius/YYWebImage/YYWebImage/YYWebImageManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // YYWebImageManager.h 3 | // YYWebImage 4 | // 5 | // Created by ibireme on 15/2/19. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | 14 | #if __has_include() 15 | #import 16 | #else 17 | #import "YYImageCache.h" 18 | #endif 19 | 20 | @class YYWebImageOperation; 21 | 22 | NS_ASSUME_NONNULL_BEGIN 23 | 24 | /// The options to control image operation. 25 | typedef NS_OPTIONS(NSUInteger, YYWebImageOptions) { 26 | 27 | /// Show network activity on status bar when download image. 28 | YYWebImageOptionShowNetworkActivity = 1 << 0, 29 | 30 | /// Display progressive/interlaced/baseline image during download (same as web browser). 31 | YYWebImageOptionProgressive = 1 << 1, 32 | 33 | /// Display blurred progressive JPEG or interlaced PNG image during download. 34 | /// This will ignore baseline image for better user experience. 35 | YYWebImageOptionProgressiveBlur = 1 << 2, 36 | 37 | /// Use NSURLCache instead of YYImageCache. 38 | YYWebImageOptionUseNSURLCache = 1 << 3, 39 | 40 | /// Allows untrusted SSL ceriticates. 41 | YYWebImageOptionAllowInvalidSSLCertificates = 1 << 4, 42 | 43 | /// Allows background task to download image when app is in background. 44 | YYWebImageOptionAllowBackgroundTask = 1 << 5, 45 | 46 | /// Handles cookies stored in NSHTTPCookieStore. 47 | YYWebImageOptionHandleCookies = 1 << 6, 48 | 49 | /// Load the image from remote and refresh the image cache. 50 | YYWebImageOptionRefreshImageCache = 1 << 7, 51 | 52 | /// Do not load image from/to disk cache. 53 | YYWebImageOptionIgnoreDiskCache = 1 << 8, 54 | 55 | /// Do not change the view's image before set a new URL to it. 56 | YYWebImageOptionIgnorePlaceHolder = 1 << 9, 57 | 58 | /// Ignore image decoding. 59 | /// This may used for image downloading without display. 60 | YYWebImageOptionIgnoreImageDecoding = 1 << 10, 61 | 62 | /// Ignore multi-frame image decoding. 63 | /// This will handle the GIF/APNG/WebP/ICO image as single frame image. 64 | YYWebImageOptionIgnoreAnimatedImage = 1 << 11, 65 | 66 | /// Set the image to view with a fade animation. 67 | /// This will add a "fade" animation on image view's layer for better user experience. 68 | YYWebImageOptionSetImageWithFadeAnimation = 1 << 12, 69 | 70 | /// Do not set the image to the view when image fetch complete. 71 | /// You may set the image manually. 72 | YYWebImageOptionAvoidSetImage = 1 << 13, 73 | 74 | /// This flag will add the URL to a blacklist (in memory) when the URL fail to be downloaded, 75 | /// so the library won't keep trying. 76 | YYWebImageOptionIgnoreFailedURL = 1 << 14, 77 | }; 78 | 79 | /// Indicated where the image came from. 80 | typedef NS_ENUM(NSUInteger, YYWebImageFromType) { 81 | 82 | /// No value. 83 | YYWebImageFromNone = 0, 84 | 85 | /// Fetched from memory cache immediately. 86 | /// If you called "setImageWithURL:..." and the image is already in memory, 87 | /// then you will get this value at the same call. 88 | YYWebImageFromMemoryCacheFast, 89 | 90 | /// Fetched from memory cache. 91 | YYWebImageFromMemoryCache, 92 | 93 | /// Fetched from disk cache. 94 | YYWebImageFromDiskCache, 95 | 96 | /// Fetched from remote (web or file path). 97 | YYWebImageFromRemote, 98 | }; 99 | 100 | /// Indicated image fetch complete stage. 101 | typedef NS_ENUM(NSInteger, YYWebImageStage) { 102 | 103 | /// Incomplete, progressive image. 104 | YYWebImageStageProgress = -1, 105 | 106 | /// Cancelled. 107 | YYWebImageStageCancelled = 0, 108 | 109 | /// Finished (succeed or failed). 110 | YYWebImageStageFinished = 1, 111 | }; 112 | 113 | 114 | /** 115 | The block invoked in remote image fetch progress. 116 | 117 | @param receivedSize Current received size in bytes. 118 | @param expectedSize Expected total size in bytes (-1 means unknown). 119 | */ 120 | typedef void(^YYWebImageProgressBlock)(NSInteger receivedSize, NSInteger expectedSize); 121 | 122 | /** 123 | The block invoked before remote image fetch finished to do additional image process. 124 | 125 | @discussion This block will be invoked before `YYWebImageCompletionBlock` to give 126 | you a chance to do additional image process (such as resize or crop). If there's 127 | no need to transform the image, just return the `image` parameter. 128 | 129 | @example You can clip the image, blur it and add rounded corners with these code: 130 | ^(UIImage *image, NSURL *url) { 131 | // Maybe you need to create an @autoreleasepool to limit memory cost. 132 | image = [image yy_imageByResizeToSize:CGSizeMake(100, 100) contentMode:UIViewContentModeScaleAspectFill]; 133 | image = [image yy_imageByBlurRadius:20 tintColor:nil tintMode:kCGBlendModeNormal saturation:1.2 maskImage:nil]; 134 | image = [image yy_imageByRoundCornerRadius:5]; 135 | return image; 136 | } 137 | 138 | @param image The image fetched from url. 139 | @param url The image url (remote or local file path). 140 | @return The transformed image. 141 | */ 142 | typedef UIImage * _Nullable (^YYWebImageTransformBlock)(UIImage *image, NSURL *url); 143 | 144 | /** 145 | The block invoked when image fetch finished or cancelled. 146 | 147 | @param image The image. 148 | @param url The image url (remote or local file path). 149 | @param from Where the image came from. 150 | @param error Error during image fetching. 151 | @param stage If the operation is cancelled, this value is NO, otherwise YES. 152 | */ 153 | typedef void (^YYWebImageCompletionBlock)(UIImage * _Nullable image, 154 | NSURL *url, 155 | YYWebImageFromType from, 156 | YYWebImageStage stage, 157 | NSError * _Nullable error); 158 | 159 | 160 | 161 | 162 | /** 163 | A manager to create and manage web image operation. 164 | */ 165 | @interface YYWebImageManager : NSObject 166 | 167 | /** 168 | Returns global YYWebImageManager instance. 169 | 170 | @return YYWebImageManager shared instance. 171 | */ 172 | + (instancetype)sharedManager; 173 | 174 | /** 175 | Creates a manager with an image cache and operation queue. 176 | 177 | @param cache Image cache used by manager (pass nil to avoid image cache). 178 | @param queue The operation queue on which image operations are scheduled and run 179 | (pass nil to make the new operation start immediately without queue). 180 | @return A new manager. 181 | */ 182 | - (instancetype)initWithCache:(nullable YYImageCache *)cache 183 | queue:(nullable NSOperationQueue *)queue NS_DESIGNATED_INITIALIZER; 184 | 185 | - (instancetype)init UNAVAILABLE_ATTRIBUTE; 186 | + (instancetype)new UNAVAILABLE_ATTRIBUTE; 187 | 188 | /** 189 | Creates and returns a new image operation, the operation will start immediately. 190 | 191 | @param url The image url (remote or local file path). 192 | @param options The options to control image operation. 193 | @param progress Progress block which will be invoked on background thread (pass nil to avoid). 194 | @param transform Transform block which will be invoked on background thread (pass nil to avoid). 195 | @param transformKey 转换key,链接相同但key不同会有不同的缓存 196 | @param completion Completion block which will be invoked on background thread (pass nil to avoid). 197 | @return A new image operation. 198 | */ 199 | - (nullable YYWebImageOperation *)requestImageWithURL:(NSURL *)url 200 | options:(YYWebImageOptions)options 201 | progress:(nullable YYWebImageProgressBlock)progress 202 | transform:(nullable YYWebImageTransformBlock)transform 203 | transformKey:(nullable NSString *)transformKey 204 | completion:(nullable YYWebImageCompletionBlock)completion; 205 | 206 | /** 207 | The image cache used by image operation. 208 | You can set it to nil to avoid image cache. 209 | */ 210 | @property (nullable, nonatomic, strong) YYImageCache *cache; 211 | 212 | /** 213 | The operation queue on which image operations are scheduled and run. 214 | You can set it to nil to make the new operation start immediately without queue. 215 | 216 | You can use this queue to control maximum number of concurrent operations, to obtain 217 | the status of the current operations, or to cancel all operations in this manager. 218 | */ 219 | @property (nullable, nonatomic, strong) NSOperationQueue *queue; 220 | 221 | /** 222 | The shared transform block to process image. Default is nil. 223 | 224 | When called `requestImageWithURL:options:progress:transform:completion` and 225 | the `transform` is nil, this block will be used. 226 | */ 227 | @property (nullable, nonatomic, copy) YYWebImageTransformBlock sharedTransformBlock; 228 | 229 | /** 230 | The image request timeout interval in seconds. Default is 15. 231 | */ 232 | @property (nonatomic) NSTimeInterval timeout; 233 | 234 | /** 235 | The username used by NSURLCredential, default is nil. 236 | */ 237 | @property (nullable, nonatomic, copy) NSString *username; 238 | 239 | /** 240 | The password used by NSURLCredential, default is nil. 241 | */ 242 | @property (nullable, nonatomic, copy) NSString *password; 243 | 244 | /** 245 | The image HTTP request header. Default is "Accept:image/webp,image/\*;q=0.8". 246 | */ 247 | @property (nullable, nonatomic, copy) NSDictionary *headers; 248 | 249 | /** 250 | A block which will be invoked for each image HTTP request to do additional 251 | HTTP header process. Default is nil. 252 | 253 | Use this block to add or remove HTTP header field for a specified URL. 254 | */ 255 | @property (nullable, nonatomic, copy) NSDictionary *(^headersFilter)(NSURL *url, NSDictionary * _Nullable header); 256 | 257 | /** 258 | A block which will be invoked for each image operation. Default is nil. 259 | 260 | Use this block to provide a custom image cache key for a specified URL. 261 | */ 262 | @property (nullable, nonatomic, copy) NSString *(^cacheKeyFilter)(NSURL *url); 263 | 264 | /** 265 | Returns the HTTP headers for a specified URL. 266 | 267 | @param url A specified URL. 268 | @return HTTP headers. 269 | */ 270 | - (nullable NSDictionary *)headersForURL:(NSURL *)url; 271 | 272 | /** 273 | Returns the cache key for a specified URL. 274 | 275 | @param url A specified URL 276 | @return Cache key used in YYImageCache. 277 | */ 278 | - (NSString *)cacheKeyForURL:(NSURL *)url transformKey:(nullable NSString *)transformKey; 279 | 280 | 281 | /** 282 | Increments the number of active network requests. 283 | If this number was zero before incrementing, this will start animating the 284 | status bar network activity indicator. 285 | 286 | This method is thread safe. 287 | 288 | This method has no effect in App Extension. 289 | */ 290 | + (void)incrementNetworkActivityCount; 291 | 292 | /** 293 | Decrements the number of active network requests. 294 | If this number becomes zero after decrementing, this will stop animating the 295 | status bar network activity indicator. 296 | 297 | This method is thread safe. 298 | 299 | This method has no effect in App Extension. 300 | */ 301 | + (void)decrementNetworkActivityCount; 302 | 303 | /** 304 | Get current number of active network requests. 305 | 306 | This method is thread safe. 307 | 308 | This method has no effect in App Extension. 309 | */ 310 | + (NSInteger)currentNetworkActivityCount; 311 | 312 | @end 313 | 314 | NS_ASSUME_NONNULL_END 315 | -------------------------------------------------------------------------------- /PlayCornerRadius/YYWebImage/YYWebImage/YYWebImageManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // YYWebImageManager.m 3 | // YYWebImage 4 | // 5 | // Created by ibireme on 15/2/19. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import "YYWebImageManager.h" 13 | #import "YYImageCache.h" 14 | #import "YYWebImageOperation.h" 15 | #import "YYImageCoder.h" 16 | #import 17 | 18 | #define kNetworkIndicatorDelay (1/30.0) 19 | 20 | 21 | /// Returns nil in App Extension. 22 | static UIApplication *_YYSharedApplication() { 23 | static BOOL isAppExtension = NO; 24 | static dispatch_once_t onceToken; 25 | dispatch_once(&onceToken, ^{ 26 | Class cls = NSClassFromString(@"UIApplication"); 27 | if(!cls || ![cls respondsToSelector:@selector(sharedApplication)]) isAppExtension = YES; 28 | if ([[[NSBundle mainBundle] bundlePath] hasSuffix:@".appex"]) isAppExtension = YES; 29 | }); 30 | #pragma clang diagnostic push 31 | #pragma clang diagnostic ignored "-Wundeclared-selector" 32 | return isAppExtension ? nil : [UIApplication performSelector:@selector(sharedApplication)]; 33 | #pragma clang diagnostic pop 34 | } 35 | 36 | 37 | @interface _YYWebImageApplicationNetworkIndicatorInfo : NSObject 38 | @property (nonatomic, assign) NSInteger count; 39 | @property (nonatomic, strong) NSTimer *timer; 40 | @end 41 | @implementation _YYWebImageApplicationNetworkIndicatorInfo 42 | @end 43 | 44 | @implementation YYWebImageManager 45 | 46 | + (instancetype)sharedManager { 47 | static YYWebImageManager *manager; 48 | static dispatch_once_t onceToken; 49 | dispatch_once(&onceToken, ^{ 50 | YYImageCache *cache = [YYImageCache sharedCache]; 51 | NSOperationQueue *queue = [NSOperationQueue new]; 52 | if ([queue respondsToSelector:@selector(setQualityOfService:)]) { 53 | queue.qualityOfService = NSQualityOfServiceBackground; 54 | } 55 | manager = [[self alloc] initWithCache:cache queue:queue]; 56 | }); 57 | return manager; 58 | } 59 | 60 | - (instancetype)init { 61 | @throw [NSException exceptionWithName:@"YYWebImageManager init error" reason:@"Use the designated initializer to init." userInfo:nil]; 62 | return [self initWithCache:nil queue:nil]; 63 | } 64 | 65 | - (instancetype)initWithCache:(YYImageCache *)cache queue:(NSOperationQueue *)queue{ 66 | self = [super init]; 67 | if (!self) return nil; 68 | _cache = cache; 69 | _queue = queue; 70 | _timeout = 15.0; 71 | if (YYImageWebPAvailable()) { 72 | _headers = @{ @"Accept" : @"image/webp,image/*;q=0.8" }; 73 | } else { 74 | _headers = @{ @"Accept" : @"image/*;q=0.8" }; 75 | } 76 | return self; 77 | } 78 | 79 | - (YYWebImageOperation *)requestImageWithURL:(NSURL *)url 80 | options:(YYWebImageOptions)options 81 | progress:(YYWebImageProgressBlock)progress 82 | transform:(YYWebImageTransformBlock)transform 83 | transformKey:(nullable NSString *)transformKey 84 | completion:(YYWebImageCompletionBlock)completion { 85 | 86 | NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; 87 | request.timeoutInterval = _timeout; 88 | request.HTTPShouldHandleCookies = (options & YYWebImageOptionHandleCookies) != 0; 89 | request.allHTTPHeaderFields = [self headersForURL:url]; 90 | request.HTTPShouldUsePipelining = YES; 91 | request.cachePolicy = (options & YYWebImageOptionUseNSURLCache) ? 92 | NSURLRequestUseProtocolCachePolicy : NSURLRequestReloadIgnoringLocalCacheData; 93 | 94 | YYWebImageOperation *operation = [[YYWebImageOperation alloc]initWithRequest:request 95 | options:options 96 | cache:_cache 97 | cacheKey:[self cacheKeyForURL:url transformKey:transformKey] 98 | progress:progress 99 | transform:transform ? transform : _sharedTransformBlock 100 | transformKey:transformKey 101 | completion:completion]; 102 | 103 | if (_username && _password) { 104 | operation.credential = [NSURLCredential credentialWithUser:_username password:_password persistence:NSURLCredentialPersistenceForSession]; 105 | } 106 | if (operation) { 107 | NSOperationQueue *queue = _queue; 108 | if (queue) { 109 | [queue addOperation:operation]; 110 | } else { 111 | [operation start]; 112 | } 113 | } 114 | return operation; 115 | } 116 | 117 | - (NSDictionary *)headersForURL:(NSURL *)url { 118 | if (!url) return nil; 119 | return _headersFilter ? _headersFilter(url, _headers) : _headers; 120 | } 121 | 122 | - (NSString *)cacheKeyForURL:(NSURL *)url transformKey:(nullable NSString *)transformKey { 123 | if (!url) return nil; 124 | NSString *cacheKey = _cacheKeyFilter ? _cacheKeyFilter(url) : url.absoluteString; 125 | if (transformKey) 126 | return [NSString stringWithFormat:@"%@--%@", cacheKey, transformKey]; 127 | else 128 | return cacheKey; 129 | } 130 | 131 | #pragma mark Network Indicator 132 | 133 | + (_YYWebImageApplicationNetworkIndicatorInfo *)_networkIndicatorInfo { 134 | return objc_getAssociatedObject(self, @selector(_networkIndicatorInfo)); 135 | } 136 | 137 | + (void)_setNetworkIndicatorInfo:(_YYWebImageApplicationNetworkIndicatorInfo *)info { 138 | objc_setAssociatedObject(self, @selector(_networkIndicatorInfo), info, OBJC_ASSOCIATION_RETAIN); 139 | } 140 | 141 | + (void)_delaySetActivity:(NSTimer *)timer { 142 | UIApplication *app = _YYSharedApplication(); 143 | if (!app) return; 144 | 145 | NSNumber *visiable = timer.userInfo; 146 | if (app.networkActivityIndicatorVisible != visiable.boolValue) { 147 | [app setNetworkActivityIndicatorVisible:visiable.boolValue]; 148 | } 149 | [timer invalidate]; 150 | } 151 | 152 | + (void)_changeNetworkActivityCount:(NSInteger)delta { 153 | if (!_YYSharedApplication()) return; 154 | 155 | void (^block)() = ^{ 156 | _YYWebImageApplicationNetworkIndicatorInfo *info = [self _networkIndicatorInfo]; 157 | if (!info) { 158 | info = [_YYWebImageApplicationNetworkIndicatorInfo new]; 159 | [self _setNetworkIndicatorInfo:info]; 160 | } 161 | NSInteger count = info.count; 162 | count += delta; 163 | info.count = count; 164 | [info.timer invalidate]; 165 | info.timer = [NSTimer timerWithTimeInterval:kNetworkIndicatorDelay target:self selector:@selector(_delaySetActivity:) userInfo:@(info.count > 0) repeats:NO]; 166 | [[NSRunLoop mainRunLoop] addTimer:info.timer forMode:NSRunLoopCommonModes]; 167 | }; 168 | if ([NSThread isMainThread]) { 169 | block(); 170 | } else { 171 | dispatch_async(dispatch_get_main_queue(), block); 172 | } 173 | } 174 | 175 | + (void)incrementNetworkActivityCount { 176 | [self _changeNetworkActivityCount:1]; 177 | } 178 | 179 | + (void)decrementNetworkActivityCount { 180 | [self _changeNetworkActivityCount:-1]; 181 | } 182 | 183 | + (NSInteger)currentNetworkActivityCount { 184 | _YYWebImageApplicationNetworkIndicatorInfo *info = [self _networkIndicatorInfo]; 185 | return info.count; 186 | } 187 | 188 | @end 189 | -------------------------------------------------------------------------------- /PlayCornerRadius/YYWebImage/YYWebImage/YYWebImageOperation.h: -------------------------------------------------------------------------------- 1 | // 2 | // YYWebImageOperation.h 3 | // YYWebImage 4 | // 5 | // Created by ibireme on 15/2/15. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | 14 | #if __has_include() 15 | #import 16 | #import 17 | #else 18 | #import "YYImageCache.h" 19 | #import "YYWebImageManager.h" 20 | #endif 21 | 22 | NS_ASSUME_NONNULL_BEGIN 23 | 24 | /** 25 | The YYWebImageOperation class is an NSOperation subclass used to fetch image 26 | from URL request. 27 | 28 | @discussion It's an asynchronous operation. You typically execute it by adding 29 | it to an operation queue, or calls 'start' to execute it manually. When the 30 | operation is started, it will: 31 | 32 | 1. Get the image from the cache, if exist, return it with `completion` block. 33 | 2. Start an URL connection to fetch image from the request, invoke the `progress` 34 | to notify request progress (and invoke `completion` block to return the 35 | progressive image if enabled by progressive option). 36 | 3. Process the image by invoke the `transform` block. 37 | 4. Put the image to cache and return it with `completion` block. 38 | 39 | */ 40 | @interface YYWebImageOperation : NSOperation 41 | 42 | @property (nonatomic, strong, readonly) NSURLRequest *request; ///< The image URL request. 43 | @property (nullable, nonatomic, strong, readonly) NSURLResponse *response; ///< The response for request. 44 | @property (nullable, nonatomic, strong, readonly) YYImageCache *cache; ///< The image cache. 45 | @property (nonatomic, strong, readonly) NSString *cacheKey; ///< The image cache key. 46 | @property (nonatomic, readonly) YYWebImageOptions options; ///< The operation's option. 47 | 48 | /** 49 | Whether the URL connection should consult the credential storage for authenticating 50 | the connection. Default is YES. 51 | 52 | @discussion This is the value that is returned in the `NSURLConnectionDelegate` 53 | method `-connectionShouldUseCredentialStorage:`. 54 | */ 55 | @property (nonatomic) BOOL shouldUseCredentialStorage; 56 | 57 | /** 58 | The credential used for authentication challenges in `-connection:didReceiveAuthenticationChallenge:`. 59 | 60 | @discussion This will be overridden by any shared credentials that exist for the 61 | username or password of the request URL, if present. 62 | */ 63 | @property (nullable, nonatomic, strong) NSURLCredential *credential; 64 | 65 | /** 66 | Creates and returns a new operation. 67 | 68 | You should call `start` to execute this operation, or you can add the operation 69 | to an operation queue. 70 | 71 | @param request The Image request. This value should not be nil. 72 | @param options A mask to specify options to use for this operation. 73 | @param cache An image cache. Pass nil to avoid image cache. 74 | @param cacheKey An image cache key. Pass nil to avoid image cache. 75 | @param progress A block invoked in image fetch progress. 76 | The block will be invoked in background thread. Pass nil to avoid it. 77 | @param transform A block invoked before image fetch finished to do additional image process. 78 | The block will be invoked in background thread. Pass nil to avoid it. 79 | @param completion A block invoked when image fetch finished or cancelled. 80 | The block will be invoked in background thread. Pass nil to avoid it. 81 | @param transformKey 转换key,链接相同但key不同会有不同的缓存 82 | 83 | @return The image request opeartion, or nil if an error occurs. 84 | */ 85 | - (instancetype)initWithRequest:(NSURLRequest *)request 86 | options:(YYWebImageOptions)options 87 | cache:(nullable YYImageCache *)cache 88 | cacheKey:(nullable NSString *)cacheKey 89 | progress:(nullable YYWebImageProgressBlock)progress 90 | transform:(nullable YYWebImageTransformBlock)transform 91 | transformKey:(nullable NSString *)transformKey 92 | completion:(nullable YYWebImageCompletionBlock)completion NS_DESIGNATED_INITIALIZER; 93 | 94 | - (instancetype)init UNAVAILABLE_ATTRIBUTE; 95 | + (instancetype)new UNAVAILABLE_ATTRIBUTE; 96 | 97 | @end 98 | 99 | NS_ASSUME_NONNULL_END 100 | -------------------------------------------------------------------------------- /PlayCornerRadius/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // PlayCornerRadius 4 | // 5 | // Created by 肖文 on 2017/1/18. 6 | // Copyright © 2017年 肖文. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # XWCornerRadius 2 | 一个简单的iOS设置圆角不引起性能问题的分类 3 | 4 | 详见简书文章:[简书地址](http://www.jianshu.com/p/ddad9e336162) 5 | 6 | ![demo列表](http://upload-images.jianshu.io/upload_images/1154055-30e4590b6302be22.gif?imageMogr2/auto-orient/strip) 7 | -------------------------------------------------------------------------------- /XWCornerRadius/UIView+XWAddForRoundedCorner.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+XWAddForRoundedCorner.h 3 | // PlayCornerRadius 4 | // 5 | // Created by 肖文 on 2017/1/18. 6 | // Copyright © 2017年 肖文. All rights reserved. 7 | // 该类设置圆角的原理为在view的最上层绘制一张相应的遮罩图片,图片的背景只要保证和view的父视图背景色一样,就能达到圆角的效果, 8 | 9 | #import 10 | 11 | @interface UIView (XWAddForRoundedCorner) 12 | 13 | 14 | /** 15 | 设置一个四角圆角 16 | 17 | @param radius 圆角半径 18 | @param color 圆角背景色 19 | */ 20 | - (void)xw_roundedCornerWithRadius:(CGFloat)radius cornerColor:(UIColor *)color; 21 | 22 | /** 23 | 设置一个普通圆角 24 | 25 | @param radius 圆角半径 26 | @param color 圆角背景色 27 | @param corners 圆角位置 28 | */ 29 | - (void)xw_roundedCornerWithRadius:(CGFloat)radius cornerColor:(UIColor *)color corners:(UIRectCorner)corners; 30 | 31 | /** 32 | 设置一个带边框的圆角 33 | 34 | @param cornerRadii 圆角半径cornerRadii 35 | @param color 圆角背景色 36 | @param corners 圆角位置 37 | @param borderColor 边框颜色 38 | @param borderWidth 边框线宽 39 | */ 40 | - (void)xw_roundedCornerWithCornerRadii:(CGSize)cornerRadii cornerColor:(UIColor *)color corners:(UIRectCorner)corners borderColor:(UIColor *)borderColor borderWidth:(CGFloat)borderWidth; 41 | @end 42 | 43 | @interface CALayer (XWAddForRoundedCorner) 44 | 45 | @property (nonatomic, strong) UIImage *contentImage;//contents的便捷设置 46 | 47 | /**如下分别对应UIView的相应API*/ 48 | 49 | - (void)xw_roundedCornerWithRadius:(CGFloat)radius cornerColor:(UIColor *)color; 50 | 51 | - (void)xw_roundedCornerWithRadius:(CGFloat)radius cornerColor:(UIColor *)color corners:(UIRectCorner)corners; 52 | 53 | - (void)xw_roundedCornerWithCornerRadii:(CGSize)cornerRadii cornerColor:(UIColor *)color corners:(UIRectCorner)corners borderColor:(UIColor *)borderColor borderWidth:(CGFloat)borderWidth; 54 | 55 | @end 56 | -------------------------------------------------------------------------------- /XWCornerRadius/UIView+XWAddForRoundedCorner.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+XWAddForRoundedCorner.m 3 | // PlayCornerRadius 4 | // 5 | // Created by 肖文 on 2017/1/18. 6 | // Copyright © 2017年 肖文. All rights reserved. 7 | // 8 | 9 | #import "UIView+XWAddForRoundedCorner.h" 10 | #import 11 | 12 | @implementation NSObject (_XWAdd) 13 | 14 | + (void)xw_swizzleInstanceMethod:(SEL)originalSel with:(SEL)newSel { 15 | Method originalMethod = class_getInstanceMethod(self, originalSel); 16 | Method newMethod = class_getInstanceMethod(self, newSel); 17 | if (!originalMethod || !newMethod) return; 18 | method_exchangeImplementations(originalMethod, newMethod); 19 | } 20 | 21 | - (void)xw_setAssociateValue:(id)value withKey:(void *)key { 22 | objc_setAssociatedObject(self, key, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 23 | } 24 | 25 | - (id)xw_getAssociatedValueForKey:(void *)key { 26 | return objc_getAssociatedObject(self, key); 27 | } 28 | 29 | - (void)xw_removeAssociateWithKey:(void *)key { 30 | objc_setAssociatedObject(self, key, nil, OBJC_ASSOCIATION_ASSIGN); 31 | } 32 | 33 | @end 34 | 35 | @implementation UIImage (XWAddForRoundedCorner) 36 | 37 | + (UIImage *)xw_imageWithSize:(CGSize)size drawBlock:(void (^)(CGContextRef context))drawBlock { 38 | if (!drawBlock) return nil; 39 | UIGraphicsBeginImageContextWithOptions(size, NO, 0); 40 | CGContextRef context = UIGraphicsGetCurrentContext(); 41 | if (!context) return nil; 42 | drawBlock(context); 43 | UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); 44 | UIGraphicsEndImageContext(); 45 | return image; 46 | } 47 | 48 | + (UIImage *)xw_maskRoundCornerRadiusImageWithColor:(UIColor *)color cornerRadii:(CGSize)cornerRadii size:(CGSize)size corners:(UIRectCorner)corners borderColor:(UIColor *)borderColor borderWidth:(CGFloat)borderWidth{ 49 | return [UIImage xw_imageWithSize:size drawBlock:^(CGContextRef _Nonnull context) { 50 | CGContextSetLineWidth(context, 0); 51 | [color set]; 52 | CGRect rect = CGRectMake(0, 0, size.width, size.height); 53 | UIBezierPath *rectPath = [UIBezierPath bezierPathWithRect:CGRectInset(rect, -0.3, -0.3)]; 54 | UIBezierPath *roundPath = [UIBezierPath bezierPathWithRoundedRect:CGRectInset(rect, 0.3, 0.3) byRoundingCorners:corners cornerRadii:cornerRadii]; 55 | [rectPath appendPath:roundPath]; 56 | CGContextAddPath(context, rectPath.CGPath); 57 | CGContextEOFillPath(context); 58 | if (!borderColor || !borderWidth) return; 59 | [borderColor set]; 60 | UIBezierPath *borderOutterPath = [UIBezierPath bezierPathWithRoundedRect:rect byRoundingCorners:corners cornerRadii:cornerRadii]; 61 | UIBezierPath *borderInnerPath = [UIBezierPath bezierPathWithRoundedRect:CGRectInset(rect, borderWidth, borderWidth) byRoundingCorners:corners cornerRadii:cornerRadii]; 62 | [borderOutterPath appendPath:borderInnerPath]; 63 | CGContextAddPath(context, borderOutterPath.CGPath); 64 | CGContextEOFillPath(context); 65 | }]; 66 | } 67 | 68 | @end 69 | 70 | 71 | 72 | static void *const _XWMaskCornerRadiusLayerKey = "_XWMaskCornerRadiusLayerKey"; 73 | static NSMutableSet *maskCornerRaidusImageSet; 74 | 75 | @implementation CALayer (XWAddForRoundedCorner) 76 | 77 | + (void)load{ 78 | [CALayer xw_swizzleInstanceMethod:@selector(layoutSublayers) with:@selector(_xw_layoutSublayers)]; 79 | } 80 | 81 | - (UIImage *)contentImage{ 82 | return [UIImage imageWithCGImage:(__bridge CGImageRef)self.contents]; 83 | } 84 | 85 | - (void)setContentImage:(UIImage *)contentImage{ 86 | self.contents = (__bridge id)contentImage.CGImage; 87 | } 88 | 89 | - (void)xw_roundedCornerWithRadius:(CGFloat)radius cornerColor:(UIColor *)color{ 90 | [self xw_roundedCornerWithRadius:radius cornerColor:color corners:UIRectCornerAllCorners]; 91 | } 92 | 93 | - (void)xw_roundedCornerWithRadius:(CGFloat)radius cornerColor:(UIColor *)color corners:(UIRectCorner)corners{ 94 | [self xw_roundedCornerWithCornerRadii:CGSizeMake(radius, radius) cornerColor:color corners:corners borderColor:nil borderWidth:0]; 95 | } 96 | 97 | - (void)xw_roundedCornerWithCornerRadii:(CGSize)cornerRadii cornerColor:(UIColor *)color corners:(UIRectCorner)corners borderColor:(UIColor *)borderColor borderWidth:(CGFloat)borderWidth{ 98 | if (!color) return; 99 | CALayer *cornerRadiusLayer = [self xw_getAssociatedValueForKey:_XWMaskCornerRadiusLayerKey]; 100 | if (!cornerRadiusLayer) { 101 | cornerRadiusLayer = [CALayer new]; 102 | cornerRadiusLayer.opaque = YES; 103 | [self xw_setAssociateValue:cornerRadiusLayer withKey:_XWMaskCornerRadiusLayerKey]; 104 | } 105 | if (color) { 106 | [cornerRadiusLayer xw_setAssociateValue:color withKey:"_xw_cornerRadiusImageColor"]; 107 | }else{ 108 | [cornerRadiusLayer xw_removeAssociateWithKey:"_xw_cornerRadiusImageColor"]; 109 | } 110 | [cornerRadiusLayer xw_setAssociateValue:[NSValue valueWithCGSize:cornerRadii] withKey:"_xw_cornerRadiusImageRadius"]; 111 | [cornerRadiusLayer xw_setAssociateValue:@(corners) withKey:"_xw_cornerRadiusImageCorners"]; 112 | if (borderColor) { 113 | [cornerRadiusLayer xw_setAssociateValue:borderColor withKey:"_xw_cornerRadiusImageBorderColor"]; 114 | }else{ 115 | [cornerRadiusLayer xw_removeAssociateWithKey:"_xw_cornerRadiusImageBorderColor"]; 116 | } 117 | [cornerRadiusLayer xw_setAssociateValue:@(borderWidth) withKey:"_xw_cornerRadiusImageBorderWidth"]; 118 | UIImage *image = [self _xw_getCornerRadiusImageFromSet]; 119 | if (image) { 120 | [CATransaction begin]; 121 | [CATransaction setDisableActions:YES]; 122 | cornerRadiusLayer.contentImage = image; 123 | [CATransaction commit]; 124 | } 125 | 126 | } 127 | 128 | - (UIImage *)_xw_getCornerRadiusImageFromSet{ 129 | if (!self.bounds.size.width || !self.bounds.size.height) return nil; 130 | CALayer *cornerRadiusLayer = [self xw_getAssociatedValueForKey:_XWMaskCornerRadiusLayerKey]; 131 | UIColor *color = [cornerRadiusLayer xw_getAssociatedValueForKey:"_xw_cornerRadiusImageColor"]; 132 | if (!color) return nil; 133 | CGSize radius = [[cornerRadiusLayer xw_getAssociatedValueForKey:"_xw_cornerRadiusImageRadius"] CGSizeValue]; 134 | NSUInteger corners = [[cornerRadiusLayer xw_getAssociatedValueForKey:"_xw_cornerRadiusImageCorners"] unsignedIntegerValue]; 135 | CGFloat borderWidth = [[cornerRadiusLayer xw_getAssociatedValueForKey:"_xw_cornerRadiusImageBorderWidth"] floatValue]; 136 | UIColor *borderColor = [cornerRadiusLayer xw_getAssociatedValueForKey:"_xw_cornerRadiusImageBorderColor"]; 137 | if (!maskCornerRaidusImageSet) { 138 | maskCornerRaidusImageSet = [NSMutableSet new]; 139 | } 140 | __block UIImage *image = nil; 141 | [maskCornerRaidusImageSet enumerateObjectsUsingBlock:^(UIImage * _Nonnull obj, BOOL * _Nonnull stop) { 142 | CGSize imageSize = [[obj xw_getAssociatedValueForKey:"_xw_cornerRadiusImageSize"] CGSizeValue]; 143 | UIColor *imageColor = [obj xw_getAssociatedValueForKey:"_xw_cornerRadiusImageColor"]; 144 | CGSize imageRadius = [[obj xw_getAssociatedValueForKey:"_xw_cornerRadiusImageRadius"] CGSizeValue]; 145 | NSUInteger imageCorners = [[obj xw_getAssociatedValueForKey:"_xw_cornerRadiusImageCorners"] unsignedIntegerValue]; 146 | CGFloat imageBorderWidth = [[obj xw_getAssociatedValueForKey:"_xw_cornerRadiusImageBorderWidth"] floatValue]; 147 | UIColor *imageBorderColor = [obj xw_getAssociatedValueForKey:"_xw_cornerRadiusImageBorderColor"]; 148 | BOOL isBorderSame = (CGColorEqualToColor(borderColor.CGColor, imageBorderColor.CGColor) && borderWidth == imageBorderWidth) || (!borderColor && !imageBorderColor) || (!borderWidth && !imageBorderWidth); 149 | BOOL canReuse = CGSizeEqualToSize(self.bounds.size, imageSize) && CGColorEqualToColor(imageColor.CGColor, color.CGColor) && imageCorners == corners && CGSizeEqualToSize(radius, imageRadius) && isBorderSame; 150 | if (canReuse) { 151 | image = obj; 152 | *stop = YES; 153 | } 154 | }]; 155 | if (!image) { 156 | image = [UIImage xw_maskRoundCornerRadiusImageWithColor:color cornerRadii:radius size:self.bounds.size corners:corners borderColor:borderColor borderWidth:borderWidth]; 157 | [image xw_setAssociateValue:[NSValue valueWithCGSize:self.bounds.size] withKey:"_xw_cornerRadiusImageSize"]; 158 | [image xw_setAssociateValue:color withKey:"_xw_cornerRadiusImageColor"]; 159 | [image xw_setAssociateValue:[NSValue valueWithCGSize:radius] withKey:"_xw_cornerRadiusImageRadius"]; 160 | [image xw_setAssociateValue:@(corners) withKey:"_xw_cornerRadiusImageCorners"]; 161 | if (borderColor) { 162 | [image xw_setAssociateValue:color withKey:"_xw_cornerRadiusImageBorderColor"]; 163 | } 164 | [image xw_setAssociateValue:@(borderWidth) withKey:"_xw_cornerRadiusImageBorderWidth"]; 165 | [maskCornerRaidusImageSet addObject:image]; 166 | } 167 | return image; 168 | } 169 | 170 | #pragma mark - exchage Methods 171 | 172 | - (void)_xw_layoutSublayers{ 173 | [self _xw_layoutSublayers]; 174 | CALayer *cornerRadiusLayer = [self xw_getAssociatedValueForKey:_XWMaskCornerRadiusLayerKey]; 175 | if (cornerRadiusLayer) { 176 | UIImage *aImage = [self _xw_getCornerRadiusImageFromSet]; 177 | [CATransaction begin]; 178 | [CATransaction setDisableActions:YES]; 179 | cornerRadiusLayer.contentImage = aImage; 180 | cornerRadiusLayer.frame = self.bounds; 181 | [CATransaction commit]; 182 | [self addSublayer:cornerRadiusLayer]; 183 | } 184 | } 185 | 186 | @end 187 | 188 | @implementation UIView (XWAddForRoundedCorner) 189 | 190 | - (void)xw_roundedCornerWithRadius:(CGFloat)radius cornerColor:(UIColor *)color{ 191 | [self.layer xw_roundedCornerWithRadius:radius cornerColor:color]; 192 | } 193 | 194 | - (void)xw_roundedCornerWithRadius:(CGFloat)radius cornerColor:(UIColor *)color corners:(UIRectCorner)corners{ 195 | [self.layer xw_roundedCornerWithRadius:radius cornerColor:color corners:corners]; 196 | } 197 | 198 | - (void)xw_roundedCornerWithCornerRadii:(CGSize)cornerRadii cornerColor:(UIColor *)color corners:(UIRectCorner)corners borderColor:(UIColor *)borderColor borderWidth:(CGFloat)borderWidth{ 199 | [self.layer xw_roundedCornerWithCornerRadii:cornerRadii cornerColor:color corners:corners borderColor:borderColor borderWidth:borderWidth]; 200 | } 201 | 202 | @end 203 | --------------------------------------------------------------------------------