├── .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 | Path | Scale |
22 | "icon.png" | 1 |
23 | "icon@2x.png" | 2 |
24 | "icon@2.5x.png" | 2.5 |
25 | "icon@2x" | 1 |
26 | "icon@2x..png" | 1 |
27 | "icon@2x.png/" | 1 |
28 |
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 | Before | After(scale:2) |
41 | "icon" | "icon@2x" |
42 | "icon " | "icon @2x" |
43 | "icon.top" | "icon.top@2x" |
44 | "/p/name" | "/p/name@2x" |
45 | "/path/" | "/path/" |
46 |
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 | Path | Scale |
63 | "icon.png" | 1 |
64 | "icon@2x.png" | 2 |
65 | "icon@2.5x.png" | 2.5 |
66 | "icon@2x" | 1 |
67 | "icon@2x..png" | 1 |
68 | "icon@2x.png/" | 1 |
69 |
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 | 
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 |
--------------------------------------------------------------------------------