Merge pull request #2664 from SDWebImage/5.0
Merge 5.x branch into master branch, ready for 5.0.0 release
|
@ -1,7 +1,27 @@
|
|||
# Contributing to SDWebImage
|
||||
|
||||
First of all, we want to thank you for you interest in this project.
|
||||
Every contribution matters, this is how we are keeping the project alive.
|
||||
We are all owners, from Olivier who started the project, to the people who use it in their projects and participated in a conversation, improved the documentation, created an example or made any code changes.
|
||||
If you want to help, but don't know where to begin, we recommend you start small:
|
||||
- it would help a lot if you read: https://opensource.guide/how-to-contribute/
|
||||
- read the ongoing discussions to see what the overall status is
|
||||
- pitch in the converstations where you feel it's useful. Talk to other people, ask questions if you don't understand something
|
||||
- contributing to the documentation or the ongoing converstations is as important as contributing to the code
|
||||
|
||||
We want to make contributing to this project as easy and transparent as possible. Here are a few guidelines for making all our lives easier.
|
||||
|
||||
## Contribute to ongoing conversations
|
||||
|
||||
If you have a valid opinion about something we are talking about, feel free to share it.
|
||||
If you also encountered an issue that someone else described, pitch in. Better yet, if you already fixed it in a certain way, share that.
|
||||
We focus mostly on the GitHub conversations, but you can also help by going to the [questions tagged with "SDWebImage" on StackOverflow](https://stackoverflow.com/questions/tagged/sdwebimage) and getting involved.
|
||||
|
||||
## Improving documentation
|
||||
|
||||
A project's documentation is something you can always improve on. Make sure you go through the existing documentation and suggest changes or just create new pieces of documentation.
|
||||
Examples are also welcome.
|
||||
|
||||
## Asking questions
|
||||
|
||||
We don't use GitHub as a support forum. For any usage questions that are not specific to the project itself, please ask on [Stack Overflow](https://stackoverflow.com/) instead. By doing so, you'll be more likely to quickly solve your problem, and you'll allow anyone else with the same question to find the answer. This also allows maintainers to focus on improving the project for others.
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
[submodule "Vendors/libwebp"]
|
||||
path = Vendors/libwebp
|
||||
url = https://github.com/webmproject/libwebp
|
||||
[submodule "Vendors/FLAnimatedImage"]
|
||||
path = Vendors/FLAnimatedImage
|
||||
url = https://github.com/Flipboard/FLAnimatedImage
|
36
.travis.yml
|
@ -1,6 +1,6 @@
|
|||
|
||||
language: objective-c
|
||||
osx_image: xcode9
|
||||
osx_image: xcode10
|
||||
|
||||
env:
|
||||
global:
|
||||
|
@ -29,26 +29,34 @@ script:
|
|||
- pod lib lint --allow-warnings
|
||||
|
||||
- echo Build as static library
|
||||
- xcodebuild clean build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage iOS static' -sdk iphonesimulator PLATFORM_NAME=iphonesimulator -configuration Debug | xcpretty -c
|
||||
- xcodebuild clean build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage watchOS static' -sdk watchsimulator -configuration Debug | xcpretty -c
|
||||
- xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage static' -sdk iphonesimulator PLATFORM_NAME=iphonesimulator -configuration Debug | xcpretty -c
|
||||
- xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage static' -sdk watchsimulator -configuration Debug | xcpretty -c
|
||||
|
||||
- echo Build as dynamic framework
|
||||
- xcodebuild clean build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage OSX' -sdk macosx -configuration Debug | xcpretty -c
|
||||
- xcodebuild clean build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage iOS' -sdk iphonesimulator PLATFORM_NAME=iphonesimulator -configuration Debug | xcpretty -c
|
||||
- xcodebuild clean build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage tvOS' -sdk appletvsimulator -configuration Debug | xcpretty -c
|
||||
- xcodebuild clean build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage watchOS' -sdk watchsimulator -configuration Debug | xcpretty -c
|
||||
- echo Build as dynamic frameworks
|
||||
- xcodebuild build clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImage' -sdk macosx -configuration Debug | xcpretty -c
|
||||
- xcodebuild build clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImage' -sdk iphonesimulator PLATFORM_NAME=iphonesimulator -configuration Debug | xcpretty -c
|
||||
- xcodebuild build clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImage' -sdk appletvsimulator -configuration Debug | xcpretty -c
|
||||
- xcodebuild build clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImage' -sdk watchsimulator -configuration Debug | xcpretty -c
|
||||
- xcodebuild build clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImageMapKit' -sdk macosx -configuration Debug | xcpretty -c
|
||||
- xcodebuild build clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImageMapKit' -sdk iphonesimulator PLATFORM_NAME=iphonesimulator -configuration Debug | xcpretty -c
|
||||
- xcodebuild build clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImageMapKit' -sdk appletvsimulator -configuration Debug | xcpretty -c
|
||||
|
||||
- echo Build the Demo apps
|
||||
- pod install --project-directory=Examples
|
||||
- xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage OSX Demo' -sdk macosx -configuration Debug | xcpretty -c
|
||||
- xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage iOS Demo' -configuration Debug -destination 'name=iPhone 6s' | xcpretty -c
|
||||
- xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage iOS Demo' -configuration Debug -destination 'name=iPhone XS' | xcpretty -c
|
||||
- xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage TV Demo' -sdk appletvsimulator -configuration Debug | xcpretty -c
|
||||
- xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage Watch Demo' -configuration Debug -destination 'name=iPhone 6s' | xcpretty -c
|
||||
- xcodebuild build -workspace SDWebImage.xcworkspace -scheme 'SDWebImage Watch Demo' -configuration Debug -destination 'name=iPhone XS' | xcpretty -c
|
||||
|
||||
- mkdir DerivedData
|
||||
|
||||
- echo Run the tests
|
||||
- pod install --project-directory=Tests
|
||||
- xcodebuild clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImage iOS' -sdk iphonesimulator PLATFORM_NAME=iphonesimulator -configuration Debug | xcpretty -c
|
||||
- xcodebuild clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImage iOS Demo' -configuration Debug -destination 'name=iPhone 6s' | xcpretty -c
|
||||
- xcodebuild test -workspace SDWebImage.xcworkspace -scheme 'Tests' -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 6,OS=latest' -configuration Debug | xcpretty -c
|
||||
- xcodebuild test -workspace SDWebImage.xcworkspace -scheme 'Tests' -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone XS' -configuration Debug | xcpretty -c
|
||||
- mv ~/Library/Developer/Xcode/DerivedData/ ./DerivedData/iOS
|
||||
- xcodebuild test -workspace SDWebImage.xcworkspace -scheme 'Tests Mac' -sdk macosx -destination 'platform=OS X,arch=x86_64' -configuration Debug | xcpretty -c
|
||||
- mv ~/Library/Developer/Xcode/DerivedData/ ./DerivedData/macOS
|
||||
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
- bash <(curl -s https://codecov.io/bash) -D './DerivedData/iOS' -J '^SDWebImage$' -F 'iOS'
|
||||
- bash <(curl -s https://codecov.io/bash) -D './DerivedData/macOS' -J '^SDWebImage$' -F 'macOS'
|
||||
|
|
207
CHANGELOG.md
|
@ -1,3 +1,78 @@
|
|||
## [5.0.0 Major release - Customizable SDWebImage, on Mar 31th, 2019](https://github.com/rs/SDWebImage/releases/tag/5.0.0)
|
||||
See [all tickets marked for the 5.0.0 release](https://github.com/SDWebImage/SDWebImage/milestone/15)
|
||||
|
||||
### Features
|
||||
|
||||
#### Animated Image
|
||||
- Introduce `SDAnimatedImageView` and `SDAnimatedImage` for full stack solution of animated images.
|
||||
- Supports custom coders for nearly every animated image format.
|
||||
- Supports progressive loading for animated images.
|
||||
- iOS/tvOS/macOS cross-platform support.
|
||||
|
||||
#### Transformer
|
||||
- Using transformer to apply image processing after image was loaded.
|
||||
- Built-in transformer for common usage: Rounded Corner, Resize, Crop, Flip, Rotate, Tint Color, Blur Effect, Core Image Filter...
|
||||
- Convenient category methods for `UIImage`/`NSImage`
|
||||
|
||||
#### Custom Loader
|
||||
- Using loader protocol to implements your own image loader.
|
||||
- Not limited on HTTP, you can even using SDWebImage with PhotoKit and third-party SDKs.
|
||||
- Supports multiple loaders at the same time using `SDImageLoadersManager`.
|
||||
|
||||
#### Custom Cache
|
||||
- Using cache protocol to implements your own image cache.
|
||||
- Standalone disk cache and memory cache class for advanced usage and customization.
|
||||
- Supports multiple caches at the same time using `SDImageCachesManager`.
|
||||
|
||||
#### Indicator
|
||||
- Use indicator to provide a loading view, customizable
|
||||
- Built-in Activity Indicator and Progress Indicator.
|
||||
- iOS/tvOS/macOS cross-platform support.
|
||||
|
||||
#### Plugins
|
||||
- All external image format coders are plugins. Supports WebP, HEIF, BPG, FLIF, SVG, PDF... Choose what you need in: [Coder Plugin List](https://github.com/SDWebImage/SDWebImage/wiki/Coder-Plugin-List)
|
||||
- PhotoKit loader as a plugin: [SDWebImagePhotosPlugin](https://github.com/SDWebImage/SDWebImagePhotosPlugin)
|
||||
- FLAnimatedImage integration as a plugin: [SDWebImageFLPlugin](https://github.com/SDWebImage/SDWebImageFLPlugin)
|
||||
- YYImage/YYCache integration as a plugin: [SDWebImageYYPlugin](https://github.com/SDWebImage/SDWebImageYYPlugin)
|
||||
|
||||
### Improvements
|
||||
|
||||
#### Swift
|
||||
- Better Swift support with some manual renaming APIs.
|
||||
- Full nullability annotation.
|
||||
- Using class property for shared instance.
|
||||
- Using `NS_TYPED_ENUM` and `NS_STRING_ENUM` for better generated APIs.
|
||||
|
||||
#### API
|
||||
- Using context option to control detail behavior for each image request beyond the limit of enums.
|
||||
- Using prefetcher to manage token (list of URL requests) to avoid conflict.
|
||||
- Use request modifier to modify constructed URLRequest.
|
||||
|
||||
### Project
|
||||
|
||||
- Supports the latest Xcode 10.
|
||||
- Supports iOS 8.0+/tvOS 9.0+/watchOS 2.0+/macOS 10.10+.
|
||||
|
||||
### Migration
|
||||
|
||||
Check [5.0 migration guide](https://github.com/SDWebImage/SDWebImage/wiki/5.0-Migration-guide) for the migration from 4.x to 5.x.
|
||||
|
||||
## [4.0.0 - New platforms (Mac OS X and watchOS) + refactoring, on Jan 28th, 2017](https://github.com/SDWebImage/SDWebImage/releases/tag/4.0.0)
|
||||
|
||||
See [all tickets marked for the 4.0.0 release](https://github.com/SDWebImage/SDWebImage/milestone/3)
|
||||
Versions 4.0.0-beta and 4.0.0-beta 2 list all the changes.
|
||||
|
||||
|
||||
## [5.0.0-beta6 - 5.0 Beta, on Mar 15th, 2019](https://github.com/rs/SDWebImage/releases/tag/5.0.0-beta6)
|
||||
See [all tickets marked for the 5.0.0-beta6 release](https://github.com/rs/SDWebImage/milestone/30)
|
||||
|
||||
#### Fixes
|
||||
- Fix the issue that SDWebImagePrefetch in 5.x, will submit all prefetch URLs to manager without any concurrent limit #2631
|
||||
- Fix the current transformer cache key generating rules, try to keep the image file extension #2635
|
||||
|
||||
#### Project
|
||||
- Move some internal classes into private header files, make it easy to maintain the code #2634
|
||||
|
||||
## [4.4.6 - 4.4 patch, on Feb 26th, 2019](https://github.com/SDWebImage/SDWebImage/releases/tag/4.4.6)
|
||||
See [all tickets marked for the 4.4.6 release](https://github.com/SDWebImage/SDWebImage/milestone/33)
|
||||
|
||||
|
@ -12,15 +87,93 @@ See [all tickets marked for the 4.4.6 release](https://github.com/SDWebImage/SDW
|
|||
#### Performances
|
||||
- Nil imageData before decode process to free memory #2624
|
||||
|
||||
## [5.0.0-beta5 - Customizable SDWebImage, on Jan 31st, 2019](https://github.com/rs/SDWebImage/releases/tag/5.0.0-beta5)
|
||||
See [all tickets marked for the 5.0.0-beta5 release](https://github.com/rs/SDWebImage/milestone/32)
|
||||
|
||||
#### Fixes
|
||||
- Fix encoding options does not works #2602
|
||||
- Remove unnecessary CGImage check when encode first frame #2609
|
||||
|
||||
## [4.4.5 - 4.4 patch, on Jan 31st, 2019](https://github.com/SDWebImage/SDWebImage/releases/tag/4.4.5)
|
||||
See [all tickets marked for the 4.4.5 release](https://github.com/SDWebImage/SDWebImage/milestone/31)
|
||||
|
||||
#### Fixes
|
||||
- Revert the modular framework, try to fix some user's install issue when using SDWebImage in prefix header #2604
|
||||
- Revert the modular framework, try to fix some user's install issue when using SDWebImage in prefix header #2604
|
||||
- Fix wrong decompression scale calculation #2608
|
||||
- Fix shouldDecode check when image format is GIF #2606
|
||||
- Fix modify data pointer if webp image scaled down #2607
|
||||
|
||||
## [5.0.0-beta4 - Customizable SDWebImage, on Jan 26th, 2019](https://github.com/rs/SDWebImage/releases/tag/5.0.0-beta4)
|
||||
See [all tickets marked for the 5.0.0 release](https://github.com/rs/SDWebImage/milestone/15)
|
||||
|
||||
#### Features
|
||||
- Expose the graphics helper method for coder plugin author and fix scale issue #2523
|
||||
|
||||
#### Performances
|
||||
- Decrease animated decode times when cache enable #2468
|
||||
- Remove kCGImageSourceShouldCache option when creating image source #2472
|
||||
- Add autoreleasepool to release autorelease objects in advance when using GCD #2474
|
||||
|
||||
#### Fixes
|
||||
- Add protect when custom animated image class image data is nil during progressive animation check #2466
|
||||
- Fix background download #2500
|
||||
|
||||
#### Project
|
||||
- Merged targets + MapKit dedicated target for Carthage installs #2476. Carthage user now does not enable MapKit support by default.
|
||||
- Upgrade Xcode 10 + using xcconfig for project settings #2494
|
||||
|
||||
#### Notable Changes (from beta3)
|
||||
|
||||
Behavior:
|
||||
|
||||
- Move webp component (and libwebp dependency) to SDWebImage/SDWebImageWebPCoder #2469. Any user who use WebP in 5.0.0 should add [SDWebImageWebPCoder](https://github.com/SDWebImage/SDWebImageWebPCoder) to your Podfile or Cartfile instead.
|
||||
- Refactory cache path about namespace && final cache directory #2535. Now the default disk cache path was moved to suitable path with the namespace.
|
||||
- Use the memory bytes size, instead of pixel size to calculate the memory cost function #2568. Now the memory cost function use bytes size instead of pixels count.
|
||||
|
||||
Swift Only:
|
||||
|
||||
- Fix the accident changes of Swift API naming for `sd_imageDataAsFormat:` #2517
|
||||
|
||||
You can always check [5.0 migration guide](https://github.com/SDWebImage/SDWebImage/wiki/5.0-Migration-guide) for the latest information for these changes.
|
||||
|
||||
## [5.0.0-beta3 - Customizable SDWebImage, on Aug 30th, 2018](https://github.com/rs/SDWebImage/releases/tag/5.0.0-beta3)
|
||||
See [all tickets marked for the 5.0.0 release](https://github.com/rs/SDWebImage/milestone/15)
|
||||
|
||||
#### Features
|
||||
- Minimum progress interval config for `SDWebImageDownloader` #2415 #2437 1d8454d
|
||||
- Feature disk cache migration from 4.x #2417 #2433
|
||||
- Add `SDImageFormatHEIF` represent `mif1` && `msf1` brands #2423 (imported from 4.4.3)
|
||||
- Add default `HTTP User-Agent` for specific system #2409 (imported from 4.4.3)
|
||||
- Replace `valueForKey` with `objectForKey` when access NSDictionary #2399
|
||||
- Improved unit tests #2438 #2434
|
||||
- Enhanced contributing guide #2416
|
||||
- Adopt all the protocol APIs which contains getter value to use property instead, to make the API easy to use or Swift user #2452
|
||||
- Remove `sd_setAnimationImagesWithURLs` API, because its cause ambiguity, behave not consistently and have rare use case #2459
|
||||
- Improved `SDAnimatedImage` protocol with `initWithData:scale:options:` #2453
|
||||
- Extra args for `SDSetImageBlock` (added `cacheType` and `imageURL`) #2449
|
||||
|
||||
#### Fixes
|
||||
- Fix that using `NS_TYPED_ENUM` on `SDImageFormat` cause the existing Swift API (`sd_UTTypeFromImageFormat`) naming changed #2413
|
||||
- Fix that downloader options about image decoding is not correctly set #2414
|
||||
- Make download receive response notification only dispatch to specific observer #2426
|
||||
- Fix a race condition during progressive animation load in `SDAnimatedImageView` #2435
|
||||
- Fix the bug that `SDWebImageContextCacheKeyFilter` wrongly be used as cache serializer and cause crash #2451
|
||||
- Fix resource key invalid when clean cached disk file #2462
|
||||
- Add no expiration file support of disk cache #2461
|
||||
|
||||
## [5.0.0-beta2 - Customizable SDWebImage, on Jul 31st, 2018](https://github.com/rs/SDWebImage/releases/tag/5.0.0-beta2)
|
||||
See [all tickets marked for the 5.0.0 release](https://github.com/rs/SDWebImage/milestone/15)
|
||||
|
||||
#### Features
|
||||
- Add `SDImageCoderWebImageContext` coder option, which allow custom coder plugin, to receive the context option from top-level API #2405
|
||||
- Updated all existing diagrams for 5.0 release + added new ones (small detailed diagrams for the most important components) #2407
|
||||
|
||||
#### Fixes
|
||||
- Fix nullable key for `sd_imageLoadOperationForKey` #2389
|
||||
- Replace `__bridge_transfer` with `__bridge` when convert from `CFStringRef` to `NSString` #2392
|
||||
- Rename `sd_UTTypeFromSDImageFormat` to `sd_UTTypeFromImageFormat` #2395
|
||||
- Change `SDImageFormat` to use `NS_TYPED_EXTENSIBLE_ENUM` instead of fixed enum, to allow custom coder plugins to extend it #2400
|
||||
|
||||
## [4.4.4 - 4.4 patch, on Jan 26th, 2019](https://github.com/SDWebImage/SDWebImage/releases/tag/4.4.4)
|
||||
See [all tickets marked for the 4.4.4 release](https://github.com/SDWebImage/SDWebImage/milestone/29)
|
||||
|
||||
|
@ -83,6 +236,58 @@ See [all tickets marked for the 4.4.2 release](https://github.com/SDWebImage/SDW
|
|||
- Check for nullable key when cancel image load operation #2386
|
||||
- Replace `__bridge_transfer` with `__bridge` when convert from `CFStringRef` to `NSString` #2394
|
||||
|
||||
## [5.0.0-beta - Customizable SDWebImage, on Jul 17th, 2018](https://github.com/rs/SDWebImage/releases/tag/5.0.0-beta)
|
||||
See [all tickets marked for the 5.0.0 release](https://github.com/rs/SDWebImage/milestone/15)
|
||||
|
||||
#### Infrastructure
|
||||
- the new requirements are **iOS 8.0+** and **macOS 10.10+** #2147
|
||||
- **Xcode 9+**
|
||||
|
||||
#### Backwards incompatible changes
|
||||
|
||||
See the [5.0 Migration Guide](https://raw.githubusercontent.com/rs/SDWebImage/master/Docs/SDWebImage-5.0-Migration-guide.md) for a list of comprehensive changes and the way to update your code
|
||||
|
||||
#### Features
|
||||
- Introduce `SDAnimatedImageView`, `SDAnimatedImage` and refactor the way we handle animated images #2140
|
||||
- Added APNG support via dedicated coder `SDImageAPNGCoder` #2149
|
||||
- Refactored `SDWebImageDownloader` configs, separated them into a dedicated `SDWebImageDownloaderConfig` object #2263
|
||||
- Refactored the way we work with the scale factor #2266
|
||||
- Created request and response modifier #2261
|
||||
- Refactor Cache Path API #2276
|
||||
- Refactor custom cache serializer & headers filter for request level #2280
|
||||
- Refactor cache - Support custom memory cache & disk cache #2282
|
||||
- Refactor cache - Support custom web cache #2278
|
||||
- Refactor - custom image loader - Supports loader protocol #2256
|
||||
- Use `SDWebImageAvoidDecodeImage` to allow user to control force decode feature for individual image request #2283
|
||||
|
||||
- `SDImageCache` supports disk cache writing options. See `SDImageCacheConfig diskCacheWritingOptions` #2148
|
||||
- `SDImageCache` now uses `NSData writeToFile:options:error` instead of `NSFileManager createFileAtPath:contents:attributes` #2148
|
||||
- Moved `SDImageCache maxMemoryCost` and `SDImageCache maxMemoryCountLimit` to `SDImageCacheConfig` #2151
|
||||
- Added `SDImageCache diskImageDataExistsWithKey:` synchronous method #2151
|
||||
- Moved `UIImage sd_imageLoopCount` and `UIImage isGIF` (and renamed to `sd_isAnimated`) to `UIImage+Metadata` category, removed the outdated methods #2152
|
||||
- Move context and other type definitions to a separate header (`SDWebImageDefine`) to allow to be included without dependency #2188
|
||||
- Pass `context` arg from the top level APIs to the bottom level APIs to allow specify logic in the future #2189 d6a3e2c c24c3d3
|
||||
- Refactor the image indicator by creating `SDWebImageIndicator` and `SDWebImageProgressIndicator` protocols and two concrete classes that implement activity and progress indicators for both UIKit and AppKit #2185 46b62cf
|
||||
- Refactor the implementation of `SDWebImagePrefetcher` so it behaves more like a "shared instance" object, similar to other platform classes. Each instance will manage its own list of urls. #2191 1efc247 92f3d2c bc164d6
|
||||
- Refactored and enhanced the way we allow image transformations. Switched from a single delegate method to composition of `SDImageTransformer` #2219
|
||||
- API style refactoring - #2250
|
||||
- Use property instead of setters and getters to make the property available in Swift
|
||||
- Use class property with the correct name instead of `+(instanceType)sharedInstance` in singleton to make it more easy to use in Swift. The generated interface should be simple `open class var shared { get }`
|
||||
- Add all nullability annotation to avoid any `AnyObject!` implicitly unwrapped optionals (Except that `null_resettable`)
|
||||
- Add all Core Foundation Ownership using `CF_RETURNS_RETAINED` for
|
||||
Get Rule and `CF_RETURNS_NOT_RETAINED` for Create Rule to avoid any `Unmanaged` CF value
|
||||
- Change all key for Dictionary with `NS_STRING_ENUM` to make it easy to use in Swift with dot syntax
|
||||
- Change all global value type which represent enum with `NS_TYPED_ENUM` to make it easy to use in Swift with dot syntax
|
||||
- Remove the extra calculation of image orientation for ImageIO coder & Fix macOS image orientation #2271
|
||||
- Added `SDWebImageError` (defined as `NS_ERROR_ENUM`) to group all our errors together #2290
|
||||
- Added tests for macOS
|
||||
- Add the `SDWebImageContextStoreCacheType` context option to specify target cache type when the image is downloaded by manager and will store to cache #2360
|
||||
- Feature watchOS `WKInterfaceImage` with `sd_setImageWithURL` #2331
|
||||
- Add options to specify query cache sync/async behavior #2312
|
||||
|
||||
#### Fixes
|
||||
- `SDWebImageManager loadImageWithURL:options:progress:completed:` changed the `completed` param requirement from `nullable` to `nonnull` #2164
|
||||
|
||||
## [4.4.1 - 4.4 patch, on June 7th, 2018](https://github.com/SDWebImage/SDWebImage/releases/tag/4.4.1)
|
||||
See [all tickets marked for the 4.4.1 release](https://github.com/SDWebImage/SDWebImage/milestone/26)
|
||||
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
// Configuration settings file format documentation can be found at:
|
||||
// https://help.apple.com/xcode/#/dev745c5c974
|
||||
|
||||
#include "Module-Debug.xcconfig"
|
||||
#include "App-Shared.xcconfig"
|
||||
|
||||
// If enabled, only the active architecture is built.
|
||||
ONLY_ACTIVE_ARCH = YES
|
|
@ -0,0 +1,11 @@
|
|||
// Configuration settings file format documentation can be found at:
|
||||
// https://help.apple.com/xcode/#/dev745c5c974
|
||||
|
||||
#include "Module-Release.xcconfig"
|
||||
#include "App-Shared.xcconfig"
|
||||
|
||||
// If enabled, only the active architecture is built.
|
||||
ONLY_ACTIVE_ARCH = NO
|
||||
|
||||
// Space-separated list of additional flags to pass to the compiler for C and Objective-C files. Be sure to backslash-escape any arguments that contain spaces or special characters, such as path names that may contain spaces. Use this setting if Xcode does not already provide UI for a particular C or Objective-C compiler flag.
|
||||
OTHER_CFLAGS = -DNS_BLOCK_ASSERTIONS=1
|
|
@ -0,0 +1,10 @@
|
|||
// Configuration settings file format documentation can be found at:
|
||||
// https://help.apple.com/xcode/#/dev745c5c974
|
||||
|
||||
#include "Module-Shared.xcconfig"
|
||||
|
||||
// Name of an asset catalog app icon set whose contents will be merged into the `Info.plist`.
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon
|
||||
|
||||
// Implicitly include the named header. The path given should either be a project relative path or an absolute path.
|
||||
GCC_PREFIX_HEADER =
|
|
@ -0,0 +1,31 @@
|
|||
// Configuration settings file format documentation can be found at:
|
||||
// https://help.apple.com/xcode/#/dev745c5c974
|
||||
|
||||
#include "Module-Shared.xcconfig"
|
||||
|
||||
// Specifies whether binary files that are copied during the build, such as in a Copy Bundle Resources or Copy Files build phase, should be stripped of debugging symbols.
|
||||
COPY_PHASE_STRIP = NO
|
||||
|
||||
// The type of debug information to produce.
|
||||
DEBUG_INFORMATION_FORMAT = dwarf
|
||||
|
||||
// Controls whether assertion logic provided by `NSAssert` is included in the preprocessed source code or is elided during preprocessing.
|
||||
ENABLE_NS_ASSERTIONS = YES
|
||||
|
||||
// When this setting is activated, the product will be built with options appropriate for running automated tests, such as making private interfaces accessible to the tests.
|
||||
ENABLE_TESTABILITY = YES
|
||||
|
||||
// Specifies the degree to which the generated code is optimized for speed and binary size.
|
||||
GCC_OPTIMIZATION_LEVEL = 0
|
||||
|
||||
// Space-separated list of preprocessor macros of the form `foo` or `foo=bar`
|
||||
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) DEBUG=1
|
||||
|
||||
// Metal debug info - not sure why we need it
|
||||
MTL_ENABLE_DEBUG_INFO = YES
|
||||
|
||||
// If enabled, only the active architecture is built.
|
||||
ONLY_ACTIVE_ARCH = YES
|
||||
|
||||
// If enabled, perform validation checks on the product as part of the build process.
|
||||
VALIDATE_PRODUCT = NO
|
|
@ -0,0 +1,28 @@
|
|||
// Configuration settings file format documentation can be found at:
|
||||
// https://help.apple.com/xcode/#/dev745c5c974
|
||||
|
||||
#include "Module-Shared.xcconfig"
|
||||
|
||||
// Specifies whether binary files that are copied during the build, such as in a Copy Bundle Resources or Copy Files build phase, should be stripped of debugging symbols.
|
||||
COPY_PHASE_STRIP = YES
|
||||
|
||||
// The type of debug information to produce.
|
||||
DEBUG_INFORMATION_FORMAT = dwarf-with-dsym
|
||||
|
||||
// Controls whether assertion logic provided by `NSAssert` is included in the preprocessed source code or is elided during preprocessing.
|
||||
ENABLE_NS_ASSERTIONS = NO
|
||||
|
||||
// When this setting is activated, the product will be built with options appropriate for running automated tests, such as making private interfaces accessible to the tests.
|
||||
ENABLE_TESTABILITY = NO
|
||||
|
||||
// Specifies the degree to which the generated code is optimized for speed and binary size.
|
||||
GCC_OPTIMIZATION_LEVEL = s
|
||||
|
||||
// Metal debug info
|
||||
MTL_ENABLE_DEBUG_INFO = NO
|
||||
|
||||
// If enabled, only the active architecture is built.
|
||||
ONLY_ACTIVE_ARCH = NO
|
||||
|
||||
// If enabled, perform validation checks on the product as part of the build process.
|
||||
VALIDATE_PRODUCT = YES
|
|
@ -0,0 +1,228 @@
|
|||
// Configuration settings file format documentation can be found at:
|
||||
// https://help.apple.com/xcode/#/dev745c5c974
|
||||
|
||||
// This setting is deprecated as of Xcode 8.3 and may not be supported in future versions. It is recommended that you disable the setting. If enabled, both `#include <header.h>`-style and `#include "header.h"`-style directives search the paths in `USER_HEADER_SEARCH_PATHS` before `HEADER_SEARCH_PATHS`
|
||||
ALWAYS_SEARCH_USER_PATHS = NO
|
||||
|
||||
// Warn for missing nullability attributes
|
||||
CLANG_ANALYZER_NONNULL = YES
|
||||
|
||||
// Warn when a number object, such as an instance of `NSNumber`, `CFNumberRef`, `OSNumber`, or `OSBoolean` is compared or converted to a primitive value instead of another object.
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE
|
||||
|
||||
// Choose a standard or non-standard C++ language dialect.
|
||||
CLANG_CXX_LANGUAGE_STANDARD = gnu++0x
|
||||
|
||||
// Choose a version of the C++ standard library to use.
|
||||
CLANG_CXX_LIBRARY = libc++
|
||||
|
||||
// Enables the use of modules for system APIs. System headers are imported as semantic modules instead of raw headers.
|
||||
CLANG_ENABLE_MODULES = YES
|
||||
|
||||
// Compiles reference-counted Objective-C code (when garbage collection is not enabled) to use Automatic Reference Counting.
|
||||
CLANG_ENABLE_OBJC_ARC = YES
|
||||
|
||||
// Warn about block captures of implicitly autoreleasing parameters.
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES
|
||||
|
||||
// Warn about implicit conversions to boolean values that are suspicious. For example, writing `if (foo)` where `foo` is the name a function will trigger a warning.
|
||||
CLANG_WARN_BOOL_CONVERSION = YES
|
||||
|
||||
// Warn about suspicious uses of the comma operator.
|
||||
CLANG_WARN_COMMA = YES
|
||||
|
||||
// Warn about implicit conversions of constant values that cause the constant value to change, either through a loss of precision, or entirely in its meaning.
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES
|
||||
|
||||
// Warn if an Objective-C class either subclasses a deprecated class or overrides a method that has been marked deprecated or unavailable.
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES
|
||||
|
||||
// Warn about direct accesses to the Objective-C `isa` pointer instead of using a runtime API.
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR
|
||||
|
||||
// Warns about issues in documentation comments (`doxygen`-style) such as missing or incorrect documentation tags.
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES
|
||||
|
||||
// Warn about declaring the same method more than once within the same `@interface`.
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES
|
||||
|
||||
// Warn about loop bodies that are suspiciously empty.
|
||||
CLANG_WARN_EMPTY_BODY = YES
|
||||
|
||||
// Warn about implicit conversions between different kinds of enum values. For example, this can catch issues when using the wrong enum flag as an argument to a function or method.
|
||||
CLANG_WARN_ENUM_CONVERSION = YES
|
||||
|
||||
// Warn if all paths through a function call itself.
|
||||
CLANG_WARN_INFINITE_RECURSION = YES
|
||||
|
||||
// Warn about implicit conversions between pointers and integers. For example, this can catch issues when one incorrectly intermixes using `NSNumber*`'s and raw integers.
|
||||
CLANG_WARN_INT_CONVERSION = YES
|
||||
|
||||
// Warn about non-literal expressions that evaluate to zero being treated as a null pointer.
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES
|
||||
|
||||
// Warn about `@property` declarations that are implicitly atomic.
|
||||
CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = NO
|
||||
|
||||
// Warn about implicit retains of `self` within blocks, which can create a retain-cycle.
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES
|
||||
|
||||
// Warn about implicit conversions from Objective-C literals to values of incompatible type.
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES
|
||||
|
||||
// Warn about classes that unintentionally do not subclass a root class, such as `NSObject`.
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR
|
||||
|
||||
// Warn about ranged-based for loops.
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES
|
||||
|
||||
// Warn about non-prototype declarations.
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES
|
||||
|
||||
// Warn about suspicious uses of `std::move`.
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES
|
||||
|
||||
// Warn if an API that is newer than the deployment target is used without "if (@available(...))" guards.
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE
|
||||
|
||||
// Warns about potentially unreachable code.
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES
|
||||
|
||||
// The path to a file specifying code-signing entitlements.
|
||||
CODE_SIGN_ENTITLEMENTS =
|
||||
|
||||
// The name, also known as the *common name*, of a valid code-signing certificate in a keychain within your keychain path. A missing or invalid certificate will cause a build error.
|
||||
CODE_SIGN_IDENTITY =
|
||||
|
||||
// This setting defines the current version of the project. The value must be a integer or floating point number, such as `57` or `365.8`.
|
||||
CURRENT_PROJECT_VERSION = 1
|
||||
|
||||
// If enabled, the product will be treated as defining its own module. This enables automatic production of LLVM module map files when appropriate, and allows the product to be imported as a module.
|
||||
DEFINES_MODULE = YES
|
||||
|
||||
// Determines the compatibility version of the resulting library, bundle, or framework binary.
|
||||
DYLIB_COMPATIBILITY_VERSION = 1
|
||||
|
||||
// This setting defines the current version of any framework built by the project. As with `CURRENT_PROJECT_VERSION`, the value must be an integer or floating point number, such as `57` or `365.8`.
|
||||
DYLIB_CURRENT_VERSION = 1
|
||||
|
||||
// Sets the base value for the internal `install path` (`LC_ID_DYLIB`) in a dynamic library. This will be combined with the `EXECUTABLE_PATH` to form the full install path.
|
||||
DYLIB_INSTALL_NAME_BASE = @rpath
|
||||
|
||||
// Controls whether `objc_msgSend` calls must be cast to the appropriate function pointer type before being called.
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES
|
||||
|
||||
// This is a list of paths to folders containing frameworks to be searched by the compiler for both included or imported header files when compiling C, Objective-C, C++, or Objective-C++, and by the linker for frameworks used by the product. Paths are delimited by whitespace, so any paths with spaces in them must be properly quoted.
|
||||
FRAMEWORK_SEARCH_PATHS = $(inherited)
|
||||
|
||||
// Choose a standard or non-standard C language dialect.
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99
|
||||
|
||||
// Faster function calls for applications. Not appropriate for shared libraries, which need to be position-independent.
|
||||
GCC_DYNAMIC_NO_PIC = NO
|
||||
|
||||
// In C, allocate even uninitialized global variables in the data section of the object file, rather than generating them as common blocks.
|
||||
GCC_NO_COMMON_BLOCKS = YES
|
||||
|
||||
// When enabled, all symbols are declared `private extern` unless explicitly marked to be exported using `\_\_attribute\_\_((visibility("default")))` in code. If not enabled, all symbols are exported unless explicitly marked as `private extern`.
|
||||
GCC_SYMBOLS_PRIVATE_EXTERN = NO
|
||||
|
||||
// Enabling this option causes all warnings to be treated as errors.
|
||||
GCC_TREAT_WARNINGS_AS_ERRORS = NO
|
||||
|
||||
// Warn if a value is implicitly converted from a 64-bit type to a 32-bit type. This is a subset of the warnings provided by -Wconversion.
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES
|
||||
|
||||
// Warn if a structure's initializer has some fields missing.
|
||||
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES
|
||||
|
||||
// Warn when a source file does not end with a newline.
|
||||
GCC_WARN_ABOUT_MISSING_NEWLINE = YES
|
||||
|
||||
// Causes warnings to be emitted about missing prototypes.
|
||||
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES
|
||||
|
||||
// Causes warnings to be emitted when a function with a defined return type (not `void`) contains a return statement without a return-value. Also emits a warning when a function is defined without specifying a return type.
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR
|
||||
|
||||
// Warn if an aggregate or union initializer is not fully bracketed.
|
||||
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES
|
||||
|
||||
// Warn whenever a local variable shadows another local variable, parameter or global variable or whenever a builtin function is shadowed.
|
||||
GCC_WARN_SHADOW = YES
|
||||
|
||||
// Warn when a comparison between signed and unsigned values could produce an incorrect result when the signed value is converted to unsigned.
|
||||
GCC_WARN_SIGN_COMPARE = YES
|
||||
|
||||
// Warn if a `@selector(...)` expression referring to an undeclared selector is found. A selector is considered undeclared if no method with that name has been declared before the `@selector(...)` expression, either explicitly in an `@interface` or `@protocol` declaration, or implicitly in an `@implementation` section.
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES
|
||||
|
||||
// Warn if a variable might be clobbered by a `setjmp` call or if an automatic variable is used without prior initialization. The compiler may not detect all cases where an automatic variable is initialized or all usage patterns that may lead to use prior to initialization.
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE
|
||||
|
||||
// Warn whenever a static function is declared but not defined or a noninline static function is unused.
|
||||
GCC_WARN_UNUSED_FUNCTION = YES
|
||||
|
||||
// Warn whenever a label is declared but not used.
|
||||
GCC_WARN_UNUSED_LABEL = YES
|
||||
|
||||
// Warn whenever a function parameter is unused aside from its declaration.
|
||||
GCC_WARN_UNUSED_PARAMETER = NO
|
||||
|
||||
// Warn whenever a local variable or nonconstant static variable is unused aside from its declaration.
|
||||
GCC_WARN_UNUSED_VARIABLE = YES
|
||||
|
||||
// This is a list of paths to folders to be searched by the compiler for included or imported header files when compiling C, Objective-C, C++, or Objective-C++. Paths are delimited by whitespace, so any paths with spaces in them need to be properly quoted.
|
||||
HEADER_SEARCH_PATHS = $(inherited)
|
||||
|
||||
// Code will load on this and later versions of iOS. Framework APIs that are unavailable in earlier versions will be weak-linked; your code should check for null function pointers or specific system versions before calling newer APIs.
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0
|
||||
|
||||
// This is a list of paths to be added to the `runpath` search path list for the image being created. At runtime, `dyld` uses the `runpath` when searching for dylibs whose load path begins with `@rpath/`.
|
||||
LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/Frameworks @loader_path/Frameworks
|
||||
|
||||
// This is a list of paths to folders to be searched by the linker for libraries used by the product. Paths are delimited by whitespace, so any paths with spaces in them need to be properly quoted.
|
||||
LIBRARY_SEARCH_PATHS = $(inherited)
|
||||
|
||||
// Code will load on this and later versions of macOS. Framework APIs that are unavailable in earlier versions will be weak-linked; your code should check for null function pointers or specific system versions before calling newer APIs.
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.10
|
||||
|
||||
// Options defined in this setting are passed to invocations of the linker.
|
||||
OTHER_LDFLAGS = -ObjC
|
||||
|
||||
// A string that uniquely identifies the bundle. The string should be in reverse DNS format using only alphanumeric characters (`A-Z`, `a-z`, `0-9`), the dot (`.`), and the hyphen (`-`). This value is used as the `CFBundleIdentifier` in the `Info.plist` of the built bundle.
|
||||
PRODUCT_BUNDLE_IDENTIFIER_PREFIX = com.dailymotion
|
||||
PRODUCT_BUNDLE_IDENTIFIER = $(PRODUCT_BUNDLE_IDENTIFIER_PREFIX).${PRODUCT_NAME:rfc1034identifier}
|
||||
|
||||
// This is the basename of the product generated by the target.
|
||||
PRODUCT_NAME = $(TARGET_NAME)
|
||||
|
||||
// Must contain a profile name (or UUID). A missing or invalid profile will cause a build error. Use in conjunction with [DEVELOPMENT_TEAM] to fully specify provisioning profile.
|
||||
PROVISIONING_PROFILE_SPECIFIER =
|
||||
|
||||
// Activating this setting will cause Xcode to run the `Clang` static analysis tool on qualifying source files during every build.
|
||||
RUN_CLANG_STATIC_ANALYZER = YES
|
||||
|
||||
// The name or path of the base SDK being used during the build. The product will be built against the headers and libraries located inside the indicated SDK. This path will be prepended to all search paths, and will be passed through the environment to the compiler and linker. Additional SDKs can be specified in the `ADDITIONAL_SDKS` setting.
|
||||
SDKROOT = macosx
|
||||
|
||||
// If enabled, don't install built products even if deployment locations are active.
|
||||
SKIP_INSTALL = YES
|
||||
|
||||
// The list of supported platforms from which a base SDK can be used. This setting is used if the product can be built for multiple platforms using different SDKs.
|
||||
SUPPORTED_PLATFORMS = macosx iphoneos iphonesimulator watchsimulator watchos appletvsimulator appletvos
|
||||
|
||||
// The build system uses the selected device to set the correct value for the `UIDeviceFamily` key it adds to the target's `Info.plist` file. This also drives the --target-device flag to actool, which determines the idioms selected during catalog compilation for iOS platforms.
|
||||
TARGETED_DEVICE_FAMILY = 1,2,3,4
|
||||
|
||||
// Code will load on this and later versions of tvOS. Framework APIs that are unavailable in earlier versions will be weak-linked; your code should check for null function pointers or specific system versions before calling newer APIs.
|
||||
TVOS_DEPLOYMENT_TARGET = 9.0
|
||||
|
||||
// Selects the process used for version-stamping generated files. * *None:* Use no versioning system. * *Apple Generic:* Use the current project version setting. [apple-generic]
|
||||
VERSIONING_SYSTEM = apple-generic
|
||||
|
||||
// Code will load on this and later versions of watchOS. Framework APIs that are unavailable in earlier versions will be weak-linked; your code should check for null function pointers or specific system versions before calling newer APIs.
|
||||
WATCHOS_DEPLOYMENT_TARGET = 2.0
|
||||
|
||||
// Implicitly include the named header. The path given should either be a project relative path or an absolute path.
|
||||
GCC_PREFIX_HEADER = WebImage/SDWebImage-Prefix.pch
|
|
@ -0,0 +1,8 @@
|
|||
// Configuration settings file format documentation can be found at:
|
||||
// https://help.apple.com/xcode/#/dev745c5c974
|
||||
|
||||
#include "Module-Debug.xcconfig"
|
||||
#include "Test-Shared.xcconfig"
|
||||
|
||||
// If enabled, only the active architecture is built.
|
||||
ONLY_ACTIVE_ARCH = YES
|
|
@ -0,0 +1,11 @@
|
|||
// Configuration settings file format documentation can be found at:
|
||||
// https://help.apple.com/xcode/#/dev745c5c974
|
||||
|
||||
#include "Module-Release.xcconfig"
|
||||
#include "Test-Shared.xcconfig"
|
||||
|
||||
// If enabled, only the active architecture is built.
|
||||
ONLY_ACTIVE_ARCH = NO
|
||||
|
||||
// Space-separated list of additional flags to pass to the compiler for C and Objective-C files. Be sure to backslash-escape any arguments that contain spaces or special characters, such as path names that may contain spaces. Use this setting if Xcode does not already provide UI for a particular C or Objective-C compiler flag.
|
||||
OTHER_CFLAGS = -DNS_BLOCK_ASSERTIONS=1
|
|
@ -0,0 +1,7 @@
|
|||
// Configuration settings file format documentation can be found at:
|
||||
// https://help.apple.com/xcode/#/dev745c5c974
|
||||
|
||||
#include "Module-Shared.xcconfig"
|
||||
|
||||
// Implicitly include the named header. The path given should either be a project relative path or an absolute path.
|
||||
GCC_PREFIX_HEADER =
|
|
@ -0,0 +1,103 @@
|
|||
body {
|
||||
font: 12px 'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif;
|
||||
margin: 0;
|
||||
padding: 0 2em 2em 2em;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin-top: 30px;
|
||||
margin-bottom: 30px;
|
||||
font-size: 28px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.headerFile {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.headerName {
|
||||
margin: 15px 0px 10px -20px;
|
||||
padding: 4px 4px 4px 20px;
|
||||
font-weight: bold;
|
||||
font-size: 120%;
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
|
||||
.differenceGroup {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.difference {
|
||||
padding-left: 20px;
|
||||
font-family: Courier, Consolas, monospace;
|
||||
font-size: 110%;
|
||||
}
|
||||
|
||||
.status {
|
||||
font-style: italic;
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
.removed {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.added {
|
||||
color: blue;
|
||||
}
|
||||
|
||||
.modified {
|
||||
color: #080;
|
||||
}
|
||||
|
||||
.declaration {
|
||||
font-family: Courier, Consolas, monospace;
|
||||
}
|
||||
|
||||
table {
|
||||
border: 1px #888 solid;
|
||||
padding: 2px;
|
||||
border-spacing: 0px;
|
||||
border-collapse: collapse;
|
||||
margin-left: 40px;
|
||||
margin-top: 7px;
|
||||
}
|
||||
|
||||
td, th {
|
||||
font-size: 10px;
|
||||
border: 1px #888 solid;
|
||||
padding:3px 6px;
|
||||
}
|
||||
|
||||
th {
|
||||
font-size: 10px;
|
||||
text-align: center;
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
td {
|
||||
font-size: 90%;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: disc outside;
|
||||
margin: 0 0 0 16px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
li {
|
||||
margin-top: 7px;
|
||||
}
|
||||
|
||||
.message {
|
||||
margin-left: 20px;
|
||||
font-style: italic;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
a:link { color: #18396E; text-decoration: none; }
|
||||
a:active { color: #18396E; text-decoration: none; }
|
||||
a:visited { color: #003366; text-decoration: none; }
|
||||
a:link:hover { color: #18396E; text-decoration: underline; }
|
||||
a:visited:hover { color: #003366; text-decoration: underline; }
|
After Width: | Height: | Size: 191 KiB |
After Width: | Height: | Size: 320 KiB |
After Width: | Height: | Size: 139 KiB |
After Width: | Height: | Size: 204 KiB |
After Width: | Height: | Size: 165 KiB |
After Width: | Height: | Size: 279 KiB |
After Width: | Height: | Size: 55 KiB |
After Width: | Height: | Size: 148 KiB |
|
@ -0,0 +1,275 @@
|
|||
## SDWebImage 5.0 Migration Guide
|
||||
|
||||
SDWebImage 5.0 is the latest major release of SDWebImage, a top library for downloading and caching images.
|
||||
As a major release, following [Semantic Versioning](http://semver.org/) conventions, 5.0 introduces several API-breaking changes with its new architecture.
|
||||
|
||||
This guide is provided in order to ease the transition of existing applications using SDWebImage 4.X to the latest APIs, as well as explain the design and structure of new and changed functionality.
|
||||
|
||||
### Requirements: iOS 8, Mac OS X 10.10, watchOS 2, tvOS 9, Xcode 9
|
||||
|
||||
SDWebImage 5.0 officially supports iOS 8 and later, Mac OS X 10.10 and later, watchOS 2 and later and tvOS 9 and later.
|
||||
It needs Xcode 9 or later to be able to build everything properly.
|
||||
|
||||
For targeting previous versions of the SDKs, check [README - Backwards compatibility](https://github.com/rs/SDWebImage#backwards-compatibility).
|
||||
|
||||
### Migration
|
||||
|
||||
Using the view categories brings no change from 4.x to 5.0.
|
||||
|
||||
Objective-C:
|
||||
|
||||
```objective-c
|
||||
[imageView sd_setImageWithURL:url placeholderImage:placeholderImage];
|
||||
```
|
||||
|
||||
Swift:
|
||||
|
||||
```swift
|
||||
imageView.sd_setImage(with: url, placeholderImage: placeholder)
|
||||
```
|
||||
|
||||
However, all view categories in 5.0 introduce a new extra arg called `SDWebImageContext`. This param can hold anything, as oposed to the previous `SDWebImageOptions` enum limitations. This gives developers advanced control for the behavior of image loading (cache, loader, etc). See the declaration for `SDWebImageContext` for detailed information.
|
||||
|
||||
### New Feature
|
||||
|
||||
#### Animated Image View
|
||||
|
||||
In 5.0, we introduced a brand new mechanism for supporting animated images. This includes animated image loading, rendering, decoding, and also supports customizations (for advanced users).
|
||||
|
||||
This animated image solution is available for `iOS`/`tvOS`/`macOS`. The `SDAnimatedImage` is subclass of `UIImage/NSImage`, and `SDAnimatedImageView` is subclass of `UIImageView/NSImageView`, to make them compatible with the common frameworks APIs. See [Animated Image](https://github.com/rs/SDWebImage/wiki/Advanced-Usage#animated-image-50) for more detailed information.
|
||||
|
||||
#### Image Transformer
|
||||
|
||||
In 5.0, we introduced an easy way to hook an image transformation process after the image was downloaded from network. This allows the user to easily scale, rotate, add rounded corner the original image and even chain a list of transformations. These transformed images will also be stored to the cache as they are after transformation. The reasons for this decision are: avoiding redoing the transformations (which can lead to unwanted behavior) and also time saving. See [Image Transformer](https://github.com/rs/SDWebImage/wiki/Advanced-Usage#image-transformer-50) for more detailed information.
|
||||
|
||||
#### Customization
|
||||
|
||||
In 5.0, we refactored our framework architecture in many aspects. This makes our framework easier to customize for advanced users, without the need for hooking anything or forking. We introduced [Custom Cache](https://github.com/rs/SDWebImage/wiki/Advanced-Usage#custom-cache-50) to control detailed cache loading behavior, and separate the memory cache & disk cache implementation. We introduced [Custom Loader](https://github.com/rs/SDWebImage/wiki/Advanced-Usage#custom-loader-50) to allow custom loading from your own source (doesn't have to be the network). And also, we changed the current [Custom Coder](https://github.com/rs/SDWebImage/wiki/Advanced-Usage#custom-coder-420) to work better for custom image decoder/encoder and animated images.
|
||||
|
||||
#### View Indicator
|
||||
In 5.0, we refactored the image loading indicator API into a better and extensible API for `iOS`/`tvOS`/`macOS`. This is suitable for easy usage like providing a loading view during the image loading process. See [View Indicator](https://github.com/rs/SDWebImage/wiki/How-to-use#use-view-indicator-50) for more detailed information.
|
||||
|
||||
#### FLAnimatedImage support moved to a dedicated plugin repo
|
||||
|
||||
In order to clean up things and make our core project do less things, we decided that the `FLAnimatedImage` integration does not belong here. From 5.0, this will still be available, but under a dedicated repo [SDWebImageFLPlugin](https://github.com/SDWebImage/SDWebImageFLPlugin).
|
||||
|
||||
#### Photos Plugin
|
||||
|
||||
By taking the advantage of the [Custom Loader](https://github.com/rs/SDWebImage/wiki/Advanced-Usage#custom-loader-50) feature, we introduced a plugin to allow easy loading images from the Photos Library. See [SDWebImagePhotosPlugin](https://github.com/SDWebImage/SDWebImagePhotosPlugin) for more detailed information.
|
||||
|
||||
|
||||
### Notable Behavior Changes (without API breaking)
|
||||
|
||||
#### Cache
|
||||
|
||||
##### Cache Paths
|
||||
|
||||
`SDImageCache` in 5.x, use `~/Library/Caches/com.hackemist.SDImageCache/default/` as default cache path. However, 4.x use `~/Library/Caches/default/com.hackemist.SDWebImageCache.default/`. And don't be worried, we will do the migration automatically once the shared cache initialized.
|
||||
|
||||
However, if you have some other custom namespace cache instance, you should try to do migration by yourself. But typically, since the cache is designed to be invalid at any time, you'd better not to bind some important logic related on that cache path changes.
|
||||
|
||||
And, if you're previously using any version from `5.0.0-beta` to `5.0.0-beta3`, please note that the cache folder has been temporarily moved to `~/Library/Caches/default/com.hackemist.SDImageCache.default/`, however, the final release version of 5.0.0 use the path above. If you upgrade from those beta version, you may need manually do migration, check `+[SDDiskCache moveCacheDirectoryFromPath:toPath:]` for detail information.
|
||||
|
||||
##### Cache Cost Function
|
||||
|
||||
`SDImageCacheConfig.maxMemoryCost` can be used to specify the memory cost limit. In the 4.x, the cost function is the **pixel count** of images. However, 5.x change it into the total **bytes size** of images.
|
||||
|
||||
Because for memory cache, we actually care about the memory usage about bytes, but not the count of pixels. And pixel count can not accurately represent the memory usage.
|
||||
|
||||
The bytes of a image occupied in the memory, can use the simple formula below:
|
||||
|
||||
**bytes size** = **pixel count** \* **bytes per pixel**
|
||||
|
||||
The **bytes per pixel** is a constant depends on [image pixel format](https://developer.apple.com/library/archive/documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_images/dq_images.html). For mostly used images (8 bits per channel with alpha), the value is 4. So you can simply migrate your previous pixel count value with 4 multiplied.
|
||||
|
||||
|
||||
#### Prefetcher
|
||||
|
||||
`SDWebImagePrefetcher` in 5.x, change the concept of fetching batch of URLs. Now, each time you call `prefetchURLs:`, you will get a token which represents the specified URLs list. It does not cancel the previous URLs which is prefetching, which make the shared prefetcher behaves more intuitively.
|
||||
|
||||
However, in 4.x, each time you call `prefetchURLs:`, it will cancel all previous URLs which is been prefetching.
|
||||
|
||||
If you still want the same behavior, manually call `cancelPrefetching` each time before any `prefetchURLs:` calls.
|
||||
|
||||
|
||||
+ Objective-C
|
||||
|
||||
```objective-c
|
||||
SDWebImagePrefetcher *prefetcher = SDWebImagePrefetcher.sharedImagePrefetcher;
|
||||
[prefetcher cancelPrefetching];
|
||||
[prefetcher prefetchURLs:@[url1, url2]];
|
||||
```
|
||||
|
||||
+ Swift
|
||||
|
||||
```swift
|
||||
let prefetcher = SDWebImagePrefetcher.shared
|
||||
prefetcher.cancelPrefetching()
|
||||
prefetcher.prefetchURLs([url1, url2])
|
||||
```
|
||||
|
||||
### API Changes
|
||||
|
||||
#### SDImageCache
|
||||
|
||||
- moved `maxMemoryCost` and `maxMemoryCountLimit` to `SDImageCacheConfig`
|
||||
- `makeDiskCachePath:` removed, use `NSSearchPathForDirectoriesInDomains` with NSString's Path API instead.
|
||||
- `addReadOnlyCachePath:` removed, use `additionalCachePathBlock` instead
|
||||
- `cachePathForKey:inPath:` removed, use `cachePathForKey:` with NSString's path API instead.
|
||||
- `defaultCachePathForKey:` removed, use `cachePathForKey:` instead
|
||||
- `SDCacheQueryCompletedBlock` renamed to `SDImageCacheQueryCompletionBlock`
|
||||
- `SDWebImageCheckCacheCompletionBlock` renamed to `SDImageCacheCheckCompletionBlock`
|
||||
- `SDWebImageCalculateSizeBlock` renamed to `SDImageCacheCalculateSizeBlock`
|
||||
- `getSize` renamed to `totalDiskSize`
|
||||
- `getDiskCount` renamed to `totalDiskCount`
|
||||
|
||||
#### SDImageCacheConfig
|
||||
|
||||
- `shouldDecompressImages` removed. Use `SDImageCacheAvoidDecodeImage` in cache options instead
|
||||
- `maxCacheAge` renamed to `maxDiskAge`
|
||||
- `maxCacheSize` renamed to `maxDiskSize`
|
||||
|
||||
#### SDWebImageManager
|
||||
|
||||
- `loadImageWithURL:options:progress:completed:` changed the `completed` param requirement from `nullable` to `nonnull`
|
||||
- `loadImageWithURL:options:progress:completed:` return type `id<SDWebImageOperation>` changed to `SDWebImageCombinedOperation *`
|
||||
- `imageCache` changed from nullable to nonnull. And property type changed from `SDImageCache *` to `id<SDImageCache>`. The default value does not change.
|
||||
- `imageDownloader` renamed to `imageLoader` and changed from nullable to nonnull. And property type changed from `SDWebImageDownloader *` to `id<SDImageLoader>`. The default value does not change.
|
||||
- `cacheKeyFilter` property type changed to `id<SDWebImageCacheKeyFilter>`, you can use `+[SDWebImageCacheKeyFilter cacheKeyFilterWithBlock:]` to create
|
||||
- `cacheSerializer` property type changed to `id<SDWebImageCacheSerializer>`, you can use `+[SDWebImageCacheSerializer cacheSerializerWithBlock:]` to create
|
||||
- `SDWebImageCacheKeyFilterBlock`'s `url` arg change from nullable to nonnull
|
||||
- `initWithCache:downloader:` 's `cache` arg type changed from `SDImageCache *` to `id<SDImageCache>`
|
||||
- `initWithCache:downloader` renamed to `initWithCache:loader:`
|
||||
- `saveImageToCache:forURL:` removed. Use `SDImageCache storeImage:imageData:forKey:cacheType:completion:` (or `SDImageCache storeImage:forKey:toDisk:completion:` if you use default cache class) with `cacheKeyForURL:` instead.
|
||||
- `diskImageExistsForURL:completion:` removed. Use `SDImageCache containsImageForKey:cacheType:completion:` (or `SDImageCache diskImageExistsWithKey:completion:` if you use default cache class) with `cacheKeyForURL:` instead.
|
||||
- `cachedImageExistsForURL:completion` removed. Use `SDImageCache containsImageForKey:cacheType:completion:` (or `SDImageCache diskImageExistsWithKey:completion:` and `SDImageCache imageFromMemoryCacheForKey:` if you use default cache class) with `cacheKeyForURL:` instead.
|
||||
|
||||
#### SDWebImageManagerDelegate
|
||||
|
||||
- removed `imageManager:transformDownloadedImage:forKey:`, use `SDImageTransformer` with context option instead
|
||||
|
||||
#### UIView and subclasses (UIImageView, UIButton, ...)
|
||||
|
||||
- `sd_internalSetImageWithURL:placeholderImage:options:operationKey:setImageBlock:progress:completed:` renamed to `UIView sd_internalSetImageWithURL:placeholderImage:options:context:setImageBlock:progress:completed:` (The biggest changes is that the completion block type from `SDExternalCompletionBlock` to `SDInternalCompletionBlock`. Which allow advanced user to get more information of image loading process)
|
||||
- `sd_internalSetImageWithURL:placeholderImage:options:operationKey:setImageBlock:progress:completed:context:` removed
|
||||
- activity indicator refactoring - use `sd_imageIndicator` with `SDWebImageActivityIndicator`
|
||||
- `sd_setShowActivityIndicatorView:` removed
|
||||
- `sd_setIndicatorStyle:` removed
|
||||
- `sd_showActivityIndicatorView` removed
|
||||
- `sd_addActivityIndicator:` removed
|
||||
- `sd_removeActivityIndicator:` removed
|
||||
|
||||
#### UIImage
|
||||
|
||||
- Renamed `isGIF` to `sd_isAnimated`, also `NSImage isGIF` renamed to `NSImage sd_isAnimated`
|
||||
- Renamed `decodedImageWithImage:` to `sd_decodedImageWithImage:`
|
||||
- Renamed `decodedAndScaledDownImageWithImage:` to `sd_decodedAndScaledDownImageWithImage:`
|
||||
- Renamed `sd_animatedGIFWithData` to `sd_imageWithGIFData:`
|
||||
- Removed `sd_webpLoopCount`
|
||||
|
||||
#### UIImageView
|
||||
|
||||
- Removed `sd_setImageWithPreviousCachedImageWithURL:placeholderImage:options:progress:completed`
|
||||
|
||||
#### SDWebImageDownloader
|
||||
|
||||
- `shouldDecompressImages` moved to `SDWebImageDownloaderConfig.shouldDecompressImages`
|
||||
- `maxConcurrentDownloads` moved to `SDWebImageDownloaderConfig.maxConcurrentDownloads`
|
||||
- `downloadTimeout` moved to `SDWebImageDownloaderConfig.downloadTimeout`
|
||||
- `operationClass` moved to `SDWebImageDownloaderConfig.operationClass`
|
||||
- `executionOrder` moved to `SDWebImageDownloaderConfig.executionOrder`
|
||||
- `urlCredential` moved to `SDWebImageDownloaderConfig.urlCredential`
|
||||
- `username` moved to `SDWebImageDownloaderConfig.username`
|
||||
- `password` moved to `SDWebImageDownloaderConfig.password`
|
||||
- `initWithSessionConfiguration:` removed, use `initWithConfig:` with session configuration instead
|
||||
- `createNewSessionWithConfiguration:` removed, use `initWithConfig:` with new session configuration instead. To modify shared downloader configuration, provide custom `SDWebImageDownloaderConfig.defaultDownloaderConfig` before it created.
|
||||
- `headersFilter` removed, use `requestModifier` instead
|
||||
- `cancel:` removed, use `-[SDWebImageDownloadToken cancel]` instead
|
||||
- `shouldDecompressImages` removed. Use `SDWebImageDownloaderAvoidDecodeImage` in downloader options instead
|
||||
- use `SDImageLoaderProgressBlock` instead of `SDWebImageDownloaderProgressBlock`
|
||||
- use `SDImageLoaderCompletedBlock` instead of `SDWebImageDownloaderCompletedBlock`
|
||||
|
||||
#### SDWebImageDownloaderOperation
|
||||
|
||||
- `initWithRequest:inSession:options:context:` is now the designated initializer
|
||||
- Removed `shouldUseCredentialStorage` property
|
||||
- `SDWebImageDownloadOperationInterface` protocol renamed to `SDWebImageDownloadOperation`
|
||||
- `expectedSize` removed, use `response.expectedContentLength` instead
|
||||
- `shouldDecompressImages` removed. Use `SDWebImageDownloaderAvoidDecodeImage` in downloader options instead.
|
||||
- `response` property change to readonly
|
||||
|
||||
#### SDWebImagePrefetcher
|
||||
|
||||
- `prefetchURLs:` and `prefetchURLs:progress:completed:` return types changed from `void` to `SDWebImagePrefetchToken`
|
||||
- `prefetcherQueue` property renamed to `delegateQueue`
|
||||
- `maxConcurrentDownloads` replaced with `maxConcurrentPrefetchCount`
|
||||
|
||||
#### SDImageCoder
|
||||
- `SDCGColorSpaceGetDeviceRGB()` moved to `+[SDImageCoderHelper colorSpaceGetDeviceRGB]`
|
||||
- `SDCGImageRefContainsAlpha()`, moved to `+[SDImageCoderHelper imageRefContainsAlpha:]`
|
||||
- `decodedImageWithData:` replaced with `decodedImageWithData:options:`
|
||||
- `encodedDataWithImage:format:` replaced with `encodedDataWithImage:format:options`
|
||||
- `init` method from `SDWebImageProgressiveCoder` changed to `initIncrementalWithOptions:`
|
||||
- `incrementalDecodedImageWithData:finished` replaced with `updateIncrementalData:finished` and `incrementalDecodedImageWithOptions:` two APIs
|
||||
- removed `decompressedImage:data:options`, use `+[SDImageCoderHelper decodedImageWithImage:]` and `+[SDImageCoderHelper decodedAndScaledDownImageWithImage:limitBytes:]` instead
|
||||
|
||||
#### Constants
|
||||
|
||||
- `SDWebImageInternalSetImageGroupKey` renamed to `SDWebImageContextSetImageGroup`
|
||||
- `SDWebImageExternalCustomManagerKey` renamed to `SDWebImageContextCustomManager`
|
||||
|
||||
#### Swift Specific API Change
|
||||
In SDWebImage 5.0 we did a clean up of the API. We are using many modern Objective-C declarations to generate the Swift API. We now provide full nullability support, string enum, class property, and even custom Swift API name, all to make the framework easier to use for our Swift users. Here are the API change specify for Swift.
|
||||
|
||||
##### UIView+WebCache
|
||||
- `sd_imageURL()` changed to `sd_imageURL`
|
||||
|
||||
##### SDImageCache
|
||||
- `shared()` changed to `shared`
|
||||
|
||||
##### SDWebImageManager
|
||||
- `shared()` changed to `shared`
|
||||
- `isRunning()` changed to `isRunning`
|
||||
|
||||
##### SDWebImageDownloader
|
||||
- `shared()` changed to `shared`
|
||||
- `setOperationClass(_:)` available for Swift user with `operationClass` property
|
||||
- `setSuspended(_:)` changed to `isSuspended` property
|
||||
|
||||
##### SDWebImageDownloadOperation
|
||||
- `SDWebImageDownloadOperationInterface` protocol renamed to `SDWebImageDownloadOperationProtocol`.
|
||||
|
||||
##### SDImageCodersManager
|
||||
|
||||
- `sharedInstance()` changed to `shared`
|
||||
|
||||
##### SDImageIOCoder
|
||||
|
||||
- `shared()` changed to `shared`
|
||||
|
||||
##### SDImageGIFCoder
|
||||
|
||||
- `shared()` changed to `shared`
|
||||
|
||||
##### SDImageWebPCoder
|
||||
|
||||
- `shared()` changed to `shared`
|
||||
|
||||
##### NSData-ImageContentType
|
||||
|
||||
- `sd_UTTypeFromSDImageFormat` return `CFString` instead of `Unmanaged<CFString>`
|
||||
|
||||
##### UIButton-WebCache
|
||||
|
||||
- `sd_currentImageURL()` changed to `sd_currentImageURL`
|
||||
|
||||
##### NSButton-WebCache
|
||||
|
||||
- `sd_currentImageURL()` changed to `sd_currentImageURL`
|
||||
- `sd_currentAlternateImageURL()` changed to `sd_currentAlternateImageURL`
|
||||
|
||||
### Full API Diff
|
||||
For advanced user who need the detailed API diff, we provide the full diff in a HTML web page (Currently based on 4.4.4 and 5.0.0-beta4):
|
||||
|
||||
[SDWebImage 5.0 API Diff](https://htmlpreview.github.io/?https://github.com/rs/SDWebImage/blob/master/Docs/API-Diff/5.0/apidiff.html).
|
||||
|
22762
Docs/SDWebImage.mdj
Before Width: | Height: | Size: 337 KiB |
Before Width: | Height: | Size: 129 KiB |
|
@ -0,0 +1,25 @@
|
|||
source 'https://github.com/CocoaPods/Specs.git'
|
||||
|
||||
use_frameworks!
|
||||
|
||||
project 'SDWebImage Demo'
|
||||
workspace '../SDWebImage'
|
||||
|
||||
pod 'SDWebImage/Core', :path => '../'
|
||||
pod 'SDWebImageWebPCoder', :git => 'https://github.com/SDWebImage/SDWebImageWebPCoder.git', :branch => 'master'
|
||||
|
||||
target 'SDWebImage iOS Demo' do
|
||||
platform :ios, '8.0'
|
||||
end
|
||||
|
||||
target 'SDWebImage OSX Demo' do
|
||||
platform :osx, '10.10'
|
||||
end
|
||||
|
||||
target 'SDWebImage TV Demo' do
|
||||
platform :tvos, '9.2'
|
||||
end
|
||||
|
||||
target 'SDWebImage Watch Demo Extension' do
|
||||
platform :watchos, '2.0'
|
||||
end
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0920"
|
||||
LastUpgradeVersion = "1000"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
@ -26,7 +26,6 @@
|
|||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
|
@ -46,7 +45,6 @@
|
|||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0920"
|
||||
LastUpgradeVersion = "1000"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
@ -26,7 +26,6 @@
|
|||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
|
@ -46,7 +45,6 @@
|
|||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0920"
|
||||
LastUpgradeVersion = "1000"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
@ -54,7 +54,6 @@
|
|||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
|
@ -74,7 +73,6 @@
|
|||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0920"
|
||||
LastUpgradeVersion = "1000"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
@ -17,7 +17,7 @@
|
|||
BlueprintIdentifier = "53761294155AB74D005750A4"
|
||||
BuildableName = "SDWebImage iOS Demo.app"
|
||||
BlueprintName = "SDWebImage iOS Demo"
|
||||
ReferencedContainer = "container:Examples/SDWebImage Demo.xcodeproj">
|
||||
ReferencedContainer = "container:SDWebImage Demo.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
|
@ -26,7 +26,6 @@
|
|||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
|
@ -36,7 +35,7 @@
|
|||
BlueprintIdentifier = "53761294155AB74D005750A4"
|
||||
BuildableName = "SDWebImage iOS Demo.app"
|
||||
BlueprintName = "SDWebImage iOS Demo"
|
||||
ReferencedContainer = "container:Examples/SDWebImage Demo.xcodeproj">
|
||||
ReferencedContainer = "container:SDWebImage Demo.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
|
@ -46,7 +45,6 @@
|
|||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
|
@ -60,7 +58,7 @@
|
|||
BlueprintIdentifier = "53761294155AB74D005750A4"
|
||||
BuildableName = "SDWebImage iOS Demo.app"
|
||||
BlueprintName = "SDWebImage iOS Demo"
|
||||
ReferencedContainer = "container:Examples/SDWebImage Demo.xcodeproj">
|
||||
ReferencedContainer = "container:SDWebImage Demo.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<EnvironmentVariables>
|
||||
|
@ -86,7 +84,7 @@
|
|||
BlueprintIdentifier = "53761294155AB74D005750A4"
|
||||
BuildableName = "SDWebImage iOS Demo.app"
|
||||
BlueprintName = "SDWebImage iOS Demo"
|
||||
ReferencedContainer = "container:Examples/SDWebImage Demo.xcodeproj">
|
||||
ReferencedContainer = "container:SDWebImage Demo.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
|
@ -7,10 +7,9 @@
|
|||
*/
|
||||
|
||||
#import "AppDelegate.h"
|
||||
|
||||
#import "MasterViewController.h"
|
||||
|
||||
#import <SDWebImage/SDImageCache.h>
|
||||
#import <SDWebImage/SDWebImage.h>
|
||||
|
||||
@implementation AppDelegate
|
||||
|
||||
|
@ -21,7 +20,10 @@
|
|||
{
|
||||
//Add a custom read-only cache path
|
||||
NSString *bundledPath = [[NSBundle mainBundle].resourcePath stringByAppendingPathComponent:@"CustomPathImages"];
|
||||
[[SDImageCache sharedImageCache] addReadOnlyCachePath:bundledPath];
|
||||
[SDImageCache sharedImageCache].additionalCachePathBlock = ^NSString * _Nullable(NSString * _Nonnull key) {
|
||||
NSString *fileName = [[SDImageCache sharedImageCache] cachePathForKey:key].lastPathComponent;
|
||||
return [bundledPath stringByAppendingPathComponent:fileName.stringByDeletingPathExtension];
|
||||
};
|
||||
|
||||
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
|
||||
// Override point for customization after application launch.
|
||||
|
|
|
@ -7,81 +7,28 @@
|
|||
*/
|
||||
|
||||
#import "DetailViewController.h"
|
||||
#import <SDWebImage/FLAnimatedImageView.h>
|
||||
#import <SDWebImage/FLAnimatedImageView+WebCache.h>
|
||||
#import <SDWebImage/SDWebImage.h>
|
||||
|
||||
@interface DetailViewController ()
|
||||
|
||||
@property (strong, nonatomic) IBOutlet FLAnimatedImageView *imageView;
|
||||
@property (strong, nonatomic) UIActivityIndicatorView *activityIndicator;
|
||||
@property (strong, nonatomic) UIProgressView *progressView;
|
||||
@property (strong, nonatomic) IBOutlet SDAnimatedImageView *imageView;
|
||||
|
||||
@end
|
||||
|
||||
@implementation DetailViewController
|
||||
|
||||
- (UIActivityIndicatorView *)activityIndicator
|
||||
{
|
||||
if (!_activityIndicator) {
|
||||
_activityIndicator = [UIActivityIndicatorView.alloc initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
|
||||
_activityIndicator.center = self.imageView.center;
|
||||
_activityIndicator.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
|
||||
[self.imageView addSubview:_activityIndicator];
|
||||
|
||||
- (void)configureView {
|
||||
if (!self.imageView.sd_imageIndicator) {
|
||||
self.imageView.sd_imageIndicator = SDWebImageProgressIndicator.defaultIndicator;
|
||||
}
|
||||
return _activityIndicator;
|
||||
}
|
||||
|
||||
- (UIProgressView *)progressView
|
||||
{
|
||||
if (!_progressView) {
|
||||
_progressView = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault];
|
||||
[self.view addSubview:_progressView];
|
||||
}
|
||||
return _progressView;
|
||||
}
|
||||
|
||||
- (void)configureView
|
||||
{
|
||||
self.activityIndicator.hidden = NO;
|
||||
[self.activityIndicator startAnimating];
|
||||
|
||||
__weak typeof(self) weakSelf = self;
|
||||
[self.imageView sd_setImageWithURL:self.imageURL
|
||||
placeholderImage:nil
|
||||
options:SDWebImageProgressiveDownload
|
||||
progress:^(NSInteger receivedSize, NSInteger expectedSize, NSURL *targetURL) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
float progress = 0;
|
||||
if (expectedSize != 0) {
|
||||
progress = (float)receivedSize / (float)expectedSize;
|
||||
}
|
||||
weakSelf.progressView.hidden = NO;
|
||||
[weakSelf.progressView setProgress:progress animated:YES];
|
||||
});
|
||||
}
|
||||
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
|
||||
weakSelf.progressView.hidden = YES;
|
||||
[weakSelf.activityIndicator stopAnimating];
|
||||
weakSelf.activityIndicator.hidden = YES;
|
||||
}];
|
||||
options:SDWebImageProgressiveLoad];
|
||||
}
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
[self configureView];
|
||||
}
|
||||
|
||||
- (void)viewDidLayoutSubviews
|
||||
{
|
||||
[super viewDidLayoutSubviews];
|
||||
self.progressView.frame = CGRectMake(0, self.topLayoutGuide.length, CGRectGetWidth(self.view.bounds), 2.0);
|
||||
}
|
||||
|
||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
|
||||
{
|
||||
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="16C67" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" initialViewController="01J-lp-oVM">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14113" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
||||
<device id="retina4_7" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
|
@ -14,9 +18,9 @@
|
|||
<viewControllerLayoutGuide type="bottom" id="xb3-aO-Qok"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
|
|
|
@ -8,13 +8,13 @@
|
|||
|
||||
#import "MasterViewController.h"
|
||||
#import "DetailViewController.h"
|
||||
#import <SDWebImage/FLAnimatedImageView+WebCache.h>
|
||||
#import <SDWebImage/UIView+WebCache.h>
|
||||
#import <SDWebImage/SDWebImage.h>
|
||||
#import <SDWebImageWebPCoder/SDImageWebPCoder.h>
|
||||
|
||||
@interface MyCustomTableViewCell : UITableViewCell
|
||||
|
||||
@property (nonatomic, strong) UILabel *customTextLabel;
|
||||
@property (nonatomic, strong) FLAnimatedImageView *customImageView;
|
||||
@property (nonatomic, strong) SDAnimatedImageView *customImageView;
|
||||
|
||||
@end
|
||||
|
||||
|
@ -22,7 +22,7 @@
|
|||
|
||||
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
|
||||
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
|
||||
_customImageView = [[FLAnimatedImageView alloc] initWithFrame:CGRectMake(20.0, 2.0, 60.0, 40.0)];
|
||||
_customImageView = [[SDAnimatedImageView alloc] initWithFrame:CGRectMake(20.0, 2.0, 60.0, 40.0)];
|
||||
[self.contentView addSubview:_customImageView];
|
||||
_customTextLabel = [[UILabel alloc] initWithFrame:CGRectMake(100.0, 12.0, 200, 20.0)];
|
||||
[self.contentView addSubview:_customTextLabel];
|
||||
|
@ -43,26 +43,29 @@
|
|||
|
||||
@implementation MasterViewController
|
||||
|
||||
- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
|
||||
{
|
||||
- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
|
||||
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
|
||||
if (self)
|
||||
{
|
||||
if (self) {
|
||||
self.title = @"SDWebImage";
|
||||
self.navigationItem.rightBarButtonItem = [UIBarButtonItem.alloc initWithTitle:@"Clear Cache"
|
||||
style:UIBarButtonItemStylePlain
|
||||
target:self
|
||||
action:@selector(flushCache)];
|
||||
|
||||
[[SDImageCodersManager sharedManager] addCoder:[SDImageWebPCoder sharedCoder]];
|
||||
|
||||
// HTTP NTLM auth example
|
||||
// Add your NTLM image url to the array below and replace the credentials
|
||||
[SDWebImageManager sharedManager].imageDownloader.username = @"httpwatch";
|
||||
[SDWebImageManager sharedManager].imageDownloader.password = @"httpwatch01";
|
||||
[SDWebImageDownloader sharedDownloader].config.username = @"httpwatch";
|
||||
[SDWebImageDownloader sharedDownloader].config.password = @"httpwatch01";
|
||||
[[SDWebImageDownloader sharedDownloader] setValue:@"SDWebImage Demo" forHTTPHeaderField:@"AppName"];
|
||||
[SDWebImageDownloader sharedDownloader].config.executionOrder = SDWebImageDownloaderLIFOExecutionOrder;
|
||||
|
||||
self.objects = [NSMutableArray arrayWithObjects:
|
||||
@"http://www.httpwatch.com/httpgallery/authentication/authenticatedimage/default.aspx?0.35786508303135633", // requires HTTP auth, used to demo the NTLM auth
|
||||
@"http://assets.sbnation.com/assets/2512203/dogflops.gif",
|
||||
@"https://raw.githubusercontent.com/liyong03/YLGIFImage/master/YLGIFImageDemo/YLGIFImageDemo/joy.gif",
|
||||
@"http://apng.onevcat.com/assets/elephant.png",
|
||||
@"http://www.ioncannon.net/wp-content/uploads/2011/06/test2.webp",
|
||||
@"http://www.ioncannon.net/wp-content/uploads/2011/06/test9.webp",
|
||||
@"http://littlesvr.ca/apng/images/SteamEngine.webp",
|
||||
|
@ -76,38 +79,21 @@
|
|||
for (int i=0; i<100; i++) {
|
||||
[self.objects addObject:[NSString stringWithFormat:@"https://s3.amazonaws.com/fast-image-cache/demo-images/FICDDemoImage%03d.jpg", i]];
|
||||
}
|
||||
|
||||
}
|
||||
[SDWebImageManager.sharedManager.imageDownloader setValue:@"SDWebImage Demo" forHTTPHeaderField:@"AppName"];
|
||||
SDWebImageManager.sharedManager.imageDownloader.executionOrder = SDWebImageDownloaderLIFOExecutionOrder;
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)flushCache
|
||||
{
|
||||
[SDWebImageManager.sharedManager.imageCache clearMemory];
|
||||
[SDWebImageManager.sharedManager.imageCache clearDiskOnCompletion:nil];
|
||||
}
|
||||
|
||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
|
||||
{
|
||||
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
|
||||
- (void)flushCache {
|
||||
[SDWebImageManager.sharedManager.imageCache clearWithCacheType:SDImageCacheTypeAll completion:nil];
|
||||
}
|
||||
|
||||
#pragma mark - Table View
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
|
||||
{
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
return self.objects.count;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
static NSString *CellIdentifier = @"Cell";
|
||||
|
||||
static UIImage *placeholderImage = nil;
|
||||
|
@ -119,11 +105,9 @@
|
|||
if (cell == nil) {
|
||||
cell = [[MyCustomTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
|
||||
cell.customImageView.sd_imageTransition = SDWebImageTransition.fadeTransition;
|
||||
cell.customImageView.sd_imageIndicator = SDWebImageActivityIndicator.grayIndicator;
|
||||
}
|
||||
|
||||
[cell.customImageView sd_setShowActivityIndicatorView:YES];
|
||||
[cell.customImageView sd_setIndicatorStyle:UIActivityIndicatorViewStyleGray];
|
||||
|
||||
cell.customTextLabel.text = [NSString stringWithFormat:@"Image #%ld", (long)indexPath.row];
|
||||
[cell.customImageView sd_setImageWithURL:[NSURL URLWithString:self.objects[indexPath.row]]
|
||||
placeholderImage:placeholderImage
|
||||
|
@ -131,8 +115,7 @@
|
|||
return cell;
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
NSString *largeImageURLString = [self.objects[indexPath.row] stringByReplacingOccurrencesOfString:@"small" withString:@"source"];
|
||||
NSURL *largeImageURL = [NSURL URLWithString:largeImageURLString];
|
||||
DetailViewController *detailViewController = [[DetailViewController alloc] initWithNibName:@"DetailViewController" bundle:nil];
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="10117" systemVersion="15E65" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none">
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" colorMatched="YES">
|
||||
<device id="retina4_7" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="DetailViewController">
|
||||
|
@ -16,12 +20,12 @@
|
|||
<rect key="frame" x="0.0" y="0.0" width="320" height="460"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" id="7" customClass="FLAnimatedImageView">
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" id="7" customClass="SDAnimatedImageView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="460"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
</view>
|
||||
</objects>
|
||||
|
|
|
@ -687,12 +687,12 @@
|
|||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" id="f0P-c9-GMe"/>
|
||||
</imageView>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="JIp-Or-vBM">
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="JIp-Or-vBM" customClass="SDAnimatedImageView">
|
||||
<rect key="frame" x="20" y="116" width="204" height="128"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" id="NJq-m3-LlB"/>
|
||||
</imageView>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="khI-tY-l0M">
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="khI-tY-l0M" customClass="SDAnimatedImageView">
|
||||
<rect key="frame" x="256" y="116" width="204" height="128"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" id="WbV-Do-9qy"/>
|
||||
|
|
|
@ -7,15 +7,15 @@
|
|||
*/
|
||||
|
||||
#import "ViewController.h"
|
||||
|
||||
@import SDWebImage;
|
||||
#import <SDWebImage/SDWebImage.h>
|
||||
#import <SDWebImageWebPCoder/SDImageWebPCoder.h>
|
||||
|
||||
@interface ViewController ()
|
||||
|
||||
@property (weak) IBOutlet NSImageView *imageView1;
|
||||
@property (weak) IBOutlet NSImageView *imageView2;
|
||||
@property (weak) IBOutlet NSImageView *imageView3;
|
||||
@property (weak) IBOutlet NSImageView *imageView4;
|
||||
@property (weak) IBOutlet SDAnimatedImageView *imageView3;
|
||||
@property (weak) IBOutlet SDAnimatedImageView *imageView4;
|
||||
@property (weak) IBOutlet NSButton *clearCacheButton;
|
||||
|
||||
@end
|
||||
|
@ -25,21 +25,19 @@
|
|||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
//Add GIF coder for better animated image rendering
|
||||
[[SDWebImageCodersManager sharedInstance] addCoder:[SDWebImageGIFCoder sharedCoder]];
|
||||
[[SDImageCodersManager sharedManager] addCoder:[SDImageWebPCoder sharedCoder]];
|
||||
|
||||
// NOTE: https links or authentication ones do not work (there is a crash)
|
||||
|
||||
// Do any additional setup after loading the view.
|
||||
// For animated GIF rendering, set `animates` to YES or will only show the first frame
|
||||
self.imageView1.animates = YES;
|
||||
self.imageView2.animates = YES; // `SDAnimatedImageRep` can be used for built-in `NSImageView` to support better GIF & APNG rendering as well. No need `SDAnimatedImageView`
|
||||
self.imageView3.animates = YES;
|
||||
[self.imageView1 sd_setImageWithURL:[NSURL URLWithString:@"http://assets.sbnation.com/assets/2512203/dogflops.gif"]];
|
||||
[self.imageView2 sd_setImageWithURL:[NSURL URLWithString:@"http://www.ioncannon.net/wp-content/uploads/2011/06/test2.webp"]];
|
||||
[self.imageView3 sd_setImageWithURL:[NSURL URLWithString:@"http://littlesvr.ca/apng/images/SteamEngine.webp"]];
|
||||
self.imageView4.animates = YES;
|
||||
self.imageView1.sd_imageIndicator = SDWebImageProgressIndicator.defaultIndicator;
|
||||
[self.imageView1 sd_setImageWithURL:[NSURL URLWithString:@"https://raw.githubusercontent.com/recurser/exif-orientation-examples/master/Landscape_2.jpg"] placeholderImage:nil options:SDWebImageProgressiveLoad];
|
||||
[self.imageView2 sd_setImageWithURL:[NSURL URLWithString:@"https:raw.githubusercontent.com/onevcat/APNGKit/master/TestImages/APNG-cube.apng"]];
|
||||
[self.imageView3 sd_setImageWithURL:[NSURL URLWithString:@"https://raw.githubusercontent.com/liyong03/YLGIFImage/master/YLGIFImageDemo/YLGIFImageDemo/joy.gif"]];
|
||||
self.imageView4.wantsLayer = YES;
|
||||
self.imageView4.sd_imageTransition = SDWebImageTransition.fadeTransition;
|
||||
[self.imageView4 sd_setImageWithURL:[NSURL URLWithString:@"http://s3.amazonaws.com/fast-image-cache/demo-images/FICDDemoImage001.jpg"] placeholderImage:nil options:SDWebImageForceTransition];
|
||||
[self.imageView4 sd_setImageWithURL:[NSURL URLWithString:@"http://littlesvr.ca/apng/images/SteamEngine.webp"] placeholderImage:nil options:SDWebImageForceTransition];
|
||||
|
||||
self.clearCacheButton.target = self;
|
||||
self.clearCacheButton.action = @selector(clearCacheButtonClicked:);
|
||||
|
|
|
@ -3,6 +3,10 @@
|
|||
{
|
||||
"idiom" : "tv",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "tv",
|
||||
"scale" : "2x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
|
|
|
@ -3,6 +3,10 @@
|
|||
{
|
||||
"idiom" : "tv",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "tv",
|
||||
"scale" : "2x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
|
|
|
@ -3,6 +3,10 @@
|
|||
{
|
||||
"idiom" : "tv",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "tv",
|
||||
"scale" : "2x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
|
|
|
@ -3,6 +3,10 @@
|
|||
{
|
||||
"idiom" : "tv",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "tv",
|
||||
"scale" : "2x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
|
|
|
@ -3,6 +3,10 @@
|
|||
{
|
||||
"idiom" : "tv",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "tv",
|
||||
"scale" : "2x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
|
|
|
@ -3,6 +3,10 @@
|
|||
{
|
||||
"idiom" : "tv",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "tv",
|
||||
"scale" : "2x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
|
|
|
@ -12,6 +12,12 @@
|
|||
"filename" : "App Icon - Small.imagestack",
|
||||
"role" : "primary-app-icon"
|
||||
},
|
||||
{
|
||||
"size" : "2320x720",
|
||||
"idiom" : "tv",
|
||||
"filename" : "Top Shelf Image Wide.imageset",
|
||||
"role" : "top-shelf-image-wide"
|
||||
},
|
||||
{
|
||||
"size" : "1920x720",
|
||||
"idiom" : "tv",
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "tv",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "tv",
|
||||
"scale" : "2x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
|
@ -3,6 +3,10 @@
|
|||
{
|
||||
"idiom" : "tv",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "tv",
|
||||
"scale" : "2x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"orientation" : "landscape",
|
||||
"idiom" : "tv",
|
||||
"extent" : "full-screen",
|
||||
"minimum-system-version" : "11.0",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"orientation" : "landscape",
|
||||
"idiom" : "tv",
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder.AppleTV.Storyboard" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="AppleTV" propertyAccessControl="none" useAutolayout="YES" initialViewController="BYZ-38-t0r">
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder.AppleTV.Storyboard" version="3.0" toolsVersion="13771" targetRuntime="AppleTV" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
|
||||
<device id="appleTV" orientation="landscape">
|
||||
<adaptation id="light"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
|
||||
<deployment identifier="tvOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
|
@ -16,20 +21,24 @@
|
|||
<rect key="frame" x="0.0" y="0.0" width="1920" height="1080"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="xeq-iS-C6S" customClass="FLAnimatedImageView">
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="xeq-iS-C6S">
|
||||
<rect key="frame" x="20" y="20" width="300" height="200"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
</imageView>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="c5h-Lg-aZx" customClass="FLAnimatedImageView">
|
||||
<rect key="frame" x="636" y="20" width="300" height="200"/>
|
||||
</imageView>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Udx-nH-mbX" customClass="FLAnimatedImageView">
|
||||
<rect key="frame" x="944" y="20" width="300" height="200"/>
|
||||
</imageView>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="xvm-ne-7D9" customClass="FLAnimatedImageView">
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="xvm-ne-7D9">
|
||||
<rect key="frame" x="328" y="20" width="300" height="200"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
</imageView>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="c5h-Lg-aZx" customClass="SDAnimatedImageView">
|
||||
<rect key="frame" x="636" y="20" width="300" height="200"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
</imageView>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Udx-nH-mbX" customClass="SDAnimatedImageView">
|
||||
<rect key="frame" x="944" y="20" width="300" height="200"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="calibratedWhite"/>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="imageView1" destination="xeq-iS-C6S" id="4gp-UN-VjW"/>
|
||||
|
|
|
@ -7,14 +7,15 @@
|
|||
*/
|
||||
|
||||
#import "ViewController.h"
|
||||
#import <SDWebImage/FLAnimatedImageView+WebCache.h>
|
||||
#import <SDWebImage/SDWebImage.h>
|
||||
#import <SDWebImageWebPCoder/SDImageWebPCoder.h>
|
||||
|
||||
@interface ViewController ()
|
||||
|
||||
@property (weak, nonatomic) IBOutlet FLAnimatedImageView *imageView1;
|
||||
@property (weak, nonatomic) IBOutlet FLAnimatedImageView *imageView2;
|
||||
@property (weak, nonatomic) IBOutlet FLAnimatedImageView *imageView3;
|
||||
@property (weak, nonatomic) IBOutlet FLAnimatedImageView *imageView4;
|
||||
@property (weak, nonatomic) IBOutlet UIImageView *imageView1;
|
||||
@property (weak, nonatomic) IBOutlet UIImageView *imageView2;
|
||||
@property (weak, nonatomic) IBOutlet SDAnimatedImageView *imageView3;
|
||||
@property (weak, nonatomic) IBOutlet SDAnimatedImageView *imageView4;
|
||||
|
||||
@end
|
||||
|
||||
|
@ -24,11 +25,12 @@
|
|||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
// Do any additional setup after loading the view, typically from a nib.
|
||||
[[SDImageCodersManager sharedManager] addCoder:[SDImageWebPCoder sharedCoder]];
|
||||
|
||||
[self.imageView1 sd_setImageWithURL:[NSURL URLWithString:@"http://assets.sbnation.com/assets/2512203/dogflops.gif"]];
|
||||
[self.imageView1 sd_setImageWithURL:[NSURL URLWithString:@"http://s3.amazonaws.com/fast-image-cache/demo-images/FICDDemoImage001.jpg"]];
|
||||
[self.imageView2 sd_setImageWithURL:[NSURL URLWithString:@"http://www.ioncannon.net/wp-content/uploads/2011/06/test2.webp"]];
|
||||
[self.imageView3 sd_setImageWithURL:[NSURL URLWithString:@"http://s3.amazonaws.com/fast-image-cache/demo-images/FICDDemoImage000.jpg"]];
|
||||
[self.imageView4 sd_setImageWithURL:[NSURL URLWithString:@"http://s3.amazonaws.com/fast-image-cache/demo-images/FICDDemoImage001.jpg"]];
|
||||
[self.imageView3 sd_setImageWithURL:[NSURL URLWithString:@"https://raw.githubusercontent.com/liyong03/YLGIFImage/master/YLGIFImageDemo/YLGIFImageDemo/joy.gif"]];
|
||||
[self.imageView4 sd_setImageWithURL:[NSURL URLWithString:@"http://littlesvr.ca/apng/images/SteamEngine.webp"]];
|
||||
}
|
||||
|
||||
- (void)didReceiveMemoryWarning {
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
*/
|
||||
|
||||
#import "InterfaceController.h"
|
||||
#import <SDWebImage/UIImageView+WebCache.h>
|
||||
#import <SDWebImage/SDWebImage.h>
|
||||
#import <SDWebImageWebPCoder/SDImageWebPCoder.h>
|
||||
|
||||
|
||||
@interface InterfaceController()
|
||||
|
@ -23,15 +24,19 @@
|
|||
[super awakeWithContext:context];
|
||||
|
||||
// Configure interface objects here.
|
||||
[[SDImageCodersManager sharedManager] addCoder:[SDImageWebPCoder sharedCoder]];
|
||||
}
|
||||
|
||||
- (void)willActivate {
|
||||
// This method is called when watch view controller is about to be visible to user
|
||||
[super willActivate];
|
||||
|
||||
NSString *urlString = @"https://nr-platform.s3.amazonaws.com/uploads/platform/published_extension/branding_icon/275/AmazonS3.png";
|
||||
NSString *urlString = @"http://apng.onevcat.com/assets/elephant.png";
|
||||
WKInterfaceImage *imageInterface = self.imageInterface;
|
||||
[imageInterface sd_setImageWithURL:[NSURL URLWithString:urlString]];
|
||||
[imageInterface sd_setImageWithURL:[NSURL URLWithString:urlString] completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
|
||||
// `WKInterfaceImage` unlike `UIImageView`. Even the image is animated image, you should explicitly call `startAnimating` to play animation.
|
||||
[imageInterface startAnimating];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)didDeactivate {
|
||||
|
|
|
@ -36,28 +36,6 @@
|
|||
[super didDeactivate];
|
||||
}
|
||||
|
||||
/*
|
||||
- (void)didReceiveLocalNotification:(UILocalNotification *)localNotification withCompletion:(void (^)(WKUserNotificationInterfaceType))completionHandler {
|
||||
// This method is called when a local notification needs to be presented.
|
||||
// Implement it if you use a dynamic notification interface.
|
||||
// Populate your dynamic notification interface as quickly as possible.
|
||||
//
|
||||
// After populating your dynamic notification interface call the completion block.
|
||||
completionHandler(WKUserNotificationInterfaceTypeCustom);
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
- (void)didReceiveRemoteNotification:(NSDictionary *)remoteNotification withCompletion:(void (^)(WKUserNotificationInterfaceType))completionHandler {
|
||||
// This method is called when a remote notification needs to be presented.
|
||||
// Implement it if you use a dynamic notification interface.
|
||||
// Populate your dynamic notification interface as quickly as possible.
|
||||
//
|
||||
// After populating your dynamic notification interface call the completion block.
|
||||
completionHandler(WKUserNotificationInterfaceTypeCustom);
|
||||
}
|
||||
*/
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
|
|
@ -33,6 +33,20 @@
|
|||
"role" : "appLauncher",
|
||||
"subtype" : "38mm"
|
||||
},
|
||||
{
|
||||
"size" : "44x44",
|
||||
"idiom" : "watch",
|
||||
"scale" : "2x",
|
||||
"role" : "appLauncher",
|
||||
"subtype" : "40mm"
|
||||
},
|
||||
{
|
||||
"size" : "50x50",
|
||||
"idiom" : "watch",
|
||||
"scale" : "2x",
|
||||
"role" : "appLauncher",
|
||||
"subtype" : "44mm"
|
||||
},
|
||||
{
|
||||
"size" : "86x86",
|
||||
"idiom" : "watch",
|
||||
|
@ -46,6 +60,18 @@
|
|||
"scale" : "2x",
|
||||
"role" : "quickLook",
|
||||
"subtype" : "42mm"
|
||||
},
|
||||
{
|
||||
"size" : "108x108",
|
||||
"idiom" : "watch",
|
||||
"scale" : "2x",
|
||||
"role" : "quickLook",
|
||||
"subtype" : "44mm"
|
||||
},
|
||||
{
|
||||
"idiom" : "watch-marketing",
|
||||
"size" : "1024x1024",
|
||||
"scale" : "1x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
|
|
2
LICENSE
|
@ -1,4 +1,4 @@
|
|||
Copyright (c) 2009-2017 Olivier Poitrey rs@dailymotion.com
|
||||
Copyright (c) 2009-2018 Olivier Poitrey rs@dailymotion.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
103
README.md
|
@ -1,5 +1,5 @@
|
|||
<p align="center">
|
||||
<img src="SDWebImage_logo.png" title="SDWebImage logo" float=left>
|
||||
<p align="center" >
|
||||
<img src="https://raw.githubusercontent.com/SDWebImage/SDWebImage/master/SDWebImage_logo.png" title="SDWebImage logo" float=left>
|
||||
</p>
|
||||
|
||||
|
||||
|
@ -18,6 +18,11 @@ This library provides an async image downloader with cache support. For convenie
|
|||
- [x] An asynchronous image downloader
|
||||
- [x] An asynchronous memory + disk image caching with automatic cache expiration handling
|
||||
- [x] A background image decompression
|
||||
- [x] Improved [support for animated images](https://github.com/SDWebImage/SDWebImage/wiki/Advanced-Usage#animated-image-50)
|
||||
- [x] [Customizable and composable transformations](https://github.com/SDWebImage/SDWebImage/wiki/Advanced-Usage#transformer-50) can be applied to the images right after download
|
||||
- [x] [Custom cache control](https://github.com/SDWebImage/SDWebImage/wiki/Advanced-Usage#custom-cache-50)
|
||||
- [x] Expand the image loading capabilites by adding your [own custom loaders](https://github.com/SDWebImage/SDWebImage/wiki/Advanced-Usage#custom-loader-50) or using prebuilt loaders like [FLAnimatedImage plugin](https://github.com/SDWebImage/SDWebImageFLPlugin) or [Photos Library plugin](https://github.com/SDWebImage/SDWebImagePhotosPlugin)
|
||||
- [x] [Loading indicators](https://github.com/SDWebImage/SDWebImage/wiki/How-to-use#use-view-indicator-50)
|
||||
- [x] A guarantee that the same URL won't be downloaded several times
|
||||
- [x] A guarantee that bogus URLs won't be retried again and again
|
||||
- [x] A guarantee that main thread will never be blocked
|
||||
|
@ -27,9 +32,33 @@ This library provides an async image downloader with cache support. For convenie
|
|||
## Supported Image Formats
|
||||
|
||||
- Image formats supported by UIImage (JPEG, PNG, ...), including GIF
|
||||
- WebP format, including animated WebP (use the `WebP` subspec)
|
||||
- WebP format, including animated WebP (use the [SDWebImageWebPCoder](https://github.com/SDWebImage/SDWebImageWebPCoder) project)
|
||||
- Support extendable coder plugins for new image formats. Like APNG, BPG, HFIF, SVG, etc. See all the list in [Image coder plugin List](https://github.com/SDWebImage/SDWebImage/wiki/Coder-Plugin-List)
|
||||
|
||||
## Additional modules
|
||||
|
||||
In order to keep SDWebImage focused and limited to the core features, but also allow extensibility and custom behaviors, during the 5.0 refactoring we focused on modularizing the library.
|
||||
As such, we have moved/built new modules to [SDWebImage org](https://github.com/SDWebImage).
|
||||
|
||||
#### Coders for additional image formats
|
||||
- [SDWebImageWebPCoder](https://github.com/SDWebImage/SDWebImageWebPCoder) - coder for WebP image format. Based on [libwebp](https://chromium.googlesource.com/webm/libwebp)
|
||||
- [SDWebImageHEIFCoder](https://github.com/SDWebImage/SDWebImageHEIFCoder) - coder to support HEIF image without Apple's `Image/IO framework`
|
||||
- [SDWebImageAPNGCoder](https://github.com/SDWebImage/SDWebImageAPNGCoder) - coder for APNG format (animated PNG)
|
||||
- [SDWebImageBPGCoder](https://github.com/SDWebImage/SDWebImageBPGCoder) - coder for BPG format
|
||||
|
||||
#### Loaders
|
||||
- [SDWebImagePhotosPlugin](https://github.com/SDWebImage/SDWebImagePhotosPlugin) - plugin to support loading images from Photos (using `Photos.framework`)
|
||||
|
||||
#### Integration with 3rd party libraries
|
||||
- [SDWebImageFLPlugin](https://github.com/SDWebImage/SDWebImageFLPlugin) - plugin to support [FLAnimatedImage](https://github.com/Flipboard/FLAnimatedImage) as the engine for animated GIFs
|
||||
- [SDWebImageYYPlugin](https://github.com/SDWebImage/SDWebImageYYPlugin) - plugin to integrate [YYImage](https://github.com/ibireme/YYImage) & [YYCache](https://github.com/ibireme/YYCache) for image rendering & caching
|
||||
- [SDWebImageProgressiveJPEGDemo](https://github.com/SDWebImage/SDWebImageProgressiveJPEGDemo) - demo project for using `SDWebImage` + [Concorde library](https://github.com/contentful-labs/Concorde) for Progressive JPEG decoding
|
||||
|
||||
#### Make our lives easier
|
||||
- [libwebp-Xcode](https://github.com/SDWebImage/libwebp-Xcode) - A wrapper for [libwebp](https://chromium.googlesource.com/webm/libwebp) + an Xcode project.
|
||||
|
||||
You can use those directly, or create similar components of your own.
|
||||
|
||||
## Beta version
|
||||
|
||||
SDWebImage's 5.0 version is nearing completion. Which introduce many new features like Animated ImageView and Transformer. We also provide a more modularized design used for advanced user customization.
|
||||
|
@ -38,15 +67,17 @@ You can check the latest [5.x branch](https://github.com/SDWebImage/SDWebImage/t
|
|||
|
||||
## Requirements
|
||||
|
||||
- iOS 7.0 or later
|
||||
- iOS 8.0 or later
|
||||
- tvOS 9.0 or later
|
||||
- watchOS 2.0 or later
|
||||
- macOS 10.9 or later
|
||||
- Xcode 7.3 or later
|
||||
- macOS 10.10 or later
|
||||
- Xcode 9.0 or later
|
||||
|
||||
#### Backwards compatibility
|
||||
|
||||
- For iOS 5 and 6, use [any 3.x version up to 3.7.6](https://github.com/SDWebImage/SDWebImage/tree/3.7.6)
|
||||
- For iOS 7, macOS 10.9 or Xcode < 8, use [any 4.x version up to 4.3.3](https://github.com/SDWebImage/SDWebImage/releases/tag/4.3.3)
|
||||
- For macOS 10.8, use [any 4.x version up to 4.3.0](https://github.com/SDWebImage/SDWebImage/releases/tag/4.3.0)
|
||||
- For iOS 5 and 6, use [any 3.x version up to 3.7.6](https://github.com/SDWebImage/SDWebImage/tag/3.7.6)
|
||||
- For iOS < 5.0, please use the last [2.0 version](https://github.com/SDWebImage/SDWebImage/tree/2.0-compat).
|
||||
|
||||
## Getting Started
|
||||
|
@ -56,7 +87,8 @@ You can check the latest [5.x branch](https://github.com/SDWebImage/SDWebImage/t
|
|||
- Read the [Documentation @ CocoaDocs](http://cocoadocs.org/docsets/SDWebImage/)
|
||||
- Try the example by downloading the project from Github or even easier using CocoaPods try `pod try SDWebImage`
|
||||
- Read the [Installation Guide](https://github.com/SDWebImage/SDWebImage/wiki/Installation-Guide)
|
||||
- Read the [SDWebImage 4.0 Migration Guide](Docs/SDWebImage-4.0-Migration-guide.md) to get an idea of the changes from 3.x to 4.x
|
||||
- Read the [SDWebImage 5.0 Migration Guide](https://raw.githubusercontent.com/SDWebImage/SDWebImage/master/Docs/SDWebImage-5.0-Migration-guide.md) to get an idea of the changes from 4.x to 5.x
|
||||
- Read the [SDWebImage 4.0 Migration Guide](https://raw.githubusercontent.com/SDWebImage/SDWebImage/master/Docs/SDWebImage-4.0-Migration-guide.md) to get an idea of the changes from 3.x to 4.x
|
||||
- Read the [Common Problems](https://github.com/SDWebImage/SDWebImage/wiki/Common-Problems) to find the solution for common problems
|
||||
- Go to the [Wiki Page](https://github.com/SDWebImage/SDWebImage/wiki) for more information such as [Advanced Usage](https://github.com/SDWebImage/SDWebImage/wiki/Advanced-Usage)
|
||||
|
||||
|
@ -69,7 +101,7 @@ You can check the latest [5.x branch](https://github.com/SDWebImage/SDWebImage/t
|
|||
- If you'd like to **ask a general question**, use [Stack Overflow](http://stackoverflow.com/questions/tagged/sdwebimage).
|
||||
- If you **found a bug**, open an issue.
|
||||
- If you **have a feature request**, open an issue.
|
||||
- If you **want to contribute**, submit a pull request.
|
||||
- If you **want to contribute**, read the [Contributing Guide](https://raw.githubusercontent.com/SDWebImage/SDWebImage/master/.github/CONTRIBUTING.md)
|
||||
|
||||
## How To Use
|
||||
|
||||
|
@ -90,15 +122,15 @@ import SDWebImage
|
|||
imageView.sd_setImage(with: URL(string: "http://www.domain.com/path/to/image.jpg"), placeholderImage: UIImage(named: "placeholder.png"))
|
||||
```
|
||||
|
||||
- For details about how to use the library and clear examples, see [The detailed How to use](Docs/HowToUse.md)
|
||||
- For details about how to use the library and clear examples, see [The detailed How to use](https://raw.githubusercontent.com/SDWebImage/SDWebImage/master/Docs/HowToUse.md)
|
||||
|
||||
## Animated Images (GIF) support
|
||||
|
||||
- Starting with the 4.0 version, we rely on [FLAnimatedImage](https://github.com/Flipboard/FLAnimatedImage) to take care of our animated images.
|
||||
- If you use cocoapods, add `pod 'SDWebImage/GIF'` to your podfile.
|
||||
- To use it, simply make sure you use `FLAnimatedImageView` instead of `UIImageView`.
|
||||
- **Note**: there is a backwards compatible feature, so if you are still trying to load a GIF into a `UIImageView`, it will only show the 1st frame as a static image by default. However, you can enable the full GIF support by using the built-in GIF coder. See [GIF coder](https://github.com/SDWebImage/SDWebImage/wiki/Advanced-Usage#gif-coder)
|
||||
- **Important**: FLAnimatedImage only works on the iOS platform. For macOS, use `NSImageView` with `animates` set to `YES` to show the entire animated images and `NO` to only show the 1st frame. For all the other platforms (tvOS, watchOS) we will fallback to the backwards compatibility feature described above
|
||||
In 5.0, we introduced a brand new mechanism for supporting animated images. This includes animated image loading, rendering, decoding, and also supports customizations (for advanced users).
|
||||
This animated image solution is available for `iOS`/`tvOS`/`macOS`. The `SDAnimatedImage` is subclass of `UIImage/NSImage`, and `SDAnimatedImageView` is subclass of `UIImageView/NSImageView`, to make them compatible with the common frameworks APIs. See [Animated Image](https://github.com/SDWebImage/SDWebImage/wiki/Advanced-Usage#animated-image-50) for more detailed information.
|
||||
|
||||
#### FLAnimatedImage integration has its own dedicated repo
|
||||
In order to clean up things and make our core project do less things, we decided that the `FLAnimatedImage` integration does not belong here. From 5.0, this will still be available, but under a dedicated repo [SDWebImageFLPlugin](https://github.com/SDWebImage/SDWebImageFLPlugin).
|
||||
|
||||
## Installation
|
||||
|
||||
|
@ -142,11 +174,11 @@ pod 'SDWebImage'
|
|||
|
||||
#### Subspecs
|
||||
|
||||
There are 4 subspecs available now: `Core`, `MapKit`, `GIF` and `WebP` (this means you can install only some of the SDWebImage modules. By default, you get just `Core`, so if you need `WebP`, you need to specify it).
|
||||
There are 2 subspecs available now: `Core` and `MapKit` (this means you can install only some of the SDWebImage modules. By default, you get just `Core`, so if you need `MapKit`, you need to specify it).
|
||||
|
||||
Podfile example:
|
||||
```
|
||||
pod 'SDWebImage/WebP'
|
||||
pod 'SDWebImage/MapKit'
|
||||
```
|
||||
|
||||
### Installation with Carthage (iOS 8+)
|
||||
|
@ -155,13 +187,16 @@ pod 'SDWebImage/WebP'
|
|||
|
||||
To install with carthage, follow the instruction on [Carthage](https://github.com/Carthage/Carthage)
|
||||
|
||||
#### Cartfile
|
||||
```
|
||||
github "SDWebImage/SDWebImage"
|
||||
```
|
||||
Carthage users can point to this repository and use whichever generated framework they'd like: SDWebImage, SDWebImageMapKit or both.
|
||||
|
||||
Make the following entry in your Cartfile: `github "SDWebImage/SDWebImage"`
|
||||
Then run `carthage update`
|
||||
If this is your first time using Carthage in the project, you'll need to go through some additional steps as explained [over at Carthage](https://github.com/Carthage/Carthage#adding-frameworks-to-an-application).
|
||||
|
||||
> NOTE: At this time, Carthage does not provide a way to build only specific repository subcomponents (or equivalent of CocoaPods's subspecs). All components and their dependencies will be built with the above command. However, you don't need to copy frameworks you aren't using into your project. For instance, if you aren't using `SDWebImageMapKit`, feel free to delete that framework from the Carthage Build directory after `carthage update` completes.
|
||||
|
||||
### Installation by cloning the repository
|
||||
- see [Manual install](Docs/ManualInstallation.md)
|
||||
- see [Manual install](https://raw.githubusercontent.com/SDWebImage/SDWebImage/master/Docs/ManualInstallation.md)
|
||||
|
||||
### Import headers in your source files
|
||||
|
||||
|
@ -192,12 +227,28 @@ All source code is licensed under the [MIT License](https://raw.github.com/SDWeb
|
|||
|
||||
## Architecture
|
||||
|
||||
<p align="center">
|
||||
<img src="Docs/SDWebImageClassDiagram.png" title="SDWebImage class diagram">
|
||||
#### High Level Diagram
|
||||
<p align="center" >
|
||||
<img src="https://raw.githubusercontent.com/SDWebImage/SDWebImage/master/Docs/Diagrams/SDWebImageHighLevelDiagram.jpeg" title="SDWebImage high level diagram">
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<img src="Docs/SDWebImageSequenceDiagram.png" title="SDWebImage sequence diagram">
|
||||
#### Overall Class Diagram
|
||||
<p align="center" >
|
||||
<img src="https://raw.githubusercontent.com/SDWebImage/SDWebImage/master/Docs/Diagrams/SDWebImageClassDiagram.png" title="SDWebImage overall class diagram">
|
||||
</p>
|
||||
|
||||
#### Top Level API Diagram
|
||||
<p align="center" >
|
||||
<img src="https://raw.githubusercontent.com/SDWebImage/SDWebImage/master/Docs/Diagrams/SDWebImageTopLevelClassDiagram.png" title="SDWebImage top level API diagram">
|
||||
</p>
|
||||
|
||||
#### Main Sequence Diagram
|
||||
<p align="center" >
|
||||
<img src="https://raw.githubusercontent.com/SDWebImage/SDWebImage/master/Docs/Diagrams/SDWebImageSequenceDiagram.png" title="SDWebImage sequence diagram">
|
||||
</p>
|
||||
|
||||
#### More detailed diagrams
|
||||
- [Manager API Diagram](https://raw.githubusercontent.com/SDWebImage/SDWebImage/master/Docs/Diagrams/SDWebImageManagerClassDiagram.png)
|
||||
- [Coders API Diagram](https://raw.githubusercontent.com/SDWebImage/SDWebImage/master/Docs/Diagrams/SDWebImageCodersClassDiagram.png)
|
||||
- [Loader API Diagram](https://raw.githubusercontent.com/SDWebImage/SDWebImage/master/Docs/Diagrams/SDWebImageLoaderClassDiagram.png)
|
||||
- [Cache API Diagram](https://raw.githubusercontent.com/SDWebImage/SDWebImage/master/Docs/Diagrams/SDWebImageCacheClassDiagram.png)
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'SDWebImage'
|
||||
s.version = '4.4.6'
|
||||
s.version = '5.0.0-beta6'
|
||||
|
||||
s.osx.deployment_target = '10.9'
|
||||
s.ios.deployment_target = '7.0'
|
||||
s.osx.deployment_target = '10.10'
|
||||
s.ios.deployment_target = '8.0'
|
||||
s.tvos.deployment_target = '9.0'
|
||||
s.watchos.deployment_target = '2.0'
|
||||
|
||||
|
@ -23,42 +23,23 @@ Pod::Spec.new do |s|
|
|||
|
||||
s.requires_arc = true
|
||||
s.framework = 'ImageIO'
|
||||
s.module_map = 'WebImage/SDWebImage.modulemap'
|
||||
|
||||
s.default_subspec = 'Core'
|
||||
|
||||
s.subspec 'Core' do |core|
|
||||
core.source_files = 'SDWebImage/{NS,SD,UI}*.{h,m}'
|
||||
core.exclude_files = 'SDWebImage/UIImage+WebP.{h,m}', 'SDWebImage/SDWebImageWebPCoder.{h,m}'
|
||||
core.tvos.exclude_files = 'SDWebImage/MKAnnotationView+WebCache.*'
|
||||
core.source_files = 'SDWebImage/*.{h,m}', 'WebImage/SDWebImage.h', 'SDWebImage/Private/*.{h,m}'
|
||||
core.exclude_files = 'SDWebImage/MapKit/*.{h,m}'
|
||||
core.private_header_files = 'SDWebImage/Private/*.h'
|
||||
core.prefix_header_contents = '#import "SDInternalMacros.h"'
|
||||
end
|
||||
|
||||
s.subspec 'MapKit' do |mk|
|
||||
mk.osx.deployment_target = '10.9'
|
||||
mk.ios.deployment_target = '7.0'
|
||||
mk.tvos.deployment_target = '9.0'
|
||||
mk.source_files = 'SDWebImage/MKAnnotationView+WebCache.*'
|
||||
mk.osx.deployment_target = '10.10'
|
||||
mk.ios.deployment_target = '8.0'
|
||||
mk.tvos.deployment_target = '9.2'
|
||||
mk.source_files = 'SDWebImage/MapKit/*.{h,m}'
|
||||
mk.framework = 'MapKit'
|
||||
mk.dependency 'SDWebImage/Core'
|
||||
end
|
||||
|
||||
s.subspec 'GIF' do |gif|
|
||||
gif.ios.deployment_target = '7.0'
|
||||
gif.source_files = 'SDWebImage/FLAnimatedImage/*.{h,m}'
|
||||
gif.dependency 'SDWebImage/Core'
|
||||
gif.dependency 'FLAnimatedImage', '~> 1.0'
|
||||
end
|
||||
|
||||
s.subspec 'WebP' do |webp|
|
||||
webp.source_files = 'SDWebImage/UIImage+WebP.{h,m}', 'SDWebImage/SDWebImageWebPCoder.{h,m}'
|
||||
webp.xcconfig = {
|
||||
'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) SD_WEBP=1',
|
||||
'USER_HEADER_SEARCH_PATHS' => '$(inherited) $(SRCROOT)/libwebp/src'
|
||||
}
|
||||
webp.watchos.xcconfig = {
|
||||
'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) SD_WEBP=1 WEBP_USE_INTRINSICS=1',
|
||||
'USER_HEADER_SEARCH_PATHS' => '$(inherited) $(SRCROOT)/libwebp/src'
|
||||
}
|
||||
webp.dependency 'SDWebImage/Core'
|
||||
webp.dependency 'libwebp', '>= 0.5', '< 2.0'
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0920"
|
||||
LastUpgradeVersion = "1000"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
@ -15,8 +15,8 @@
|
|||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "53761307155AD0D5005750A4"
|
||||
BuildableName = "libSDWebImage iOS static.a"
|
||||
BlueprintName = "SDWebImage iOS static"
|
||||
BuildableName = "libSDWebImage.a"
|
||||
BlueprintName = "SDWebImage static"
|
||||
ReferencedContainer = "container:SDWebImage.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
|
@ -26,7 +26,6 @@
|
|||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
|
@ -37,7 +36,6 @@
|
|||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
|
@ -48,8 +46,8 @@
|
|||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "53761307155AD0D5005750A4"
|
||||
BuildableName = "libSDWebImage iOS static.a"
|
||||
BlueprintName = "SDWebImage iOS static"
|
||||
BuildableName = "libSDWebImage.a"
|
||||
BlueprintName = "SDWebImage static"
|
||||
ReferencedContainer = "container:SDWebImage.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
|
@ -1,82 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0920"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "00733A4B1BC487C000A5A117"
|
||||
BuildableName = "SDWebImage.framework"
|
||||
BlueprintName = "SDWebImage tvOS"
|
||||
ReferencedContainer = "container:SDWebImage.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "00733A4B1BC487C000A5A117"
|
||||
BuildableName = "SDWebImage.framework"
|
||||
BlueprintName = "SDWebImage tvOS"
|
||||
ReferencedContainer = "container:SDWebImage.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "00733A4B1BC487C000A5A117"
|
||||
BuildableName = "SDWebImage.framework"
|
||||
BlueprintName = "SDWebImage tvOS"
|
||||
ReferencedContainer = "container:SDWebImage.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
|
@ -1,82 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0920"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "431BB6891D06D2C1006A3455"
|
||||
BuildableName = "SDWebImage.framework"
|
||||
BlueprintName = "SDWebImage watchOS"
|
||||
ReferencedContainer = "container:SDWebImage.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "431BB6891D06D2C1006A3455"
|
||||
BuildableName = "SDWebImage.framework"
|
||||
BlueprintName = "SDWebImage watchOS"
|
||||
ReferencedContainer = "container:SDWebImage.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "431BB6891D06D2C1006A3455"
|
||||
BuildableName = "SDWebImage.framework"
|
||||
BlueprintName = "SDWebImage watchOS"
|
||||
ReferencedContainer = "container:SDWebImage.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0920"
|
||||
LastUpgradeVersion = "1000"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
@ -16,7 +16,7 @@
|
|||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "4A2CADFE1AB4BB5300B6BC39"
|
||||
BuildableName = "SDWebImage.framework"
|
||||
BlueprintName = "SDWebImage iOS"
|
||||
BlueprintName = "SDWebImage"
|
||||
ReferencedContainer = "container:SDWebImage.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
|
@ -26,7 +26,6 @@
|
|||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
|
@ -37,7 +36,6 @@
|
|||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
|
@ -49,7 +47,7 @@
|
|||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "4A2CADFE1AB4BB5300B6BC39"
|
||||
BuildableName = "SDWebImage.framework"
|
||||
BlueprintName = "SDWebImage iOS"
|
||||
BlueprintName = "SDWebImage"
|
||||
ReferencedContainer = "container:SDWebImage.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
|
@ -67,7 +65,7 @@
|
|||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "4A2CADFE1AB4BB5300B6BC39"
|
||||
BuildableName = "SDWebImage.framework"
|
||||
BlueprintName = "SDWebImage iOS"
|
||||
BlueprintName = "SDWebImage"
|
||||
ReferencedContainer = "container:SDWebImage.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0920"
|
||||
LastUpgradeVersion = "1000"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
@ -14,9 +14,9 @@
|
|||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "4397D2761D0DDD8C00BB2784"
|
||||
BuildableName = "SDWebImage.framework"
|
||||
BlueprintName = "SDWebImage OSX"
|
||||
BlueprintIdentifier = "80B6DF862142B71600BCB334"
|
||||
BuildableName = "SDWebImageMapKit.framework"
|
||||
BlueprintName = "SDWebImageMapKit"
|
||||
ReferencedContainer = "container:SDWebImage.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
|
@ -26,7 +26,6 @@
|
|||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
|
@ -37,7 +36,6 @@
|
|||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
|
@ -47,9 +45,9 @@
|
|||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "4397D2761D0DDD8C00BB2784"
|
||||
BuildableName = "SDWebImage.framework"
|
||||
BlueprintName = "SDWebImage OSX"
|
||||
BlueprintIdentifier = "80B6DF862142B71600BCB334"
|
||||
BuildableName = "SDWebImageMapKit.framework"
|
||||
BlueprintName = "SDWebImageMapKit"
|
||||
ReferencedContainer = "container:SDWebImage.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
|
@ -65,9 +63,9 @@
|
|||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "4397D2761D0DDD8C00BB2784"
|
||||
BuildableName = "SDWebImage.framework"
|
||||
BlueprintName = "SDWebImage OSX"
|
||||
BlueprintIdentifier = "80B6DF862142B71600BCB334"
|
||||
BuildableName = "SDWebImageMapKit.framework"
|
||||
BlueprintName = "SDWebImageMapKit"
|
||||
ReferencedContainer = "container:SDWebImage.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
|
@ -1,6 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "group:SDWebImage.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:Examples/SDWebImage Demo.xcodeproj">
|
||||
</FileRef>
|
||||
|
@ -25,4 +28,7 @@
|
|||
<FileRef
|
||||
location = "group:Tests/Pods/Pods.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:Examples/Pods/Pods.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
|
|
|
@ -1,168 +0,0 @@
|
|||
/*
|
||||
* This file is part of the SDWebImage package.
|
||||
* (c) Olivier Poitrey <rs@dailymotion.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
#import "SDWebImageCompat.h"
|
||||
|
||||
#if SD_UIKIT
|
||||
|
||||
#if __has_include(<FLAnimatedImage/FLAnimatedImage.h>)
|
||||
#import <FLAnimatedImage/FLAnimatedImage.h>
|
||||
#else
|
||||
#import "FLAnimatedImage.h"
|
||||
#endif
|
||||
|
||||
#import "SDWebImageManager.h"
|
||||
|
||||
/**
|
||||
* FLAnimatedImage is not a subclass of UIImage, so it's not possible to store it into the memory cache currently. However, for performance issue and cell reuse on FLAnimatedImageView, we use associate object to bind a FLAnimatedImage into UIImage when an animated GIF image load. For most cases, you don't need to touch this.
|
||||
*/
|
||||
@interface UIImage (FLAnimatedImage)
|
||||
|
||||
/**
|
||||
* The FLAnimatedImage associated to the UIImage instance when an animated GIF image load.
|
||||
* For most cases this is read-only and you should avoid manually setting this value. Util some cases like using placeholder with a `FLAnimatedImage`.
|
||||
*/
|
||||
@property (nonatomic, strong, nullable) FLAnimatedImage *sd_FLAnimatedImage;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
/**
|
||||
* A category for the FLAnimatedImage imageView class that hooks it to the SDWebImage system.
|
||||
* Very similar to the base class category (UIImageView (WebCache))
|
||||
*/
|
||||
@interface FLAnimatedImageView (WebCache)
|
||||
|
||||
/**
|
||||
* Optimal frame cache size of FLAnimatedImage during initializer. (1.0.11 version later)
|
||||
* This value will help you set `optimalFrameCacheSize` arg of FLAnimatedImage initializer after image load.
|
||||
* Defaults to 0.
|
||||
*/
|
||||
@property (nonatomic, assign) NSUInteger sd_optimalFrameCacheSize;
|
||||
|
||||
/**
|
||||
* Predrawing control of FLAnimatedImage during initializer. (1.0.11 version later)
|
||||
* This value will help you set `predrawingEnabled` arg of FLAnimatedImage initializer after image load.
|
||||
* Defaults to YES.
|
||||
*/
|
||||
@property (nonatomic, assign) BOOL sd_predrawingEnabled;
|
||||
|
||||
/**
|
||||
* Cache control for associated FLAnimatedImage object for memory cache. When enabled, we will bind created FLAnimatedImage instance to UIImage, and store it into memory cache to avoid create this instance cause decoding performance. See `UIImage+FLAnimatedImage`.
|
||||
* When enabled, this may consume more memory, if you are facing memory issue, disable it and let FLAnimatedImage been created just in time and dealloced as it not been used. However, when disabled, this may impact performance since we need query disk cache, create FLAnimatedImage and decoding even when the current GIF url is cached.
|
||||
* Defatuls to YES;
|
||||
*/
|
||||
@property (nonatomic, assign) BOOL sd_cacheFLAnimatedImage;
|
||||
|
||||
/**
|
||||
* Load the image at the given url (either from cache or download) and load it in this imageView. It works with both static and dynamic images
|
||||
* The download is asynchronous and cached.
|
||||
*
|
||||
* @param url The url for the image.
|
||||
*/
|
||||
- (void)sd_setImageWithURL:(nullable NSURL *)url NS_REFINED_FOR_SWIFT;
|
||||
|
||||
/**
|
||||
* Load the image at the given url (either from cache or download) and load it in this imageView. It works with both static and dynamic images
|
||||
* The download is asynchronous and cached.
|
||||
* Uses a placeholder until the request finishes.
|
||||
*
|
||||
* @param url The url for the image.
|
||||
* @param placeholder The image to be set initially, until the image request finishes.
|
||||
*/
|
||||
- (void)sd_setImageWithURL:(nullable NSURL *)url
|
||||
placeholderImage:(nullable UIImage *)placeholder NS_REFINED_FOR_SWIFT;
|
||||
|
||||
/**
|
||||
* Load the image at the given url (either from cache or download) and load it in this imageView. It works with both static and dynamic images
|
||||
* The download is asynchronous and cached.
|
||||
* Uses a placeholder until the request finishes.
|
||||
*
|
||||
* @param url The url for the image.
|
||||
* @param placeholder The image to be set initially, until the image request finishes.
|
||||
* @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values.
|
||||
*/
|
||||
- (void)sd_setImageWithURL:(nullable NSURL *)url
|
||||
placeholderImage:(nullable UIImage *)placeholder
|
||||
options:(SDWebImageOptions)options NS_REFINED_FOR_SWIFT;
|
||||
|
||||
/**
|
||||
* Load the image at the given url (either from cache or download) and load it in this imageView. It works with both static and dynamic images
|
||||
* The download is asynchronous and cached.
|
||||
*
|
||||
* @param url The url for the image.
|
||||
* @param completedBlock A block called when operation has been completed. This block has no return value
|
||||
* and takes the requested UIImage as first parameter. In case of error the image parameter
|
||||
* is nil and the second parameter may contain an NSError. The third parameter is a Boolean
|
||||
* indicating if the image was retrieved from the local cache or from the network.
|
||||
* The fourth parameter is the original image url.
|
||||
*/
|
||||
- (void)sd_setImageWithURL:(nullable NSURL *)url
|
||||
completed:(nullable SDExternalCompletionBlock)completedBlock;
|
||||
|
||||
/**
|
||||
* Load the image at the given url (either from cache or download) and load it in this imageView. It works with both static and dynamic images
|
||||
* The download is asynchronous and cached.
|
||||
* Uses a placeholder until the request finishes.
|
||||
*
|
||||
* @param url The url for the image.
|
||||
* @param placeholder The image to be set initially, until the image request finishes.
|
||||
* @param completedBlock A block called when operation has been completed. This block has no return value
|
||||
* and takes the requested UIImage as first parameter. In case of error the image parameter
|
||||
* is nil and the second parameter may contain an NSError. The third parameter is a Boolean
|
||||
* indicating if the image was retrieved from the local cache or from the network.
|
||||
* The fourth parameter is the original image url.
|
||||
*/
|
||||
- (void)sd_setImageWithURL:(nullable NSURL *)url
|
||||
placeholderImage:(nullable UIImage *)placeholder
|
||||
completed:(nullable SDExternalCompletionBlock)completedBlock NS_REFINED_FOR_SWIFT;
|
||||
|
||||
/**
|
||||
* Load the image at the given url (either from cache or download) and load it in this imageView. It works with both static and dynamic images
|
||||
* The download is asynchronous and cached.
|
||||
* Uses a placeholder until the request finishes.
|
||||
*
|
||||
* @param url The url for the image.
|
||||
* @param placeholder The image to be set initially, until the image request finishes.
|
||||
* @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values.
|
||||
* @param completedBlock A block called when operation has been completed. This block has no return value
|
||||
* and takes the requested UIImage as first parameter. In case of error the image parameter
|
||||
* is nil and the second parameter may contain an NSError. The third parameter is a Boolean
|
||||
* indicating if the image was retrieved from the local cache or from the network.
|
||||
* The fourth parameter is the original image url.
|
||||
*/
|
||||
- (void)sd_setImageWithURL:(nullable NSURL *)url
|
||||
placeholderImage:(nullable UIImage *)placeholder
|
||||
options:(SDWebImageOptions)options
|
||||
completed:(nullable SDExternalCompletionBlock)completedBlock;
|
||||
|
||||
/**
|
||||
* Load the image at the given url (either from cache or download) and load it in this imageView. It works with both static and dynamic images
|
||||
* The download is asynchronous and cached.
|
||||
* Uses a placeholder until the request finishes.
|
||||
*
|
||||
* @param url The url for the image.
|
||||
* @param placeholder The image to be set initially, until the image request finishes.
|
||||
* @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values.
|
||||
* @param progressBlock A block called while image is downloading
|
||||
* @note the progress block is executed on a background queue
|
||||
* @param completedBlock A block called when operation has been completed. This block has no return value
|
||||
* and takes the requested UIImage as first parameter. In case of error the image parameter
|
||||
* is nil and the second parameter may contain an NSError. The third parameter is a Boolean
|
||||
* indicating if the image was retrieved from the local cache or from the network.
|
||||
* The fourth parameter is the original image url.
|
||||
*/
|
||||
- (void)sd_setImageWithURL:(nullable NSURL *)url
|
||||
placeholderImage:(nullable UIImage *)placeholder
|
||||
options:(SDWebImageOptions)options
|
||||
progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
|
||||
completed:(nullable SDExternalCompletionBlock)completedBlock;
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
|
@ -1,215 +0,0 @@
|
|||
/*
|
||||
* This file is part of the SDWebImage package.
|
||||
* (c) Olivier Poitrey <rs@dailymotion.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
#import "FLAnimatedImageView+WebCache.h"
|
||||
|
||||
#if SD_UIKIT
|
||||
#import "objc/runtime.h"
|
||||
#import "UIView+WebCacheOperation.h"
|
||||
#import "UIView+WebCache.h"
|
||||
#import "NSData+ImageContentType.h"
|
||||
#import "UIImageView+WebCache.h"
|
||||
#import "UIImage+MultiFormat.h"
|
||||
#import "UIImage+MemoryCacheCost.h"
|
||||
|
||||
@interface UIView (PrivateWebCache)
|
||||
|
||||
- (void)sd_internalSetImageWithURL:(nullable NSURL *)url
|
||||
placeholderImage:(nullable UIImage *)placeholder
|
||||
options:(SDWebImageOptions)options
|
||||
operationKey:(nullable NSString *)operationKey
|
||||
internalSetImageBlock:(nullable SDInternalSetImageBlock)setImageBlock
|
||||
progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
|
||||
completed:(nullable SDExternalCompletionBlock)completedBlock
|
||||
context:(nullable NSDictionary<NSString *, id> *)context;
|
||||
|
||||
@end
|
||||
|
||||
static inline FLAnimatedImage * SDWebImageCreateFLAnimatedImage(FLAnimatedImageView *imageView, NSData *imageData) {
|
||||
if ([NSData sd_imageFormatForImageData:imageData] != SDImageFormatGIF) {
|
||||
return nil;
|
||||
}
|
||||
FLAnimatedImage *animatedImage;
|
||||
// Compatibility in 4.x for lower version FLAnimatedImage.
|
||||
if ([FLAnimatedImage instancesRespondToSelector:@selector(initWithAnimatedGIFData:optimalFrameCacheSize:predrawingEnabled:)]) {
|
||||
animatedImage = [[FLAnimatedImage alloc] initWithAnimatedGIFData:imageData optimalFrameCacheSize:imageView.sd_optimalFrameCacheSize predrawingEnabled:imageView.sd_predrawingEnabled];
|
||||
} else {
|
||||
animatedImage = [[FLAnimatedImage alloc] initWithAnimatedGIFData:imageData];
|
||||
}
|
||||
return animatedImage;
|
||||
}
|
||||
|
||||
static inline NSUInteger SDWebImageMemoryCostFLAnimatedImage(FLAnimatedImage *animatedImage, UIImage *image) {
|
||||
NSUInteger frameCacheSizeCurrent = animatedImage.frameCacheSizeCurrent; // [1...frame count], more suitable than raw frame count because FLAnimatedImage internal actually store a buffer size but not full frames (they called `window`)
|
||||
NSUInteger pixelsPerFrame = animatedImage.size.width * animatedImage.size.height; // FLAnimatedImage does not support scale factor
|
||||
NSUInteger animatedImageCost = frameCacheSizeCurrent * pixelsPerFrame;
|
||||
|
||||
NSUInteger imageCost = image.size.height * image.size.width * image.scale * image.scale; // Same as normal cost calculation
|
||||
imageCost = image.images ? (imageCost * image.images.count) : imageCost;
|
||||
|
||||
return animatedImageCost + imageCost;
|
||||
}
|
||||
|
||||
@implementation UIImage (FLAnimatedImage)
|
||||
|
||||
- (FLAnimatedImage *)sd_FLAnimatedImage {
|
||||
return objc_getAssociatedObject(self, @selector(sd_FLAnimatedImage));
|
||||
}
|
||||
|
||||
- (void)setSd_FLAnimatedImage:(FLAnimatedImage *)sd_FLAnimatedImage {
|
||||
objc_setAssociatedObject(self, @selector(sd_FLAnimatedImage), sd_FLAnimatedImage, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation FLAnimatedImageView (WebCache)
|
||||
|
||||
// These property based options will moved to `SDWebImageContext` in 5.x, to allow per-image-request level options instead of per-imageView-level options
|
||||
- (NSUInteger)sd_optimalFrameCacheSize {
|
||||
NSUInteger optimalFrameCacheSize = 0;
|
||||
NSNumber *value = objc_getAssociatedObject(self, @selector(sd_optimalFrameCacheSize));
|
||||
if ([value isKindOfClass:[NSNumber class]]) {
|
||||
optimalFrameCacheSize = value.unsignedShortValue;
|
||||
}
|
||||
return optimalFrameCacheSize;
|
||||
}
|
||||
|
||||
- (void)setSd_optimalFrameCacheSize:(NSUInteger)sd_optimalFrameCacheSize {
|
||||
objc_setAssociatedObject(self, @selector(sd_optimalFrameCacheSize), @(sd_optimalFrameCacheSize), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
|
||||
- (BOOL)sd_predrawingEnabled {
|
||||
BOOL predrawingEnabled = YES;
|
||||
NSNumber *value = objc_getAssociatedObject(self, @selector(sd_predrawingEnabled));
|
||||
if ([value isKindOfClass:[NSNumber class]]) {
|
||||
predrawingEnabled = value.boolValue;
|
||||
}
|
||||
return predrawingEnabled;
|
||||
}
|
||||
|
||||
- (void)setSd_predrawingEnabled:(BOOL)sd_predrawingEnabled {
|
||||
objc_setAssociatedObject(self, @selector(sd_predrawingEnabled), @(sd_predrawingEnabled), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
|
||||
- (BOOL)sd_cacheFLAnimatedImage {
|
||||
BOOL cacheFLAnimatedImage = YES;
|
||||
NSNumber *value = objc_getAssociatedObject(self, @selector(sd_cacheFLAnimatedImage));
|
||||
if ([value isKindOfClass:[NSNumber class]]) {
|
||||
cacheFLAnimatedImage = value.boolValue;
|
||||
}
|
||||
return cacheFLAnimatedImage;
|
||||
}
|
||||
|
||||
- (void)setSd_cacheFLAnimatedImage:(BOOL)sd_cacheFLAnimatedImage {
|
||||
objc_setAssociatedObject(self, @selector(sd_cacheFLAnimatedImage), @(sd_cacheFLAnimatedImage), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
|
||||
- (void)sd_setImageWithURL:(nullable NSURL *)url {
|
||||
[self sd_setImageWithURL:url placeholderImage:nil options:0 progress:nil completed:nil];
|
||||
}
|
||||
|
||||
- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder {
|
||||
[self sd_setImageWithURL:url placeholderImage:placeholder options:0 progress:nil completed:nil];
|
||||
}
|
||||
|
||||
- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options {
|
||||
[self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:nil];
|
||||
}
|
||||
|
||||
- (void)sd_setImageWithURL:(nullable NSURL *)url completed:(nullable SDExternalCompletionBlock)completedBlock {
|
||||
[self sd_setImageWithURL:url placeholderImage:nil options:0 progress:nil completed:completedBlock];
|
||||
}
|
||||
|
||||
- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder completed:(nullable SDExternalCompletionBlock)completedBlock {
|
||||
[self sd_setImageWithURL:url placeholderImage:placeholder options:0 progress:nil completed:completedBlock];
|
||||
}
|
||||
|
||||
- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options completed:(nullable SDExternalCompletionBlock)completedBlock {
|
||||
[self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:completedBlock];
|
||||
}
|
||||
|
||||
- (void)sd_setImageWithURL:(nullable NSURL *)url
|
||||
placeholderImage:(nullable UIImage *)placeholder
|
||||
options:(SDWebImageOptions)options
|
||||
progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
|
||||
completed:(nullable SDExternalCompletionBlock)completedBlock {
|
||||
dispatch_group_t group = dispatch_group_create();
|
||||
__weak typeof(self)weakSelf = self;
|
||||
[self sd_internalSetImageWithURL:url
|
||||
placeholderImage:placeholder
|
||||
options:options
|
||||
operationKey:nil
|
||||
internalSetImageBlock:^(UIImage * _Nullable image, NSData * _Nullable imageData, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
|
||||
__strong typeof(weakSelf)strongSelf = weakSelf;
|
||||
if (!strongSelf) {
|
||||
dispatch_group_leave(group);
|
||||
return;
|
||||
}
|
||||
// Step 1. Check memory cache (associate object)
|
||||
FLAnimatedImage *associatedAnimatedImage = image.sd_FLAnimatedImage;
|
||||
if (associatedAnimatedImage) {
|
||||
// Asscociated animated image exist
|
||||
// FLAnimatedImage framework contains a bug that cause GIF been rotated if previous rendered image orientation is not Up. We have to call `setImage:` with non-nil image to reset the state. See `https://github.com/SDWebImage/SDWebImage/issues/2402`
|
||||
strongSelf.image = associatedAnimatedImage.posterImage;
|
||||
strongSelf.animatedImage = associatedAnimatedImage;
|
||||
dispatch_group_leave(group);
|
||||
return;
|
||||
}
|
||||
// Step 2. Check if original compressed image data is "GIF"
|
||||
BOOL isGIF = (image.sd_imageFormat == SDImageFormatGIF || [NSData sd_imageFormatForImageData:imageData] == SDImageFormatGIF);
|
||||
// Check if placeholder, which does not trigger a backup disk cache query
|
||||
BOOL isPlaceholder = !imageData && image && cacheType == SDImageCacheTypeNone;
|
||||
if (!isGIF || isPlaceholder) {
|
||||
strongSelf.image = image;
|
||||
strongSelf.animatedImage = nil;
|
||||
dispatch_group_leave(group);
|
||||
return;
|
||||
}
|
||||
__weak typeof(strongSelf) wweakSelf = strongSelf;
|
||||
// Hack, mark we need should use dispatch group notify for completedBlock
|
||||
objc_setAssociatedObject(group, &SDWebImageInternalSetImageGroupKey, @(YES), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
|
||||
__strong typeof(wweakSelf) sstrongSelf = wweakSelf;
|
||||
if (!sstrongSelf || ![url isEqual:sstrongSelf.sd_imageURL]) { return ; }
|
||||
// Step 3. Check if data exist or query disk cache
|
||||
NSString *key = [[SDWebImageManager sharedManager] cacheKeyForURL:url];
|
||||
__block NSData *gifData = imageData;
|
||||
if (!gifData) {
|
||||
gifData = [[SDImageCache sharedImageCache] diskImageDataForKey:key];
|
||||
}
|
||||
// Step 4. Create FLAnimatedImage
|
||||
FLAnimatedImage *animatedImage = SDWebImageCreateFLAnimatedImage(sstrongSelf, gifData);
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (![url isEqual:sstrongSelf.sd_imageURL]) { return ; }
|
||||
// Step 5. Set animatedImage or normal image
|
||||
if (animatedImage) {
|
||||
if (sstrongSelf.sd_cacheFLAnimatedImage && SDImageCache.sharedImageCache.config.shouldCacheImagesInMemory) {
|
||||
image.sd_FLAnimatedImage = animatedImage;
|
||||
image.sd_memoryCost = SDWebImageMemoryCostFLAnimatedImage(animatedImage, image);
|
||||
// Update the memory cache
|
||||
[SDImageCache.sharedImageCache removeImageForKey:key fromDisk:NO withCompletion:nil];
|
||||
[SDImageCache.sharedImageCache storeImage:image forKey:key toDisk:NO completion:nil];
|
||||
}
|
||||
sstrongSelf.image = animatedImage.posterImage;
|
||||
sstrongSelf.animatedImage = animatedImage;
|
||||
} else {
|
||||
sstrongSelf.image = image;
|
||||
sstrongSelf.animatedImage = nil;
|
||||
}
|
||||
dispatch_group_leave(group);
|
||||
});
|
||||
});
|
||||
}
|
||||
progress:progressBlock
|
||||
completed:completedBlock
|
||||
context:@{SDWebImageInternalSetImageGroupKey: group}];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
|
@ -1,57 +0,0 @@
|
|||
/*
|
||||
* This file is part of the SDWebImage package.
|
||||
* (c) Olivier Poitrey <rs@dailymotion.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
#import "MKAnnotationView+WebCache.h"
|
||||
|
||||
#if SD_UIKIT || SD_MAC
|
||||
|
||||
#import "objc/runtime.h"
|
||||
#import "UIView+WebCacheOperation.h"
|
||||
#import "UIView+WebCache.h"
|
||||
|
||||
@implementation MKAnnotationView (WebCache)
|
||||
|
||||
- (void)sd_setImageWithURL:(nullable NSURL *)url {
|
||||
[self sd_setImageWithURL:url placeholderImage:nil options:0 completed:nil];
|
||||
}
|
||||
|
||||
- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder {
|
||||
[self sd_setImageWithURL:url placeholderImage:placeholder options:0 completed:nil];
|
||||
}
|
||||
|
||||
- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options {
|
||||
[self sd_setImageWithURL:url placeholderImage:placeholder options:options completed:nil];
|
||||
}
|
||||
|
||||
- (void)sd_setImageWithURL:(nullable NSURL *)url completed:(nullable SDExternalCompletionBlock)completedBlock {
|
||||
[self sd_setImageWithURL:url placeholderImage:nil options:0 completed:completedBlock];
|
||||
}
|
||||
|
||||
- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder completed:(nullable SDExternalCompletionBlock)completedBlock {
|
||||
[self sd_setImageWithURL:url placeholderImage:placeholder options:0 completed:completedBlock];
|
||||
}
|
||||
|
||||
- (void)sd_setImageWithURL:(nullable NSURL *)url
|
||||
placeholderImage:(nullable UIImage *)placeholder
|
||||
options:(SDWebImageOptions)options
|
||||
completed:(nullable SDExternalCompletionBlock)completedBlock {
|
||||
__weak typeof(self)weakSelf = self;
|
||||
[self sd_internalSetImageWithURL:url
|
||||
placeholderImage:placeholder
|
||||
options:options
|
||||
operationKey:nil
|
||||
setImageBlock:^(UIImage *image, NSData *imageData) {
|
||||
weakSelf.image = image;
|
||||
}
|
||||
progress:nil
|
||||
completed:completedBlock];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
|
@ -53,6 +53,22 @@
|
|||
placeholderImage:(nullable UIImage *)placeholder
|
||||
options:(SDWebImageOptions)options NS_REFINED_FOR_SWIFT;
|
||||
|
||||
/**
|
||||
* Set the imageView `image` with an `url`, placeholder, custom options and context.
|
||||
*
|
||||
* The download is asynchronous and cached.
|
||||
*
|
||||
* @param url The url for the image.
|
||||
* @param placeholder The image to be set initially, until the image request finishes.
|
||||
* @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values.
|
||||
* @param context A context contains different options to perform specify changes or processes, see `SDWebImageContextOption`. This hold the extra objects which `options` enum can not hold.
|
||||
*/
|
||||
|
||||
- (void)sd_setImageWithURL:(nullable NSURL *)url
|
||||
placeholderImage:(nullable UIImage *)placeholder
|
||||
options:(SDWebImageOptions)options
|
||||
context:(nullable SDWebImageContext *)context;
|
||||
|
||||
/**
|
||||
* Set the imageView `image` with an `url`.
|
||||
*
|
||||
|
@ -104,6 +120,52 @@
|
|||
options:(SDWebImageOptions)options
|
||||
completed:(nullable SDExternalCompletionBlock)completedBlock;
|
||||
|
||||
/**
|
||||
* Set the imageView `image` with an `url`, placeholder and custom options.
|
||||
*
|
||||
* The download is asynchronous and cached.
|
||||
*
|
||||
* @param url The url for the image.
|
||||
* @param placeholder The image to be set initially, until the image request finishes.
|
||||
* @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values.
|
||||
* @param progressBlock A block called while image is downloading
|
||||
* @note the progress block is executed on a background queue
|
||||
* @param completedBlock A block called when operation has been completed. This block has no return value
|
||||
* and takes the requested UIImage as first parameter. In case of error the image parameter
|
||||
* is nil and the second parameter may contain an NSError. The third parameter is a Boolean
|
||||
* indicating if the image was retrieved from the local cache or from the network.
|
||||
* The fourth parameter is the original image url.
|
||||
*/
|
||||
- (void)sd_setImageWithURL:(nullable NSURL *)url
|
||||
placeholderImage:(nullable UIImage *)placeholder
|
||||
options:(SDWebImageOptions)options
|
||||
progress:(nullable SDImageLoaderProgressBlock)progressBlock
|
||||
completed:(nullable SDExternalCompletionBlock)completedBlock;
|
||||
|
||||
/**
|
||||
* Set the imageView `image` with an `url`, placeholder, custom options and context.
|
||||
*
|
||||
* The download is asynchronous and cached.
|
||||
*
|
||||
* @param url The url for the image.
|
||||
* @param placeholder The image to be set initially, until the image request finishes.
|
||||
* @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values.
|
||||
* @param context A context contains different options to perform specify changes or processes, see `SDWebImageContextOption`. This hold the extra objects which `options` enum can not hold.
|
||||
* @param progressBlock A block called while image is downloading
|
||||
* @note the progress block is executed on a background queue
|
||||
* @param completedBlock A block called when operation has been completed. This block has no return value
|
||||
* and takes the requested UIImage as first parameter. In case of error the image parameter
|
||||
* is nil and the second parameter may contain an NSError. The third parameter is a Boolean
|
||||
* indicating if the image was retrieved from the local cache or from the network.
|
||||
* The fourth parameter is the original image url.
|
||||
*/
|
||||
- (void)sd_setImageWithURL:(nullable NSURL *)url
|
||||
placeholderImage:(nullable UIImage *)placeholder
|
||||
options:(SDWebImageOptions)options
|
||||
context:(nullable SDWebImageContext *)context
|
||||
progress:(nullable SDImageLoaderProgressBlock)progressBlock
|
||||
completed:(nullable SDExternalCompletionBlock)completedBlock;
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* This file is part of the SDWebImage package.
|
||||
* (c) Olivier Poitrey <rs@dailymotion.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
#import "MKAnnotationView+WebCache.h"
|
||||
|
||||
#if SD_UIKIT || SD_MAC
|
||||
|
||||
#import "objc/runtime.h"
|
||||
#import "UIView+WebCacheOperation.h"
|
||||
#import "UIView+WebCache.h"
|
||||
|
||||
@implementation MKAnnotationView (WebCache)
|
||||
|
||||
- (void)sd_setImageWithURL:(nullable NSURL *)url {
|
||||
[self sd_setImageWithURL:url placeholderImage:nil options:0 completed:nil];
|
||||
}
|
||||
|
||||
- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder {
|
||||
[self sd_setImageWithURL:url placeholderImage:placeholder options:0 completed:nil];
|
||||
}
|
||||
|
||||
- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options {
|
||||
[self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:nil];
|
||||
}
|
||||
|
||||
- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options context:(nullable SDWebImageContext *)context {
|
||||
[self sd_setImageWithURL:url placeholderImage:placeholder options:options context:context progress:nil completed:nil];
|
||||
}
|
||||
|
||||
- (void)sd_setImageWithURL:(nullable NSURL *)url completed:(nullable SDExternalCompletionBlock)completedBlock {
|
||||
[self sd_setImageWithURL:url placeholderImage:nil options:0 completed:completedBlock];
|
||||
}
|
||||
|
||||
- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder completed:(nullable SDExternalCompletionBlock)completedBlock {
|
||||
[self sd_setImageWithURL:url placeholderImage:placeholder options:0 completed:completedBlock];
|
||||
}
|
||||
|
||||
- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options completed:(nullable SDExternalCompletionBlock)completedBlock {
|
||||
[self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:completedBlock];
|
||||
}
|
||||
|
||||
- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock {
|
||||
[self sd_setImageWithURL:url placeholderImage:placeholder options:options context:nil progress:progressBlock completed:completedBlock];
|
||||
}
|
||||
|
||||
- (void)sd_setImageWithURL:(nullable NSURL *)url
|
||||
placeholderImage:(nullable UIImage *)placeholder
|
||||
options:(SDWebImageOptions)options
|
||||
context:(nullable SDWebImageContext *)context
|
||||
progress:(nullable SDImageLoaderProgressBlock)progressBlock
|
||||
completed:(nullable SDExternalCompletionBlock)completedBlock {
|
||||
@weakify(self);
|
||||
[self sd_internalSetImageWithURL:url
|
||||
placeholderImage:placeholder
|
||||
options:options
|
||||
context:context
|
||||
setImageBlock:^(UIImage * _Nullable image, NSData * _Nullable imageData, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
|
||||
@strongify(self);
|
||||
self.image = image;
|
||||
}
|
||||
progress:progressBlock
|
||||
completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) {
|
||||
if (completedBlock) {
|
||||
completedBlock(image, error, cacheType, imageURL);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
|
@ -19,7 +19,7 @@
|
|||
/**
|
||||
* Get the current image URL.
|
||||
*/
|
||||
- (nullable NSURL *)sd_currentImageURL;
|
||||
@property (nonatomic, strong, readonly, nullable) NSURL *sd_currentImageURL;
|
||||
|
||||
/**
|
||||
* Set the button `image` with an `url`.
|
||||
|
@ -55,6 +55,21 @@
|
|||
placeholderImage:(nullable UIImage *)placeholder
|
||||
options:(SDWebImageOptions)options NS_REFINED_FOR_SWIFT;
|
||||
|
||||
/**
|
||||
* Set the button `image` with an `url`, placeholder and custom options.
|
||||
*
|
||||
* The download is asynchronous and cached.
|
||||
*
|
||||
* @param url The url for the image.
|
||||
* @param placeholder The image to be set initially, until the image request finishes.
|
||||
* @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values.
|
||||
* @param context A context contains different options to perform specify changes or processes, see `SDWebImageContextOption`. This hold the extra objects which `options` enum can not hold.
|
||||
*/
|
||||
- (void)sd_setImageWithURL:(nullable NSURL *)url
|
||||
placeholderImage:(nullable UIImage *)placeholder
|
||||
options:(SDWebImageOptions)options
|
||||
context:(nullable SDWebImageContext *)context;
|
||||
|
||||
/**
|
||||
* Set the button `image` with an `url`.
|
||||
*
|
||||
|
@ -125,7 +140,31 @@
|
|||
- (void)sd_setImageWithURL:(nullable NSURL *)url
|
||||
placeholderImage:(nullable UIImage *)placeholder
|
||||
options:(SDWebImageOptions)options
|
||||
progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
|
||||
progress:(nullable SDImageLoaderProgressBlock)progressBlock
|
||||
completed:(nullable SDExternalCompletionBlock)completedBlock;
|
||||
|
||||
/**
|
||||
* Set the button `image` with an `url`, placeholder and custom options.
|
||||
*
|
||||
* The download is asynchronous and cached.
|
||||
*
|
||||
* @param url The url for the image.
|
||||
* @param placeholder The image to be set initially, until the image request finishes.
|
||||
* @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values.
|
||||
* @param context A context contains different options to perform specify changes or processes, see `SDWebImageContextOption`. This hold the extra objects which `options` enum can not hold.
|
||||
* @param progressBlock A block called while image is downloading
|
||||
* @note the progress block is executed on a background queue
|
||||
* @param completedBlock A block called when operation has been completed. This block has no return value
|
||||
* and takes the requested UIImage as first parameter. In case of error the image parameter
|
||||
* is nil and the second parameter may contain an NSError. The third parameter is a Boolean
|
||||
* indicating if the image was retrieved from the local cache or from the network.
|
||||
* The fourth parameter is the original image url.
|
||||
*/
|
||||
- (void)sd_setImageWithURL:(nullable NSURL *)url
|
||||
placeholderImage:(nullable UIImage *)placeholder
|
||||
options:(SDWebImageOptions)options
|
||||
context:(nullable SDWebImageContext *)context
|
||||
progress:(nullable SDImageLoaderProgressBlock)progressBlock
|
||||
completed:(nullable SDExternalCompletionBlock)completedBlock;
|
||||
|
||||
#pragma mark - Alternate Image
|
||||
|
@ -133,7 +172,7 @@
|
|||
/**
|
||||
* Get the current alternateImage URL.
|
||||
*/
|
||||
- (nullable NSURL *)sd_currentAlternateImageURL;
|
||||
@property (nonatomic, strong, readonly, nullable) NSURL *sd_currentAlternateImageURL;
|
||||
|
||||
/**
|
||||
* Set the button `alternateImage` with an `url`.
|
||||
|
@ -169,6 +208,21 @@
|
|||
placeholderImage:(nullable UIImage *)placeholder
|
||||
options:(SDWebImageOptions)options NS_REFINED_FOR_SWIFT;
|
||||
|
||||
/**
|
||||
* Set the button `alternateImage` with an `url`, placeholder, custom options and context.
|
||||
*
|
||||
* The download is asynchronous and cached.
|
||||
*
|
||||
* @param url The url for the alternateImage.
|
||||
* @param placeholder The alternateImage to be set initially, until the alternateImage request finishes.
|
||||
* @param options The options to use when downloading the alternateImage. @see SDWebImageOptions for the possible values.
|
||||
* @param context A context contains different options to perform specify changes or processes, see `SDWebImageContextOption`. This hold the extra objects which `options` enum can not hold.
|
||||
*/
|
||||
- (void)sd_setAlternateImageWithURL:(nullable NSURL *)url
|
||||
placeholderImage:(nullable UIImage *)placeholder
|
||||
options:(SDWebImageOptions)options
|
||||
context:(nullable SDWebImageContext *)context;
|
||||
|
||||
/**
|
||||
* Set the button `alternateImage` with an `url`.
|
||||
*
|
||||
|
@ -239,7 +293,31 @@
|
|||
- (void)sd_setAlternateImageWithURL:(nullable NSURL *)url
|
||||
placeholderImage:(nullable UIImage *)placeholder
|
||||
options:(SDWebImageOptions)options
|
||||
progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
|
||||
progress:(nullable SDImageLoaderProgressBlock)progressBlock
|
||||
completed:(nullable SDExternalCompletionBlock)completedBlock;
|
||||
|
||||
/**
|
||||
* Set the button `alternateImage` with an `url`, placeholder, custom options and context.
|
||||
*
|
||||
* The download is asynchronous and cached.
|
||||
*
|
||||
* @param url The url for the alternateImage.
|
||||
* @param placeholder The alternateImage to be set initially, until the alternateImage request finishes.
|
||||
* @param options The options to use when downloading the alternateImage. @see SDWebImageOptions for the possible values.
|
||||
* @param context A context contains different options to perform specify changes or processes, see `SDWebImageContextOption`. This hold the extra objects which `options` enum can not hold.
|
||||
* @param progressBlock A block called while alternateImage is downloading
|
||||
* @note the progress block is executed on a background queue
|
||||
* @param completedBlock A block called when operation has been completed. This block has no return value
|
||||
* and takes the requested UIImage as first parameter. In case of error the alternateImage parameter
|
||||
* is nil and the second parameter may contain an NSError. The third parameter is a Boolean
|
||||
* indicating if the alternateImage was retrieved from the local cache or from the network.
|
||||
* The fourth parameter is the original alternateImage url.
|
||||
*/
|
||||
- (void)sd_setAlternateImageWithURL:(nullable NSURL *)url
|
||||
placeholderImage:(nullable UIImage *)placeholder
|
||||
options:(SDWebImageOptions)options
|
||||
context:(nullable SDWebImageContext *)context
|
||||
progress:(nullable SDImageLoaderProgressBlock)progressBlock
|
||||
completed:(nullable SDExternalCompletionBlock)completedBlock;
|
||||
|
||||
#pragma mark - Cancel
|
||||
|
|
|
@ -14,13 +14,7 @@
|
|||
#import "UIView+WebCacheOperation.h"
|
||||
#import "UIView+WebCache.h"
|
||||
|
||||
static inline NSString * imageOperationKey() {
|
||||
return @"NSButtonImageOperation";
|
||||
}
|
||||
|
||||
static inline NSString * alternateImageOperationKey() {
|
||||
return @"NSButtonAlternateImageOperation";
|
||||
}
|
||||
static NSString * const SDAlternateImageOperationKey = @"NSButtonAlternateImageOperation";
|
||||
|
||||
@implementation NSButton (WebCache)
|
||||
|
||||
|
@ -38,6 +32,10 @@ static inline NSString * alternateImageOperationKey() {
|
|||
[self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:nil];
|
||||
}
|
||||
|
||||
- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options context:(nullable SDWebImageContext *)context {
|
||||
[self sd_setImageWithURL:url placeholderImage:placeholder options:options context:context progress:nil completed:nil];
|
||||
}
|
||||
|
||||
- (void)sd_setImageWithURL:(nullable NSURL *)url completed:(nullable SDExternalCompletionBlock)completedBlock {
|
||||
[self sd_setImageWithURL:url placeholderImage:nil options:0 progress:nil completed:completedBlock];
|
||||
}
|
||||
|
@ -50,23 +48,28 @@ static inline NSString * alternateImageOperationKey() {
|
|||
[self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:completedBlock];
|
||||
}
|
||||
|
||||
- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock {
|
||||
[self sd_setImageWithURL:url placeholderImage:placeholder options:options context:nil progress:progressBlock completed:completedBlock];
|
||||
}
|
||||
|
||||
- (void)sd_setImageWithURL:(nullable NSURL *)url
|
||||
placeholderImage:(nullable UIImage *)placeholder
|
||||
options:(SDWebImageOptions)options
|
||||
progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
|
||||
context:(nullable SDWebImageContext *)context
|
||||
progress:(nullable SDImageLoaderProgressBlock)progressBlock
|
||||
completed:(nullable SDExternalCompletionBlock)completedBlock {
|
||||
self.sd_currentImageURL = url;
|
||||
|
||||
__weak typeof(self)weakSelf = self;
|
||||
[self sd_internalSetImageWithURL:url
|
||||
placeholderImage:placeholder
|
||||
options:options
|
||||
operationKey:imageOperationKey()
|
||||
setImageBlock:^(NSImage * _Nullable image, NSData * _Nullable imageData) {
|
||||
weakSelf.image = image;
|
||||
}
|
||||
context:context
|
||||
setImageBlock:nil
|
||||
progress:progressBlock
|
||||
completed:completedBlock];
|
||||
completed:^(NSImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) {
|
||||
if (completedBlock) {
|
||||
completedBlock(image, error, cacheType, imageURL);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - Alternate Image
|
||||
|
@ -83,6 +86,10 @@ static inline NSString * alternateImageOperationKey() {
|
|||
[self sd_setAlternateImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:nil];
|
||||
}
|
||||
|
||||
- (void)sd_setAlternateImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options context:(nullable SDWebImageContext *)context {
|
||||
[self sd_setAlternateImageWithURL:url placeholderImage:placeholder options:options context:context progress:nil completed:nil];
|
||||
}
|
||||
|
||||
- (void)sd_setAlternateImageWithURL:(nullable NSURL *)url completed:(nullable SDExternalCompletionBlock)completedBlock {
|
||||
[self sd_setAlternateImageWithURL:url placeholderImage:nil options:0 progress:nil completed:completedBlock];
|
||||
}
|
||||
|
@ -95,33 +102,50 @@ static inline NSString * alternateImageOperationKey() {
|
|||
[self sd_setAlternateImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:completedBlock];
|
||||
}
|
||||
|
||||
- (void)sd_setAlternateImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock {
|
||||
[self sd_setAlternateImageWithURL:url placeholderImage:placeholder options:options context:nil progress:progressBlock completed:completedBlock];
|
||||
}
|
||||
|
||||
- (void)sd_setAlternateImageWithURL:(nullable NSURL *)url
|
||||
placeholderImage:(nullable UIImage *)placeholder
|
||||
options:(SDWebImageOptions)options
|
||||
progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
|
||||
context:(nullable SDWebImageContext *)context
|
||||
progress:(nullable SDImageLoaderProgressBlock)progressBlock
|
||||
completed:(nullable SDExternalCompletionBlock)completedBlock {
|
||||
self.sd_currentAlternateImageURL = url;
|
||||
|
||||
__weak typeof(self)weakSelf = self;
|
||||
SDWebImageMutableContext *mutableContext;
|
||||
if (context) {
|
||||
mutableContext = [context mutableCopy];
|
||||
} else {
|
||||
mutableContext = [NSMutableDictionary dictionary];
|
||||
}
|
||||
mutableContext[SDWebImageContextSetImageOperationKey] = SDAlternateImageOperationKey;
|
||||
@weakify(self);
|
||||
[self sd_internalSetImageWithURL:url
|
||||
placeholderImage:placeholder
|
||||
options:options
|
||||
operationKey:alternateImageOperationKey()
|
||||
setImageBlock:^(NSImage * _Nullable image, NSData * _Nullable imageData) {
|
||||
weakSelf.alternateImage = image;
|
||||
context:mutableContext
|
||||
setImageBlock:^(NSImage * _Nullable image, NSData * _Nullable imageData, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
|
||||
@strongify(self);
|
||||
self.alternateImage = image;
|
||||
}
|
||||
progress:progressBlock
|
||||
completed:completedBlock];
|
||||
completed:^(NSImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) {
|
||||
if (completedBlock) {
|
||||
completedBlock(image, error, cacheType, imageURL);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - Cancel
|
||||
|
||||
- (void)sd_cancelCurrentImageLoad {
|
||||
[self sd_cancelImageLoadOperationWithKey:imageOperationKey()];
|
||||
[self sd_cancelImageLoadOperationWithKey:NSStringFromClass([self class])];
|
||||
}
|
||||
|
||||
- (void)sd_cancelCurrentAlternateImageLoad {
|
||||
[self sd_cancelImageLoadOperationWithKey:alternateImageOperationKey()];
|
||||
[self sd_cancelImageLoadOperationWithKey:SDAlternateImageOperationKey];
|
||||
}
|
||||
|
||||
#pragma mar - Private
|
||||
|
|
|
@ -10,16 +10,19 @@
|
|||
#import <Foundation/Foundation.h>
|
||||
#import "SDWebImageCompat.h"
|
||||
|
||||
typedef NS_ENUM(NSInteger, SDImageFormat) {
|
||||
SDImageFormatUndefined = -1,
|
||||
SDImageFormatJPEG = 0,
|
||||
SDImageFormatPNG,
|
||||
SDImageFormatGIF,
|
||||
SDImageFormatTIFF,
|
||||
SDImageFormatWebP,
|
||||
SDImageFormatHEIC,
|
||||
SDImageFormatHEIF
|
||||
};
|
||||
/**
|
||||
You can use switch case like normal enum. It's also recommended to add a default case. You should not assume anything about the raw value.
|
||||
For custom coder plugin, it can also extern the enum for supported format. See `SDImageCoder` for more detailed information.
|
||||
*/
|
||||
typedef NSInteger SDImageFormat NS_TYPED_EXTENSIBLE_ENUM;
|
||||
static const SDImageFormat SDImageFormatUndefined = -1;
|
||||
static const SDImageFormat SDImageFormatJPEG = 0;
|
||||
static const SDImageFormat SDImageFormatPNG = 1;
|
||||
static const SDImageFormat SDImageFormatGIF = 2;
|
||||
static const SDImageFormat SDImageFormatTIFF = 3;
|
||||
static const SDImageFormat SDImageFormatWebP = 4;
|
||||
static const SDImageFormat SDImageFormatHEIC = 5;
|
||||
static const SDImageFormat SDImageFormatHEIF = 6;
|
||||
|
||||
@interface NSData (ImageContentType)
|
||||
|
||||
|
@ -38,7 +41,7 @@ typedef NS_ENUM(NSInteger, SDImageFormat) {
|
|||
* @param format Format as SDImageFormat
|
||||
* @return The UTType as CFStringRef
|
||||
*/
|
||||
+ (nonnull CFStringRef)sd_UTTypeFromSDImageFormat:(SDImageFormat)format;
|
||||
+ (nonnull CFStringRef)sd_UTTypeFromImageFormat:(SDImageFormat)format CF_RETURNS_NOT_RETAINED NS_SWIFT_NAME(sd_UTType(from:));
|
||||
|
||||
/**
|
||||
* Convert UTTyppe to SDImageFormat
|
||||
|
|
|
@ -60,6 +60,7 @@
|
|||
|| [testString isEqualToString:@"ftyphevx"]) {
|
||||
return SDImageFormatHEIC;
|
||||
}
|
||||
//....ftypmif1 ....ftypmsf1
|
||||
if ([testString isEqualToString:@"ftypmif1"] || [testString isEqualToString:@"ftypmsf1"]) {
|
||||
return SDImageFormatHEIF;
|
||||
}
|
||||
|
@ -70,7 +71,7 @@
|
|||
return SDImageFormatUndefined;
|
||||
}
|
||||
|
||||
+ (nonnull CFStringRef)sd_UTTypeFromSDImageFormat:(SDImageFormat)format {
|
||||
+ (nonnull CFStringRef)sd_UTTypeFromImageFormat:(SDImageFormat)format {
|
||||
CFStringRef UTType;
|
||||
switch (format) {
|
||||
case SDImageFormatJPEG:
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* This file is part of the SDWebImage package.
|
||||
* (c) Olivier Poitrey <rs@dailymotion.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
#import "SDWebImageCompat.h"
|
||||
|
||||
// This category is provided to easily write cross-platform(AppKit/UIKit) code. For common usage, see `UIImage+Metadata.h`.
|
||||
|
||||
#if SD_MAC
|
||||
|
||||
@interface NSImage (Compatibility)
|
||||
|
||||
/**
|
||||
The underlying Core Graphics image object. This will actually use `CGImageForProposedRect` with the image size.
|
||||
*/
|
||||
@property (nonatomic, readonly, nullable) CGImageRef CGImage;
|
||||
/**
|
||||
The scale factor of the image. This wil actually use `bestRepresentationForRect` with image size and pixel size to calculate the scale factor. If failed, use the default value 1.0. Should be greater than or equal to 1.0.
|
||||
*/
|
||||
@property (nonatomic, readonly) CGFloat scale;
|
||||
|
||||
// These are convenience methods to make AppKit's `NSImage` match UIKit's `UIImage` behavior. The scale factor should be greater than or equal to 1.0.
|
||||
|
||||
/**
|
||||
Returns an image object with the scale factor and orientation. The representation is created from the Core Graphics image object.
|
||||
@note The difference between this and `initWithCGImage:size` is that `initWithCGImage:size` will actually create a `NSCGImageSnapshotRep` representation and always use `backingScaleFactor` as scale factor. So we should avoid it and use `NSBitmapImageRep` with `initWithCGImage:` instead.
|
||||
@note The difference between this and UIKit's `UIImage` equivalent method is the way to process orientation. If the provided image orientation is not equal to Up orientation, this method will firstly rotate the CGImage to the correct orientation to work compatible with `NSImageView`. However, UIKit will not actually rotate CGImage and just store it as `imageOrientation` property.
|
||||
|
||||
@param cgImage A Core Graphics image object
|
||||
@param scale The image scale factor
|
||||
@param orientation The orientation of the image data
|
||||
@return The image object
|
||||
*/
|
||||
- (nonnull instancetype)initWithCGImage:(nonnull CGImageRef)cgImage scale:(CGFloat)scale orientation:(CGImagePropertyOrientation)orientation;
|
||||
|
||||
/**
|
||||
Returns an image object with the scale factor. The representation is created from the image data.
|
||||
@note The difference between these this and `initWithData:` is that `initWithData:` will always use `backingScaleFactor` as scale factor.
|
||||
|
||||
@param data The image data
|
||||
@param scale The image scale factor
|
||||
@return The image object
|
||||
*/
|
||||
- (nullable instancetype)initWithData:(nonnull NSData *)data scale:(CGFloat)scale;
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* This file is part of the SDWebImage package.
|
||||
* (c) Olivier Poitrey <rs@dailymotion.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
#import "NSImage+Compatibility.h"
|
||||
|
||||
#if SD_MAC
|
||||
|
||||
#import "SDImageCoderHelper.h"
|
||||
|
||||
@implementation NSImage (Compatibility)
|
||||
|
||||
- (CGImageRef)CGImage {
|
||||
NSRect imageRect = NSMakeRect(0, 0, self.size.width, self.size.height);
|
||||
CGImageRef cgImage = [self CGImageForProposedRect:&imageRect context:nil hints:nil];
|
||||
return cgImage;
|
||||
}
|
||||
|
||||
- (CGFloat)scale {
|
||||
CGFloat scale = 1;
|
||||
NSRect imageRect = NSMakeRect(0, 0, self.size.width, self.size.height);
|
||||
NSImageRep *imageRep = [self bestRepresentationForRect:imageRect context:nil hints:nil];
|
||||
CGFloat width = imageRep.size.width;
|
||||
CGFloat height = imageRep.size.height;
|
||||
NSUInteger pixelWidth = imageRep.pixelsWide;
|
||||
NSUInteger pixelHeight = imageRep.pixelsHigh;
|
||||
if (width > 0 && height > 0) {
|
||||
CGFloat widthScale = pixelWidth / width;
|
||||
CGFloat heightScale = pixelHeight / height;
|
||||
if (widthScale == heightScale && widthScale >= 1) {
|
||||
// Protect because there may be `NSImageRepMatchesDevice` (0)
|
||||
scale = widthScale;
|
||||
}
|
||||
}
|
||||
|
||||
return scale;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCGImage:(CGImageRef)cgImage scale:(CGFloat)scale orientation:(CGImagePropertyOrientation)orientation {
|
||||
NSBitmapImageRep *imageRep;
|
||||
if (orientation != kCGImagePropertyOrientationUp) {
|
||||
// AppKit design is different from UIKit. Where CGImage based image rep does not respect to any orientation. Only data based image rep which contains the EXIF metadata can automatically detect orientation.
|
||||
// This should be nonnull, until the memory is exhausted cause `CGBitmapContextCreate` failed.
|
||||
CGImageRef rotatedCGImage = [SDImageCoderHelper CGImageCreateDecoded:cgImage orientation:orientation];
|
||||
imageRep = [[NSBitmapImageRep alloc] initWithCGImage:rotatedCGImage];
|
||||
CGImageRelease(rotatedCGImage);
|
||||
} else {
|
||||
imageRep = [[NSBitmapImageRep alloc] initWithCGImage:cgImage];
|
||||
}
|
||||
if (scale < 1) {
|
||||
scale = 1;
|
||||
}
|
||||
CGFloat pixelWidth = imageRep.pixelsWide;
|
||||
CGFloat pixelHeight = imageRep.pixelsHigh;
|
||||
NSSize size = NSMakeSize(pixelWidth / scale, pixelHeight / scale);
|
||||
self = [self initWithSize:size];
|
||||
if (self) {
|
||||
imageRep.size = size;
|
||||
[self addRepresentation:imageRep];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithData:(NSData *)data scale:(CGFloat)scale {
|
||||
NSBitmapImageRep *imageRep = [[NSBitmapImageRep alloc] initWithData:data];
|
||||
if (!imageRep) {
|
||||
return nil;
|
||||
}
|
||||
if (scale < 1) {
|
||||
scale = 1;
|
||||
}
|
||||
CGFloat pixelWidth = imageRep.pixelsWide;
|
||||
CGFloat pixelHeight = imageRep.pixelsHigh;
|
||||
NSSize size = NSMakeSize(pixelWidth / scale, pixelHeight / scale);
|
||||
self = [self initWithSize:size];
|
||||
if (self) {
|
||||
imageRep.size = size;
|
||||
[self addRepresentation:imageRep];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
|
@ -1,41 +0,0 @@
|
|||
/*
|
||||
* This file is part of the SDWebImage package.
|
||||
* (c) Olivier Poitrey <rs@dailymotion.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
#import "NSImage+WebCache.h"
|
||||
|
||||
#if SD_MAC
|
||||
|
||||
@implementation NSImage (WebCache)
|
||||
|
||||
- (CGImageRef)CGImage {
|
||||
NSRect imageRect = NSMakeRect(0, 0, self.size.width, self.size.height);
|
||||
CGImageRef cgImage = [self CGImageForProposedRect:&imageRect context:NULL hints:nil];
|
||||
return cgImage;
|
||||
}
|
||||
|
||||
- (NSArray<NSImage *> *)images {
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (BOOL)isGIF {
|
||||
BOOL isGIF = NO;
|
||||
for (NSImageRep *rep in self.representations) {
|
||||
if ([rep isKindOfClass:[NSBitmapImageRep class]]) {
|
||||
NSBitmapImageRep *bitmapRep = (NSBitmapImageRep *)rep;
|
||||
NSUInteger frameCount = [[bitmapRep valueForProperty:NSImageFrameCount] unsignedIntegerValue];
|
||||
isGIF = frameCount > 1 ? YES : NO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return isGIF;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* This file is part of the SDWebImage package.
|
||||
* (c) Olivier Poitrey <rs@dailymotion.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
#import "SDWebImageCompat.h"
|
||||
|
||||
#if SD_MAC
|
||||
|
||||
#import "UIImage+Transform.h"
|
||||
|
||||
@interface NSBezierPath (RoundedCorners)
|
||||
|
||||
/**
|
||||
Convenience way to create a bezier path with the specify rounding corners on macOS. Same as the one on `UIBezierPath`.
|
||||
*/
|
||||
+ (nonnull instancetype)sd_bezierPathWithRoundedRect:(NSRect)rect byRoundingCorners:(SDRectCorner)corners cornerRadius:(CGFloat)cornerRadius;
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* This file is part of the SDWebImage package.
|
||||
* (c) Olivier Poitrey <rs@dailymotion.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
#import "NSBezierPath+RoundedCorners.h"
|
||||
|
||||
#if SD_MAC
|
||||
|
||||
@implementation NSBezierPath (RoundedCorners)
|
||||
|
||||
+ (instancetype)sd_bezierPathWithRoundedRect:(NSRect)rect byRoundingCorners:(SDRectCorner)corners cornerRadius:(CGFloat)cornerRadius {
|
||||
NSBezierPath *path = [NSBezierPath bezierPath];
|
||||
|
||||
CGFloat maxCorner = MIN(NSWidth(rect), NSHeight(rect)) / 2;
|
||||
|
||||
CGFloat topLeftRadius = MIN(maxCorner, (corners & SDRectCornerTopLeft) ? cornerRadius : 0);
|
||||
CGFloat topRightRadius = MIN(maxCorner, (corners & SDRectCornerTopRight) ? cornerRadius : 0);
|
||||
CGFloat bottomLeftRadius = MIN(maxCorner, (corners & SDRectCornerBottomLeft) ? cornerRadius : 0);
|
||||
CGFloat bottomRightRadius = MIN(maxCorner, (corners & SDRectCornerBottomRight) ? cornerRadius : 0);
|
||||
|
||||
NSPoint topLeft = NSMakePoint(NSMinX(rect), NSMaxY(rect));
|
||||
NSPoint topRight = NSMakePoint(NSMaxX(rect), NSMaxY(rect));
|
||||
NSPoint bottomLeft = NSMakePoint(NSMinX(rect), NSMinY(rect));
|
||||
NSPoint bottomRight = NSMakePoint(NSMaxX(rect), NSMinY(rect));
|
||||
|
||||
[path moveToPoint:NSMakePoint(NSMidX(rect), NSMaxY(rect))];
|
||||
[path appendBezierPathWithArcFromPoint:topLeft toPoint:bottomLeft radius:topLeftRadius];
|
||||
[path appendBezierPathWithArcFromPoint:bottomLeft toPoint:bottomRight radius:bottomLeftRadius];
|
||||
[path appendBezierPathWithArcFromPoint:bottomRight toPoint:topRight radius:bottomRightRadius];
|
||||
[path appendBezierPathWithArcFromPoint:topRight toPoint:topLeft radius:topRightRadius];
|
||||
[path closePath];
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* This file is part of the SDWebImage package.
|
||||
* (c) Olivier Poitrey <rs@dailymotion.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
#import "SDWebImageCompat.h"
|
||||
|
||||
@class SDAsyncBlockOperation;
|
||||
typedef void (^SDAsyncBlock)(SDAsyncBlockOperation * __nonnull asyncOperation);
|
||||
|
||||
@interface SDAsyncBlockOperation : NSOperation
|
||||
|
||||
- (nonnull instancetype)initWithBlock:(nonnull SDAsyncBlock)block;
|
||||
+ (nonnull instancetype)blockOperationWithBlock:(nonnull SDAsyncBlock)block;
|
||||
- (void)complete;
|
||||
|
||||
@end
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* This file is part of the SDWebImage package.
|
||||
* (c) Olivier Poitrey <rs@dailymotion.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
#import "SDAsyncBlockOperation.h"
|
||||
|
||||
@interface SDAsyncBlockOperation ()
|
||||
|
||||
@property (assign, nonatomic, getter = isExecuting) BOOL executing;
|
||||
@property (assign, nonatomic, getter = isFinished) BOOL finished;
|
||||
@property (nonatomic, copy, nonnull) SDAsyncBlock executionBlock;
|
||||
|
||||
@end
|
||||
|
||||
@implementation SDAsyncBlockOperation
|
||||
|
||||
@synthesize executing = _executing;
|
||||
@synthesize finished = _finished;
|
||||
|
||||
- (nonnull instancetype)initWithBlock:(nonnull SDAsyncBlock)block {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.executionBlock = block;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (nonnull instancetype)blockOperationWithBlock:(nonnull SDAsyncBlock)block {
|
||||
SDAsyncBlockOperation *operation = [[SDAsyncBlockOperation alloc] initWithBlock:block];
|
||||
return operation;
|
||||
}
|
||||
|
||||
- (void)start {
|
||||
if (self.isCancelled) {
|
||||
return;
|
||||
}
|
||||
|
||||
[self willChangeValueForKey:@"isExecuting"];
|
||||
self.executing = YES;
|
||||
[self didChangeValueForKey:@"isExecuting"];
|
||||
|
||||
if (self.executionBlock) {
|
||||
self.executionBlock(self);
|
||||
} else {
|
||||
[self complete];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)cancel {
|
||||
[super cancel];
|
||||
[self complete];
|
||||
}
|
||||
|
||||
- (void)complete {
|
||||
[self willChangeValueForKey:@"isExecuting"];
|
||||
[self willChangeValueForKey:@"isFinished"];
|
||||
self.executing = NO;
|
||||
self.finished = YES;
|
||||
[self didChangeValueForKey:@"isExecuting"];
|
||||
[self didChangeValueForKey:@"isFinished"];
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* This file is part of the SDWebImage package.
|
||||
* (c) Olivier Poitrey <rs@dailymotion.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
#import "SDWebImageCompat.h"
|
||||
#import "SDImageAPNGCoder.h"
|
||||
|
||||
@interface SDImageAPNGCoder ()
|
||||
|
||||
- (float)sd_frameDurationAtIndex:(NSUInteger)index source:(nonnull CGImageSourceRef)source;
|
||||
- (NSUInteger)sd_imageLoopCountWithSource:(nonnull CGImageSourceRef)source;
|
||||
|
||||
@end
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* This file is part of the SDWebImage package.
|
||||
* (c) Olivier Poitrey <rs@dailymotion.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "SDWebImageCompat.h"
|
||||
|
||||
// Apple parse the Asset Catalog compiled file(`Assets.car`) by CoreUI.framework, however it's a private framework and there are no other ways to directly get the data. So we just process the normal bundle files :)
|
||||
|
||||
@interface SDImageAssetManager : NSObject
|
||||
|
||||
@property (nonatomic, strong, nonnull) NSMapTable<NSString *, UIImage *> *imageTable;
|
||||
|
||||
+ (nonnull instancetype)sharedAssetManager;
|
||||
- (nullable NSString *)getPathForName:(nonnull NSString *)name bundle:(nonnull NSBundle *)bundle preferredScale:(nonnull CGFloat *)scale;
|
||||
- (nullable UIImage *)imageForName:(nonnull NSString *)name;
|
||||
- (void)storeImage:(nonnull UIImage *)image forName:(nonnull NSString *)name;
|
||||
|
||||
@end
|
|
@ -0,0 +1,157 @@
|
|||
/*
|
||||
* This file is part of the SDWebImage package.
|
||||
* (c) Olivier Poitrey <rs@dailymotion.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
#import "SDImageAssetManager.h"
|
||||
|
||||
static NSArray *SDBundlePreferredScales() {
|
||||
static NSArray *scales;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
#if SD_WATCH
|
||||
CGFloat screenScale = [WKInterfaceDevice currentDevice].screenScale;
|
||||
#elif SD_UIKIT
|
||||
CGFloat screenScale = [UIScreen mainScreen].scale;
|
||||
#elif SD_MAC
|
||||
CGFloat screenScale = [NSScreen mainScreen].backingScaleFactor;
|
||||
#endif
|
||||
if (screenScale <= 1) {
|
||||
scales = @[@1,@2,@3];
|
||||
} else if (screenScale <= 2) {
|
||||
scales = @[@2,@3,@1];
|
||||
} else {
|
||||
scales = @[@3,@2,@1];
|
||||
}
|
||||
});
|
||||
return scales;
|
||||
}
|
||||
|
||||
@implementation SDImageAssetManager {
|
||||
dispatch_semaphore_t _lock;
|
||||
}
|
||||
|
||||
+ (instancetype)sharedAssetManager {
|
||||
static dispatch_once_t onceToken;
|
||||
static SDImageAssetManager *assetManager;
|
||||
dispatch_once(&onceToken, ^{
|
||||
assetManager = [[SDImageAssetManager alloc] init];
|
||||
});
|
||||
return assetManager;
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
NSPointerFunctionsOptions valueOptions;
|
||||
#if SD_MAC
|
||||
// Apple says that NSImage use a weak reference to value
|
||||
valueOptions = NSPointerFunctionsWeakMemory;
|
||||
#else
|
||||
// Apple says that UIImage use a strong reference to value
|
||||
valueOptions = NSPointerFunctionsStrongMemory;
|
||||
#endif
|
||||
_imageTable = [NSMapTable mapTableWithKeyOptions:NSPointerFunctionsCopyIn valueOptions:valueOptions];
|
||||
_lock = dispatch_semaphore_create(1);
|
||||
#if SD_UIKIT
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveMemoryWarning:) name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
|
||||
#endif
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
#if SD_UIKIT
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)didReceiveMemoryWarning:(NSNotification *)notification {
|
||||
SD_LOCK(_lock);
|
||||
[self.imageTable removeAllObjects];
|
||||
SD_UNLOCK(_lock);
|
||||
}
|
||||
|
||||
- (NSString *)getPathForName:(NSString *)name bundle:(NSBundle *)bundle preferredScale:(CGFloat *)scale {
|
||||
NSParameterAssert(name);
|
||||
NSParameterAssert(bundle);
|
||||
NSString *path;
|
||||
if (name.length == 0) {
|
||||
return path;
|
||||
}
|
||||
if ([name hasSuffix:@"/"]) {
|
||||
return path;
|
||||
}
|
||||
NSString *extension = name.pathExtension;
|
||||
if (extension.length == 0) {
|
||||
// If no extension, follow Apple's doc, check PNG format
|
||||
extension = @"png";
|
||||
}
|
||||
name = [name stringByDeletingPathExtension];
|
||||
|
||||
CGFloat providedScale = *scale;
|
||||
NSArray *scales = SDBundlePreferredScales();
|
||||
|
||||
// Check if file name contains scale
|
||||
for (size_t i = 0; i < scales.count; i++) {
|
||||
NSNumber *scaleValue = scales[i];
|
||||
if ([name hasSuffix:[NSString stringWithFormat:@"@%@x", scaleValue]]) {
|
||||
path = [bundle pathForResource:name ofType:extension];
|
||||
if (path) {
|
||||
*scale = scaleValue.doubleValue; // override
|
||||
return path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Search with provided scale first
|
||||
if (providedScale != 0) {
|
||||
NSString *scaledName = [name stringByAppendingFormat:@"@%@x", @(providedScale)];
|
||||
path = [bundle pathForResource:scaledName ofType:extension];
|
||||
if (path) {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
// Search with preferred scale
|
||||
for (size_t i = 0; i < scales.count; i++) {
|
||||
NSNumber *scaleValue = scales[i];
|
||||
if (scaleValue.doubleValue == providedScale) {
|
||||
// Ignore provided scale
|
||||
continue;
|
||||
}
|
||||
NSString *scaledName = [name stringByAppendingFormat:@"@%@x", scaleValue];
|
||||
path = [bundle pathForResource:scaledName ofType:extension];
|
||||
if (path) {
|
||||
*scale = scaleValue.doubleValue; // override
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
// Search without scale
|
||||
path = [bundle pathForResource:name ofType:extension];
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
- (UIImage *)imageForName:(NSString *)name {
|
||||
NSParameterAssert(name);
|
||||
UIImage *image;
|
||||
SD_LOCK(_lock);
|
||||
image = [self.imageTable objectForKey:name];
|
||||
SD_UNLOCK(_lock);
|
||||
return image;
|
||||
}
|
||||
|
||||
- (void)storeImage:(UIImage *)image forName:(NSString *)name {
|
||||
NSParameterAssert(image);
|
||||
NSParameterAssert(name);
|
||||
SD_LOCK(_lock);
|
||||
[self.imageTable setObject:image forKey:name];
|
||||
SD_UNLOCK(_lock);
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* This file is part of the SDWebImage package.
|
||||
* (c) Olivier Poitrey <rs@dailymotion.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "SDWebImageCompat.h"
|
||||
|
||||
// This is used for operation management, but not for operation queue execute
|
||||
@interface SDImageCachesManagerOperation : NSOperation
|
||||
|
||||
@property (nonatomic, assign, readonly) NSUInteger pendingCount;
|
||||
|
||||
- (void)beginWithTotalCount:(NSUInteger)totalCount;
|
||||
- (void)completeOne;
|
||||
- (void)done;
|
||||
|
||||
@end
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* This file is part of the SDWebImage package.
|
||||
* (c) Olivier Poitrey <rs@dailymotion.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
#import "SDImageCachesManagerOperation.h"
|
||||
|
||||
@implementation SDImageCachesManagerOperation
|
||||
{
|
||||
dispatch_semaphore_t _pendingCountLock;
|
||||
}
|
||||
|
||||
@synthesize executing = _executing;
|
||||
@synthesize finished = _finished;
|
||||
@synthesize cancelled = _cancelled;
|
||||
@synthesize pendingCount = _pendingCount;
|
||||
|
||||
- (instancetype)init {
|
||||
if (self = [super init]) {
|
||||
_pendingCountLock = dispatch_semaphore_create(1);
|
||||
_pendingCount = 0;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)beginWithTotalCount:(NSUInteger)totalCount {
|
||||
self.executing = YES;
|
||||
self.finished = NO;
|
||||
_pendingCount = totalCount;
|
||||
}
|
||||
|
||||
- (NSUInteger)pendingCount {
|
||||
SD_LOCK(_pendingCountLock);
|
||||
NSUInteger pendingCount = _pendingCount;
|
||||
SD_UNLOCK(_pendingCountLock);
|
||||
return pendingCount;
|
||||
}
|
||||
|
||||
- (void)completeOne {
|
||||
SD_LOCK(_pendingCountLock);
|
||||
_pendingCount = _pendingCount > 0 ? _pendingCount - 1 : 0;
|
||||
SD_UNLOCK(_pendingCountLock);
|
||||
}
|
||||
|
||||
- (void)cancel {
|
||||
self.cancelled = YES;
|
||||
[self reset];
|
||||
}
|
||||
|
||||
- (void)done {
|
||||
self.finished = YES;
|
||||
self.executing = NO;
|
||||
[self reset];
|
||||
}
|
||||
|
||||
- (void)reset {
|
||||
SD_LOCK(_pendingCountLock);
|
||||
_pendingCount = 0;
|
||||
SD_UNLOCK(_pendingCountLock);
|
||||
}
|
||||
|
||||
- (void)setFinished:(BOOL)finished {
|
||||
[self willChangeValueForKey:@"isFinished"];
|
||||
_finished = finished;
|
||||
[self didChangeValueForKey:@"isFinished"];
|
||||
}
|
||||
|
||||
- (void)setExecuting:(BOOL)executing {
|
||||
[self willChangeValueForKey:@"isExecuting"];
|
||||
_executing = executing;
|
||||
[self didChangeValueForKey:@"isExecuting"];
|
||||
}
|
||||
|
||||
- (void)setCancelled:(BOOL)cancelled {
|
||||
[self willChangeValueForKey:@"isCancelled"];
|
||||
_cancelled = cancelled;
|
||||
[self didChangeValueForKey:@"isCancelled"];
|
||||
}
|
||||
|
||||
@end
|
|
@ -7,17 +7,10 @@
|
|||
*/
|
||||
|
||||
#import "SDWebImageCompat.h"
|
||||
#import "SDImageGIFCoder.h"
|
||||
|
||||
#if SD_MAC
|
||||
@interface SDImageGIFCoder ()
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface NSImage (WebCache)
|
||||
|
||||
- (CGImageRef)CGImage;
|
||||
- (NSArray<NSImage *> *)images;
|
||||
- (BOOL)isGIF;
|
||||
- (float)sd_frameDurationAtIndex:(NSUInteger)index source:(nonnull CGImageSourceRef)source;
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* This file is part of the SDWebImage package.
|
||||
* (c) Olivier Poitrey <rs@dailymotion.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "SDmetamacros.h"
|
||||
|
||||
#ifndef SD_LOCK
|
||||
#define SD_LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
|
||||
#endif
|
||||
|
||||
#ifndef SD_UNLOCK
|
||||
#define SD_UNLOCK(lock) dispatch_semaphore_signal(lock);
|
||||
#endif
|
||||
|
||||
#ifndef weakify
|
||||
#define weakify(...) \
|
||||
sd_keywordify \
|
||||
metamacro_foreach_cxt(sd_weakify_,, __weak, __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#ifndef strongify
|
||||
#define strongify(...) \
|
||||
sd_keywordify \
|
||||
_Pragma("clang diagnostic push") \
|
||||
_Pragma("clang diagnostic ignored \"-Wshadow\"") \
|
||||
metamacro_foreach(sd_strongify_,, __VA_ARGS__) \
|
||||
_Pragma("clang diagnostic pop")
|
||||
#endif
|
||||
|
||||
#define sd_weakify_(INDEX, CONTEXT, VAR) \
|
||||
CONTEXT __typeof__(VAR) metamacro_concat(VAR, _weak_) = (VAR);
|
||||
|
||||
#define sd_strongify_(INDEX, VAR) \
|
||||
__strong __typeof__(VAR) VAR = metamacro_concat(VAR, _weak_);
|
||||
|
||||
#if DEBUG
|
||||
#define sd_keywordify autoreleasepool {}
|
||||
#else
|
||||
#define sd_keywordify try {} @catch (...) {}
|
||||
#endif
|
||||
|
||||
#ifndef onExit
|
||||
#define onExit \
|
||||
sd_keywordify \
|
||||
__strong sd_cleanupBlock_t metamacro_concat(sd_exitBlock_, __LINE__) __attribute__((cleanup(sd_executeCleanupBlock), unused)) = ^
|
||||
#endif
|
||||
|
||||
typedef void (^sd_cleanupBlock_t)(void);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
void sd_executeCleanupBlock (__strong sd_cleanupBlock_t *block);
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* This file is part of the SDWebImage package.
|
||||
* (c) Olivier Poitrey <rs@dailymotion.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
#import "SDInternalMacros.h"
|
||||
|
||||
void sd_executeCleanupBlock (__strong sd_cleanupBlock_t *block) {
|
||||
(*block)();
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* This file is part of the SDWebImage package.
|
||||
* (c) Olivier Poitrey <rs@dailymotion.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "SDWebImageCompat.h"
|
||||
|
||||
@interface SDWeakProxy : NSProxy
|
||||
|
||||
@property (nonatomic, weak, readonly, nullable) id target;
|
||||
|
||||
- (nonnull instancetype)initWithTarget:(nonnull id)target;
|
||||
+ (nonnull instancetype)proxyWithTarget:(nonnull id)target;
|
||||
|
||||
@end
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* This file is part of the SDWebImage package.
|
||||
* (c) Olivier Poitrey <rs@dailymotion.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
#import "SDWeakProxy.h"
|
||||
|
||||
@implementation SDWeakProxy
|
||||
|
||||
- (instancetype)initWithTarget:(id)target {
|
||||
_target = target;
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (instancetype)proxyWithTarget:(id)target {
|
||||
return [[SDWeakProxy alloc] initWithTarget:target];
|
||||
}
|
||||
|
||||
- (id)forwardingTargetForSelector:(SEL)selector {
|
||||
return _target;
|
||||
}
|
||||
|
||||
- (void)forwardInvocation:(NSInvocation *)invocation {
|
||||
void *null = NULL;
|
||||
[invocation setReturnValue:&null];
|
||||
}
|
||||
|
||||
- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector {
|
||||
return [NSObject instanceMethodSignatureForSelector:@selector(init)];
|
||||
}
|
||||
|
||||
- (BOOL)respondsToSelector:(SEL)aSelector {
|
||||
return [_target respondsToSelector:aSelector];
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(id)object {
|
||||
return [_target isEqual:object];
|
||||
}
|
||||
|
||||
- (NSUInteger)hash {
|
||||
return [_target hash];
|
||||
}
|
||||
|
||||
- (Class)superclass {
|
||||
return [_target superclass];
|
||||
}
|
||||
|
||||
- (Class)class {
|
||||
return [_target class];
|
||||
}
|
||||
|
||||
- (BOOL)isKindOfClass:(Class)aClass {
|
||||
return [_target isKindOfClass:aClass];
|
||||
}
|
||||
|
||||
- (BOOL)isMemberOfClass:(Class)aClass {
|
||||
return [_target isMemberOfClass:aClass];
|
||||
}
|
||||
|
||||
- (BOOL)conformsToProtocol:(Protocol *)aProtocol {
|
||||
return [_target conformsToProtocol:aProtocol];
|
||||
}
|
||||
|
||||
- (BOOL)isProxy {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (NSString *)description {
|
||||
return [_target description];
|
||||
}
|
||||
|
||||
- (NSString *)debugDescription {
|
||||
return [_target debugDescription];
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,667 @@
|
|||
/**
|
||||
* Macros for metaprogramming
|
||||
* ExtendedC
|
||||
*
|
||||
* Copyright (C) 2012 Justin Spahr-Summers
|
||||
* Released under the MIT license
|
||||
*/
|
||||
|
||||
#ifndef EXTC_METAMACROS_H
|
||||
#define EXTC_METAMACROS_H
|
||||
|
||||
|
||||
/**
|
||||
* Executes one or more expressions (which may have a void type, such as a call
|
||||
* to a function that returns no value) and always returns true.
|
||||
*/
|
||||
#define metamacro_exprify(...) \
|
||||
((__VA_ARGS__), true)
|
||||
|
||||
/**
|
||||
* Returns a string representation of VALUE after full macro expansion.
|
||||
*/
|
||||
#define metamacro_stringify(VALUE) \
|
||||
metamacro_stringify_(VALUE)
|
||||
|
||||
/**
|
||||
* Returns A and B concatenated after full macro expansion.
|
||||
*/
|
||||
#define metamacro_concat(A, B) \
|
||||
metamacro_concat_(A, B)
|
||||
|
||||
/**
|
||||
* Returns the Nth variadic argument (starting from zero). At least
|
||||
* N + 1 variadic arguments must be given. N must be between zero and twenty,
|
||||
* inclusive.
|
||||
*/
|
||||
#define metamacro_at(N, ...) \
|
||||
metamacro_concat(metamacro_at, N)(__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* Returns the number of arguments (up to twenty) provided to the macro. At
|
||||
* least one argument must be provided.
|
||||
*
|
||||
* Inspired by P99: http://p99.gforge.inria.fr
|
||||
*/
|
||||
#define metamacro_argcount(...) \
|
||||
metamacro_at(20, __VA_ARGS__, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
|
||||
|
||||
/**
|
||||
* Identical to #metamacro_foreach_cxt, except that no CONTEXT argument is
|
||||
* given. Only the index and current argument will thus be passed to MACRO.
|
||||
*/
|
||||
#define metamacro_foreach(MACRO, SEP, ...) \
|
||||
metamacro_foreach_cxt(metamacro_foreach_iter, SEP, MACRO, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* For each consecutive variadic argument (up to twenty), MACRO is passed the
|
||||
* zero-based index of the current argument, CONTEXT, and then the argument
|
||||
* itself. The results of adjoining invocations of MACRO are then separated by
|
||||
* SEP.
|
||||
*
|
||||
* Inspired by P99: http://p99.gforge.inria.fr
|
||||
*/
|
||||
#define metamacro_foreach_cxt(MACRO, SEP, CONTEXT, ...) \
|
||||
metamacro_concat(metamacro_foreach_cxt, metamacro_argcount(__VA_ARGS__))(MACRO, SEP, CONTEXT, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* Identical to #metamacro_foreach_cxt. This can be used when the former would
|
||||
* fail due to recursive macro expansion.
|
||||
*/
|
||||
#define metamacro_foreach_cxt_recursive(MACRO, SEP, CONTEXT, ...) \
|
||||
metamacro_concat(metamacro_foreach_cxt_recursive, metamacro_argcount(__VA_ARGS__))(MACRO, SEP, CONTEXT, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* In consecutive order, appends each variadic argument (up to twenty) onto
|
||||
* BASE. The resulting concatenations are then separated by SEP.
|
||||
*
|
||||
* This is primarily useful to manipulate a list of macro invocations into instead
|
||||
* invoking a different, possibly related macro.
|
||||
*/
|
||||
#define metamacro_foreach_concat(BASE, SEP, ...) \
|
||||
metamacro_foreach_cxt(metamacro_foreach_concat_iter, SEP, BASE, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* Iterates COUNT times, each time invoking MACRO with the current index
|
||||
* (starting at zero) and CONTEXT. The results of adjoining invocations of MACRO
|
||||
* are then separated by SEP.
|
||||
*
|
||||
* COUNT must be an integer between zero and twenty, inclusive.
|
||||
*/
|
||||
#define metamacro_for_cxt(COUNT, MACRO, SEP, CONTEXT) \
|
||||
metamacro_concat(metamacro_for_cxt, COUNT)(MACRO, SEP, CONTEXT)
|
||||
|
||||
/**
|
||||
* Returns the first argument given. At least one argument must be provided.
|
||||
*
|
||||
* This is useful when implementing a variadic macro, where you may have only
|
||||
* one variadic argument, but no way to retrieve it (for example, because \c ...
|
||||
* always needs to match at least one argument).
|
||||
*
|
||||
* @code
|
||||
|
||||
#define varmacro(...) \
|
||||
metamacro_head(__VA_ARGS__)
|
||||
|
||||
* @endcode
|
||||
*/
|
||||
#define metamacro_head(...) \
|
||||
metamacro_head_(__VA_ARGS__, 0)
|
||||
|
||||
/**
|
||||
* Returns every argument except the first. At least two arguments must be
|
||||
* provided.
|
||||
*/
|
||||
#define metamacro_tail(...) \
|
||||
metamacro_tail_(__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* Returns the first N (up to twenty) variadic arguments as a new argument list.
|
||||
* At least N variadic arguments must be provided.
|
||||
*/
|
||||
#define metamacro_take(N, ...) \
|
||||
metamacro_concat(metamacro_take, N)(__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* Removes the first N (up to twenty) variadic arguments from the given argument
|
||||
* list. At least N variadic arguments must be provided.
|
||||
*/
|
||||
#define metamacro_drop(N, ...) \
|
||||
metamacro_concat(metamacro_drop, N)(__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* Decrements VAL, which must be a number between zero and twenty, inclusive.
|
||||
*
|
||||
* This is primarily useful when dealing with indexes and counts in
|
||||
* metaprogramming.
|
||||
*/
|
||||
#define metamacro_dec(VAL) \
|
||||
metamacro_at(VAL, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19)
|
||||
|
||||
/**
|
||||
* Increments VAL, which must be a number between zero and twenty, inclusive.
|
||||
*
|
||||
* This is primarily useful when dealing with indexes and counts in
|
||||
* metaprogramming.
|
||||
*/
|
||||
#define metamacro_inc(VAL) \
|
||||
metamacro_at(VAL, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21)
|
||||
|
||||
/**
|
||||
* If A is equal to B, the next argument list is expanded; otherwise, the
|
||||
* argument list after that is expanded. A and B must be numbers between zero
|
||||
* and twenty, inclusive. Additionally, B must be greater than or equal to A.
|
||||
*
|
||||
* @code
|
||||
|
||||
// expands to true
|
||||
metamacro_if_eq(0, 0)(true)(false)
|
||||
|
||||
// expands to false
|
||||
metamacro_if_eq(0, 1)(true)(false)
|
||||
|
||||
* @endcode
|
||||
*
|
||||
* This is primarily useful when dealing with indexes and counts in
|
||||
* metaprogramming.
|
||||
*/
|
||||
#define metamacro_if_eq(A, B) \
|
||||
metamacro_concat(metamacro_if_eq, A)(B)
|
||||
|
||||
/**
|
||||
* Identical to #metamacro_if_eq. This can be used when the former would fail
|
||||
* due to recursive macro expansion.
|
||||
*/
|
||||
#define metamacro_if_eq_recursive(A, B) \
|
||||
metamacro_concat(metamacro_if_eq_recursive, A)(B)
|
||||
|
||||
/**
|
||||
* Returns 1 if N is an even number, or 0 otherwise. N must be between zero and
|
||||
* twenty, inclusive.
|
||||
*
|
||||
* For the purposes of this test, zero is considered even.
|
||||
*/
|
||||
#define metamacro_is_even(N) \
|
||||
metamacro_at(N, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1)
|
||||
|
||||
/**
|
||||
* Returns the logical NOT of B, which must be the number zero or one.
|
||||
*/
|
||||
#define metamacro_not(B) \
|
||||
metamacro_at(B, 1, 0)
|
||||
|
||||
// IMPLEMENTATION DETAILS FOLLOW!
|
||||
// Do not write code that depends on anything below this line.
|
||||
#define metamacro_stringify_(VALUE) # VALUE
|
||||
#define metamacro_concat_(A, B) A ## B
|
||||
#define metamacro_foreach_iter(INDEX, MACRO, ARG) MACRO(INDEX, ARG)
|
||||
#define metamacro_head_(FIRST, ...) FIRST
|
||||
#define metamacro_tail_(FIRST, ...) __VA_ARGS__
|
||||
#define metamacro_consume_(...)
|
||||
#define metamacro_expand_(...) __VA_ARGS__
|
||||
|
||||
// implemented from scratch so that metamacro_concat() doesn't end up nesting
|
||||
#define metamacro_foreach_concat_iter(INDEX, BASE, ARG) metamacro_foreach_concat_iter_(BASE, ARG)
|
||||
#define metamacro_foreach_concat_iter_(BASE, ARG) BASE ## ARG
|
||||
|
||||
// metamacro_at expansions
|
||||
#define metamacro_at0(...) metamacro_head(__VA_ARGS__)
|
||||
#define metamacro_at1(_0, ...) metamacro_head(__VA_ARGS__)
|
||||
#define metamacro_at2(_0, _1, ...) metamacro_head(__VA_ARGS__)
|
||||
#define metamacro_at3(_0, _1, _2, ...) metamacro_head(__VA_ARGS__)
|
||||
#define metamacro_at4(_0, _1, _2, _3, ...) metamacro_head(__VA_ARGS__)
|
||||
#define metamacro_at5(_0, _1, _2, _3, _4, ...) metamacro_head(__VA_ARGS__)
|
||||
#define metamacro_at6(_0, _1, _2, _3, _4, _5, ...) metamacro_head(__VA_ARGS__)
|
||||
#define metamacro_at7(_0, _1, _2, _3, _4, _5, _6, ...) metamacro_head(__VA_ARGS__)
|
||||
#define metamacro_at8(_0, _1, _2, _3, _4, _5, _6, _7, ...) metamacro_head(__VA_ARGS__)
|
||||
#define metamacro_at9(_0, _1, _2, _3, _4, _5, _6, _7, _8, ...) metamacro_head(__VA_ARGS__)
|
||||
#define metamacro_at10(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, ...) metamacro_head(__VA_ARGS__)
|
||||
#define metamacro_at11(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, ...) metamacro_head(__VA_ARGS__)
|
||||
#define metamacro_at12(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, ...) metamacro_head(__VA_ARGS__)
|
||||
#define metamacro_at13(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, ...) metamacro_head(__VA_ARGS__)
|
||||
#define metamacro_at14(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, ...) metamacro_head(__VA_ARGS__)
|
||||
#define metamacro_at15(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, ...) metamacro_head(__VA_ARGS__)
|
||||
#define metamacro_at16(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, ...) metamacro_head(__VA_ARGS__)
|
||||
#define metamacro_at17(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, ...) metamacro_head(__VA_ARGS__)
|
||||
#define metamacro_at18(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, ...) metamacro_head(__VA_ARGS__)
|
||||
#define metamacro_at19(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, ...) metamacro_head(__VA_ARGS__)
|
||||
#define metamacro_at20(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, ...) metamacro_head(__VA_ARGS__)
|
||||
|
||||
// metamacro_foreach_cxt expansions
|
||||
#define metamacro_foreach_cxt0(MACRO, SEP, CONTEXT)
|
||||
#define metamacro_foreach_cxt1(MACRO, SEP, CONTEXT, _0) MACRO(0, CONTEXT, _0)
|
||||
|
||||
#define metamacro_foreach_cxt2(MACRO, SEP, CONTEXT, _0, _1) \
|
||||
metamacro_foreach_cxt1(MACRO, SEP, CONTEXT, _0) \
|
||||
SEP \
|
||||
MACRO(1, CONTEXT, _1)
|
||||
|
||||
#define metamacro_foreach_cxt3(MACRO, SEP, CONTEXT, _0, _1, _2) \
|
||||
metamacro_foreach_cxt2(MACRO, SEP, CONTEXT, _0, _1) \
|
||||
SEP \
|
||||
MACRO(2, CONTEXT, _2)
|
||||
|
||||
#define metamacro_foreach_cxt4(MACRO, SEP, CONTEXT, _0, _1, _2, _3) \
|
||||
metamacro_foreach_cxt3(MACRO, SEP, CONTEXT, _0, _1, _2) \
|
||||
SEP \
|
||||
MACRO(3, CONTEXT, _3)
|
||||
|
||||
#define metamacro_foreach_cxt5(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4) \
|
||||
metamacro_foreach_cxt4(MACRO, SEP, CONTEXT, _0, _1, _2, _3) \
|
||||
SEP \
|
||||
MACRO(4, CONTEXT, _4)
|
||||
|
||||
#define metamacro_foreach_cxt6(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5) \
|
||||
metamacro_foreach_cxt5(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4) \
|
||||
SEP \
|
||||
MACRO(5, CONTEXT, _5)
|
||||
|
||||
#define metamacro_foreach_cxt7(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6) \
|
||||
metamacro_foreach_cxt6(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5) \
|
||||
SEP \
|
||||
MACRO(6, CONTEXT, _6)
|
||||
|
||||
#define metamacro_foreach_cxt8(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7) \
|
||||
metamacro_foreach_cxt7(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6) \
|
||||
SEP \
|
||||
MACRO(7, CONTEXT, _7)
|
||||
|
||||
#define metamacro_foreach_cxt9(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8) \
|
||||
metamacro_foreach_cxt8(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7) \
|
||||
SEP \
|
||||
MACRO(8, CONTEXT, _8)
|
||||
|
||||
#define metamacro_foreach_cxt10(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9) \
|
||||
metamacro_foreach_cxt9(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8) \
|
||||
SEP \
|
||||
MACRO(9, CONTEXT, _9)
|
||||
|
||||
#define metamacro_foreach_cxt11(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) \
|
||||
metamacro_foreach_cxt10(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9) \
|
||||
SEP \
|
||||
MACRO(10, CONTEXT, _10)
|
||||
|
||||
#define metamacro_foreach_cxt12(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11) \
|
||||
metamacro_foreach_cxt11(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) \
|
||||
SEP \
|
||||
MACRO(11, CONTEXT, _11)
|
||||
|
||||
#define metamacro_foreach_cxt13(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12) \
|
||||
metamacro_foreach_cxt12(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11) \
|
||||
SEP \
|
||||
MACRO(12, CONTEXT, _12)
|
||||
|
||||
#define metamacro_foreach_cxt14(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13) \
|
||||
metamacro_foreach_cxt13(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12) \
|
||||
SEP \
|
||||
MACRO(13, CONTEXT, _13)
|
||||
|
||||
#define metamacro_foreach_cxt15(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14) \
|
||||
metamacro_foreach_cxt14(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13) \
|
||||
SEP \
|
||||
MACRO(14, CONTEXT, _14)
|
||||
|
||||
#define metamacro_foreach_cxt16(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15) \
|
||||
metamacro_foreach_cxt15(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14) \
|
||||
SEP \
|
||||
MACRO(15, CONTEXT, _15)
|
||||
|
||||
#define metamacro_foreach_cxt17(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16) \
|
||||
metamacro_foreach_cxt16(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15) \
|
||||
SEP \
|
||||
MACRO(16, CONTEXT, _16)
|
||||
|
||||
#define metamacro_foreach_cxt18(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17) \
|
||||
metamacro_foreach_cxt17(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16) \
|
||||
SEP \
|
||||
MACRO(17, CONTEXT, _17)
|
||||
|
||||
#define metamacro_foreach_cxt19(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18) \
|
||||
metamacro_foreach_cxt18(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17) \
|
||||
SEP \
|
||||
MACRO(18, CONTEXT, _18)
|
||||
|
||||
#define metamacro_foreach_cxt20(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19) \
|
||||
metamacro_foreach_cxt19(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18) \
|
||||
SEP \
|
||||
MACRO(19, CONTEXT, _19)
|
||||
|
||||
// metamacro_foreach_cxt_recursive expansions
|
||||
#define metamacro_foreach_cxt_recursive0(MACRO, SEP, CONTEXT)
|
||||
#define metamacro_foreach_cxt_recursive1(MACRO, SEP, CONTEXT, _0) MACRO(0, CONTEXT, _0)
|
||||
|
||||
#define metamacro_foreach_cxt_recursive2(MACRO, SEP, CONTEXT, _0, _1) \
|
||||
metamacro_foreach_cxt_recursive1(MACRO, SEP, CONTEXT, _0) \
|
||||
SEP \
|
||||
MACRO(1, CONTEXT, _1)
|
||||
|
||||
#define metamacro_foreach_cxt_recursive3(MACRO, SEP, CONTEXT, _0, _1, _2) \
|
||||
metamacro_foreach_cxt_recursive2(MACRO, SEP, CONTEXT, _0, _1) \
|
||||
SEP \
|
||||
MACRO(2, CONTEXT, _2)
|
||||
|
||||
#define metamacro_foreach_cxt_recursive4(MACRO, SEP, CONTEXT, _0, _1, _2, _3) \
|
||||
metamacro_foreach_cxt_recursive3(MACRO, SEP, CONTEXT, _0, _1, _2) \
|
||||
SEP \
|
||||
MACRO(3, CONTEXT, _3)
|
||||
|
||||
#define metamacro_foreach_cxt_recursive5(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4) \
|
||||
metamacro_foreach_cxt_recursive4(MACRO, SEP, CONTEXT, _0, _1, _2, _3) \
|
||||
SEP \
|
||||
MACRO(4, CONTEXT, _4)
|
||||
|
||||
#define metamacro_foreach_cxt_recursive6(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5) \
|
||||
metamacro_foreach_cxt_recursive5(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4) \
|
||||
SEP \
|
||||
MACRO(5, CONTEXT, _5)
|
||||
|
||||
#define metamacro_foreach_cxt_recursive7(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6) \
|
||||
metamacro_foreach_cxt_recursive6(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5) \
|
||||
SEP \
|
||||
MACRO(6, CONTEXT, _6)
|
||||
|
||||
#define metamacro_foreach_cxt_recursive8(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7) \
|
||||
metamacro_foreach_cxt_recursive7(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6) \
|
||||
SEP \
|
||||
MACRO(7, CONTEXT, _7)
|
||||
|
||||
#define metamacro_foreach_cxt_recursive9(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8) \
|
||||
metamacro_foreach_cxt_recursive8(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7) \
|
||||
SEP \
|
||||
MACRO(8, CONTEXT, _8)
|
||||
|
||||
#define metamacro_foreach_cxt_recursive10(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9) \
|
||||
metamacro_foreach_cxt_recursive9(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8) \
|
||||
SEP \
|
||||
MACRO(9, CONTEXT, _9)
|
||||
|
||||
#define metamacro_foreach_cxt_recursive11(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) \
|
||||
metamacro_foreach_cxt_recursive10(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9) \
|
||||
SEP \
|
||||
MACRO(10, CONTEXT, _10)
|
||||
|
||||
#define metamacro_foreach_cxt_recursive12(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11) \
|
||||
metamacro_foreach_cxt_recursive11(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) \
|
||||
SEP \
|
||||
MACRO(11, CONTEXT, _11)
|
||||
|
||||
#define metamacro_foreach_cxt_recursive13(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12) \
|
||||
metamacro_foreach_cxt_recursive12(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11) \
|
||||
SEP \
|
||||
MACRO(12, CONTEXT, _12)
|
||||
|
||||
#define metamacro_foreach_cxt_recursive14(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13) \
|
||||
metamacro_foreach_cxt_recursive13(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12) \
|
||||
SEP \
|
||||
MACRO(13, CONTEXT, _13)
|
||||
|
||||
#define metamacro_foreach_cxt_recursive15(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14) \
|
||||
metamacro_foreach_cxt_recursive14(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13) \
|
||||
SEP \
|
||||
MACRO(14, CONTEXT, _14)
|
||||
|
||||
#define metamacro_foreach_cxt_recursive16(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15) \
|
||||
metamacro_foreach_cxt_recursive15(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14) \
|
||||
SEP \
|
||||
MACRO(15, CONTEXT, _15)
|
||||
|
||||
#define metamacro_foreach_cxt_recursive17(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16) \
|
||||
metamacro_foreach_cxt_recursive16(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15) \
|
||||
SEP \
|
||||
MACRO(16, CONTEXT, _16)
|
||||
|
||||
#define metamacro_foreach_cxt_recursive18(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17) \
|
||||
metamacro_foreach_cxt_recursive17(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16) \
|
||||
SEP \
|
||||
MACRO(17, CONTEXT, _17)
|
||||
|
||||
#define metamacro_foreach_cxt_recursive19(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18) \
|
||||
metamacro_foreach_cxt_recursive18(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17) \
|
||||
SEP \
|
||||
MACRO(18, CONTEXT, _18)
|
||||
|
||||
#define metamacro_foreach_cxt_recursive20(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19) \
|
||||
metamacro_foreach_cxt_recursive19(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18) \
|
||||
SEP \
|
||||
MACRO(19, CONTEXT, _19)
|
||||
|
||||
// metamacro_for_cxt expansions
|
||||
#define metamacro_for_cxt0(MACRO, SEP, CONTEXT)
|
||||
#define metamacro_for_cxt1(MACRO, SEP, CONTEXT) MACRO(0, CONTEXT)
|
||||
|
||||
#define metamacro_for_cxt2(MACRO, SEP, CONTEXT) \
|
||||
metamacro_for_cxt1(MACRO, SEP, CONTEXT) \
|
||||
SEP \
|
||||
MACRO(1, CONTEXT)
|
||||
|
||||
#define metamacro_for_cxt3(MACRO, SEP, CONTEXT) \
|
||||
metamacro_for_cxt2(MACRO, SEP, CONTEXT) \
|
||||
SEP \
|
||||
MACRO(2, CONTEXT)
|
||||
|
||||
#define metamacro_for_cxt4(MACRO, SEP, CONTEXT) \
|
||||
metamacro_for_cxt3(MACRO, SEP, CONTEXT) \
|
||||
SEP \
|
||||
MACRO(3, CONTEXT)
|
||||
|
||||
#define metamacro_for_cxt5(MACRO, SEP, CONTEXT) \
|
||||
metamacro_for_cxt4(MACRO, SEP, CONTEXT) \
|
||||
SEP \
|
||||
MACRO(4, CONTEXT)
|
||||
|
||||
#define metamacro_for_cxt6(MACRO, SEP, CONTEXT) \
|
||||
metamacro_for_cxt5(MACRO, SEP, CONTEXT) \
|
||||
SEP \
|
||||
MACRO(5, CONTEXT)
|
||||
|
||||
#define metamacro_for_cxt7(MACRO, SEP, CONTEXT) \
|
||||
metamacro_for_cxt6(MACRO, SEP, CONTEXT) \
|
||||
SEP \
|
||||
MACRO(6, CONTEXT)
|
||||
|
||||
#define metamacro_for_cxt8(MACRO, SEP, CONTEXT) \
|
||||
metamacro_for_cxt7(MACRO, SEP, CONTEXT) \
|
||||
SEP \
|
||||
MACRO(7, CONTEXT)
|
||||
|
||||
#define metamacro_for_cxt9(MACRO, SEP, CONTEXT) \
|
||||
metamacro_for_cxt8(MACRO, SEP, CONTEXT) \
|
||||
SEP \
|
||||
MACRO(8, CONTEXT)
|
||||
|
||||
#define metamacro_for_cxt10(MACRO, SEP, CONTEXT) \
|
||||
metamacro_for_cxt9(MACRO, SEP, CONTEXT) \
|
||||
SEP \
|
||||
MACRO(9, CONTEXT)
|
||||
|
||||
#define metamacro_for_cxt11(MACRO, SEP, CONTEXT) \
|
||||
metamacro_for_cxt10(MACRO, SEP, CONTEXT) \
|
||||
SEP \
|
||||
MACRO(10, CONTEXT)
|
||||
|
||||
#define metamacro_for_cxt12(MACRO, SEP, CONTEXT) \
|
||||
metamacro_for_cxt11(MACRO, SEP, CONTEXT) \
|
||||
SEP \
|
||||
MACRO(11, CONTEXT)
|
||||
|
||||
#define metamacro_for_cxt13(MACRO, SEP, CONTEXT) \
|
||||
metamacro_for_cxt12(MACRO, SEP, CONTEXT) \
|
||||
SEP \
|
||||
MACRO(12, CONTEXT)
|
||||
|
||||
#define metamacro_for_cxt14(MACRO, SEP, CONTEXT) \
|
||||
metamacro_for_cxt13(MACRO, SEP, CONTEXT) \
|
||||
SEP \
|
||||
MACRO(13, CONTEXT)
|
||||
|
||||
#define metamacro_for_cxt15(MACRO, SEP, CONTEXT) \
|
||||
metamacro_for_cxt14(MACRO, SEP, CONTEXT) \
|
||||
SEP \
|
||||
MACRO(14, CONTEXT)
|
||||
|
||||
#define metamacro_for_cxt16(MACRO, SEP, CONTEXT) \
|
||||
metamacro_for_cxt15(MACRO, SEP, CONTEXT) \
|
||||
SEP \
|
||||
MACRO(15, CONTEXT)
|
||||
|
||||
#define metamacro_for_cxt17(MACRO, SEP, CONTEXT) \
|
||||
metamacro_for_cxt16(MACRO, SEP, CONTEXT) \
|
||||
SEP \
|
||||
MACRO(16, CONTEXT)
|
||||
|
||||
#define metamacro_for_cxt18(MACRO, SEP, CONTEXT) \
|
||||
metamacro_for_cxt17(MACRO, SEP, CONTEXT) \
|
||||
SEP \
|
||||
MACRO(17, CONTEXT)
|
||||
|
||||
#define metamacro_for_cxt19(MACRO, SEP, CONTEXT) \
|
||||
metamacro_for_cxt18(MACRO, SEP, CONTEXT) \
|
||||
SEP \
|
||||
MACRO(18, CONTEXT)
|
||||
|
||||
#define metamacro_for_cxt20(MACRO, SEP, CONTEXT) \
|
||||
metamacro_for_cxt19(MACRO, SEP, CONTEXT) \
|
||||
SEP \
|
||||
MACRO(19, CONTEXT)
|
||||
|
||||
// metamacro_if_eq expansions
|
||||
#define metamacro_if_eq0(VALUE) \
|
||||
metamacro_concat(metamacro_if_eq0_, VALUE)
|
||||
|
||||
#define metamacro_if_eq0_0(...) __VA_ARGS__ metamacro_consume_
|
||||
#define metamacro_if_eq0_1(...) metamacro_expand_
|
||||
#define metamacro_if_eq0_2(...) metamacro_expand_
|
||||
#define metamacro_if_eq0_3(...) metamacro_expand_
|
||||
#define metamacro_if_eq0_4(...) metamacro_expand_
|
||||
#define metamacro_if_eq0_5(...) metamacro_expand_
|
||||
#define metamacro_if_eq0_6(...) metamacro_expand_
|
||||
#define metamacro_if_eq0_7(...) metamacro_expand_
|
||||
#define metamacro_if_eq0_8(...) metamacro_expand_
|
||||
#define metamacro_if_eq0_9(...) metamacro_expand_
|
||||
#define metamacro_if_eq0_10(...) metamacro_expand_
|
||||
#define metamacro_if_eq0_11(...) metamacro_expand_
|
||||
#define metamacro_if_eq0_12(...) metamacro_expand_
|
||||
#define metamacro_if_eq0_13(...) metamacro_expand_
|
||||
#define metamacro_if_eq0_14(...) metamacro_expand_
|
||||
#define metamacro_if_eq0_15(...) metamacro_expand_
|
||||
#define metamacro_if_eq0_16(...) metamacro_expand_
|
||||
#define metamacro_if_eq0_17(...) metamacro_expand_
|
||||
#define metamacro_if_eq0_18(...) metamacro_expand_
|
||||
#define metamacro_if_eq0_19(...) metamacro_expand_
|
||||
#define metamacro_if_eq0_20(...) metamacro_expand_
|
||||
|
||||
#define metamacro_if_eq1(VALUE) metamacro_if_eq0(metamacro_dec(VALUE))
|
||||
#define metamacro_if_eq2(VALUE) metamacro_if_eq1(metamacro_dec(VALUE))
|
||||
#define metamacro_if_eq3(VALUE) metamacro_if_eq2(metamacro_dec(VALUE))
|
||||
#define metamacro_if_eq4(VALUE) metamacro_if_eq3(metamacro_dec(VALUE))
|
||||
#define metamacro_if_eq5(VALUE) metamacro_if_eq4(metamacro_dec(VALUE))
|
||||
#define metamacro_if_eq6(VALUE) metamacro_if_eq5(metamacro_dec(VALUE))
|
||||
#define metamacro_if_eq7(VALUE) metamacro_if_eq6(metamacro_dec(VALUE))
|
||||
#define metamacro_if_eq8(VALUE) metamacro_if_eq7(metamacro_dec(VALUE))
|
||||
#define metamacro_if_eq9(VALUE) metamacro_if_eq8(metamacro_dec(VALUE))
|
||||
#define metamacro_if_eq10(VALUE) metamacro_if_eq9(metamacro_dec(VALUE))
|
||||
#define metamacro_if_eq11(VALUE) metamacro_if_eq10(metamacro_dec(VALUE))
|
||||
#define metamacro_if_eq12(VALUE) metamacro_if_eq11(metamacro_dec(VALUE))
|
||||
#define metamacro_if_eq13(VALUE) metamacro_if_eq12(metamacro_dec(VALUE))
|
||||
#define metamacro_if_eq14(VALUE) metamacro_if_eq13(metamacro_dec(VALUE))
|
||||
#define metamacro_if_eq15(VALUE) metamacro_if_eq14(metamacro_dec(VALUE))
|
||||
#define metamacro_if_eq16(VALUE) metamacro_if_eq15(metamacro_dec(VALUE))
|
||||
#define metamacro_if_eq17(VALUE) metamacro_if_eq16(metamacro_dec(VALUE))
|
||||
#define metamacro_if_eq18(VALUE) metamacro_if_eq17(metamacro_dec(VALUE))
|
||||
#define metamacro_if_eq19(VALUE) metamacro_if_eq18(metamacro_dec(VALUE))
|
||||
#define metamacro_if_eq20(VALUE) metamacro_if_eq19(metamacro_dec(VALUE))
|
||||
|
||||
// metamacro_if_eq_recursive expansions
|
||||
#define metamacro_if_eq_recursive0(VALUE) \
|
||||
metamacro_concat(metamacro_if_eq_recursive0_, VALUE)
|
||||
|
||||
#define metamacro_if_eq_recursive0_0(...) __VA_ARGS__ metamacro_consume_
|
||||
#define metamacro_if_eq_recursive0_1(...) metamacro_expand_
|
||||
#define metamacro_if_eq_recursive0_2(...) metamacro_expand_
|
||||
#define metamacro_if_eq_recursive0_3(...) metamacro_expand_
|
||||
#define metamacro_if_eq_recursive0_4(...) metamacro_expand_
|
||||
#define metamacro_if_eq_recursive0_5(...) metamacro_expand_
|
||||
#define metamacro_if_eq_recursive0_6(...) metamacro_expand_
|
||||
#define metamacro_if_eq_recursive0_7(...) metamacro_expand_
|
||||
#define metamacro_if_eq_recursive0_8(...) metamacro_expand_
|
||||
#define metamacro_if_eq_recursive0_9(...) metamacro_expand_
|
||||
#define metamacro_if_eq_recursive0_10(...) metamacro_expand_
|
||||
#define metamacro_if_eq_recursive0_11(...) metamacro_expand_
|
||||
#define metamacro_if_eq_recursive0_12(...) metamacro_expand_
|
||||
#define metamacro_if_eq_recursive0_13(...) metamacro_expand_
|
||||
#define metamacro_if_eq_recursive0_14(...) metamacro_expand_
|
||||
#define metamacro_if_eq_recursive0_15(...) metamacro_expand_
|
||||
#define metamacro_if_eq_recursive0_16(...) metamacro_expand_
|
||||
#define metamacro_if_eq_recursive0_17(...) metamacro_expand_
|
||||
#define metamacro_if_eq_recursive0_18(...) metamacro_expand_
|
||||
#define metamacro_if_eq_recursive0_19(...) metamacro_expand_
|
||||
#define metamacro_if_eq_recursive0_20(...) metamacro_expand_
|
||||
|
||||
#define metamacro_if_eq_recursive1(VALUE) metamacro_if_eq_recursive0(metamacro_dec(VALUE))
|
||||
#define metamacro_if_eq_recursive2(VALUE) metamacro_if_eq_recursive1(metamacro_dec(VALUE))
|
||||
#define metamacro_if_eq_recursive3(VALUE) metamacro_if_eq_recursive2(metamacro_dec(VALUE))
|
||||
#define metamacro_if_eq_recursive4(VALUE) metamacro_if_eq_recursive3(metamacro_dec(VALUE))
|
||||
#define metamacro_if_eq_recursive5(VALUE) metamacro_if_eq_recursive4(metamacro_dec(VALUE))
|
||||
#define metamacro_if_eq_recursive6(VALUE) metamacro_if_eq_recursive5(metamacro_dec(VALUE))
|
||||
#define metamacro_if_eq_recursive7(VALUE) metamacro_if_eq_recursive6(metamacro_dec(VALUE))
|
||||
#define metamacro_if_eq_recursive8(VALUE) metamacro_if_eq_recursive7(metamacro_dec(VALUE))
|
||||
#define metamacro_if_eq_recursive9(VALUE) metamacro_if_eq_recursive8(metamacro_dec(VALUE))
|
||||
#define metamacro_if_eq_recursive10(VALUE) metamacro_if_eq_recursive9(metamacro_dec(VALUE))
|
||||
#define metamacro_if_eq_recursive11(VALUE) metamacro_if_eq_recursive10(metamacro_dec(VALUE))
|
||||
#define metamacro_if_eq_recursive12(VALUE) metamacro_if_eq_recursive11(metamacro_dec(VALUE))
|
||||
#define metamacro_if_eq_recursive13(VALUE) metamacro_if_eq_recursive12(metamacro_dec(VALUE))
|
||||
#define metamacro_if_eq_recursive14(VALUE) metamacro_if_eq_recursive13(metamacro_dec(VALUE))
|
||||
#define metamacro_if_eq_recursive15(VALUE) metamacro_if_eq_recursive14(metamacro_dec(VALUE))
|
||||
#define metamacro_if_eq_recursive16(VALUE) metamacro_if_eq_recursive15(metamacro_dec(VALUE))
|
||||
#define metamacro_if_eq_recursive17(VALUE) metamacro_if_eq_recursive16(metamacro_dec(VALUE))
|
||||
#define metamacro_if_eq_recursive18(VALUE) metamacro_if_eq_recursive17(metamacro_dec(VALUE))
|
||||
#define metamacro_if_eq_recursive19(VALUE) metamacro_if_eq_recursive18(metamacro_dec(VALUE))
|
||||
#define metamacro_if_eq_recursive20(VALUE) metamacro_if_eq_recursive19(metamacro_dec(VALUE))
|
||||
|
||||
// metamacro_take expansions
|
||||
#define metamacro_take0(...)
|
||||
#define metamacro_take1(...) metamacro_head(__VA_ARGS__)
|
||||
#define metamacro_take2(...) metamacro_head(__VA_ARGS__), metamacro_take1(metamacro_tail(__VA_ARGS__))
|
||||
#define metamacro_take3(...) metamacro_head(__VA_ARGS__), metamacro_take2(metamacro_tail(__VA_ARGS__))
|
||||
#define metamacro_take4(...) metamacro_head(__VA_ARGS__), metamacro_take3(metamacro_tail(__VA_ARGS__))
|
||||
#define metamacro_take5(...) metamacro_head(__VA_ARGS__), metamacro_take4(metamacro_tail(__VA_ARGS__))
|
||||
#define metamacro_take6(...) metamacro_head(__VA_ARGS__), metamacro_take5(metamacro_tail(__VA_ARGS__))
|
||||
#define metamacro_take7(...) metamacro_head(__VA_ARGS__), metamacro_take6(metamacro_tail(__VA_ARGS__))
|
||||
#define metamacro_take8(...) metamacro_head(__VA_ARGS__), metamacro_take7(metamacro_tail(__VA_ARGS__))
|
||||
#define metamacro_take9(...) metamacro_head(__VA_ARGS__), metamacro_take8(metamacro_tail(__VA_ARGS__))
|
||||
#define metamacro_take10(...) metamacro_head(__VA_ARGS__), metamacro_take9(metamacro_tail(__VA_ARGS__))
|
||||
#define metamacro_take11(...) metamacro_head(__VA_ARGS__), metamacro_take10(metamacro_tail(__VA_ARGS__))
|
||||
#define metamacro_take12(...) metamacro_head(__VA_ARGS__), metamacro_take11(metamacro_tail(__VA_ARGS__))
|
||||
#define metamacro_take13(...) metamacro_head(__VA_ARGS__), metamacro_take12(metamacro_tail(__VA_ARGS__))
|
||||
#define metamacro_take14(...) metamacro_head(__VA_ARGS__), metamacro_take13(metamacro_tail(__VA_ARGS__))
|
||||
#define metamacro_take15(...) metamacro_head(__VA_ARGS__), metamacro_take14(metamacro_tail(__VA_ARGS__))
|
||||
#define metamacro_take16(...) metamacro_head(__VA_ARGS__), metamacro_take15(metamacro_tail(__VA_ARGS__))
|
||||
#define metamacro_take17(...) metamacro_head(__VA_ARGS__), metamacro_take16(metamacro_tail(__VA_ARGS__))
|
||||
#define metamacro_take18(...) metamacro_head(__VA_ARGS__), metamacro_take17(metamacro_tail(__VA_ARGS__))
|
||||
#define metamacro_take19(...) metamacro_head(__VA_ARGS__), metamacro_take18(metamacro_tail(__VA_ARGS__))
|
||||
#define metamacro_take20(...) metamacro_head(__VA_ARGS__), metamacro_take19(metamacro_tail(__VA_ARGS__))
|
||||
|
||||
// metamacro_drop expansions
|
||||
#define metamacro_drop0(...) __VA_ARGS__
|
||||
#define metamacro_drop1(...) metamacro_tail(__VA_ARGS__)
|
||||
#define metamacro_drop2(...) metamacro_drop1(metamacro_tail(__VA_ARGS__))
|
||||
#define metamacro_drop3(...) metamacro_drop2(metamacro_tail(__VA_ARGS__))
|
||||
#define metamacro_drop4(...) metamacro_drop3(metamacro_tail(__VA_ARGS__))
|
||||
#define metamacro_drop5(...) metamacro_drop4(metamacro_tail(__VA_ARGS__))
|
||||
#define metamacro_drop6(...) metamacro_drop5(metamacro_tail(__VA_ARGS__))
|
||||
#define metamacro_drop7(...) metamacro_drop6(metamacro_tail(__VA_ARGS__))
|
||||
#define metamacro_drop8(...) metamacro_drop7(metamacro_tail(__VA_ARGS__))
|
||||
#define metamacro_drop9(...) metamacro_drop8(metamacro_tail(__VA_ARGS__))
|
||||
#define metamacro_drop10(...) metamacro_drop9(metamacro_tail(__VA_ARGS__))
|
||||
#define metamacro_drop11(...) metamacro_drop10(metamacro_tail(__VA_ARGS__))
|
||||
#define metamacro_drop12(...) metamacro_drop11(metamacro_tail(__VA_ARGS__))
|
||||
#define metamacro_drop13(...) metamacro_drop12(metamacro_tail(__VA_ARGS__))
|
||||
#define metamacro_drop14(...) metamacro_drop13(metamacro_tail(__VA_ARGS__))
|
||||
#define metamacro_drop15(...) metamacro_drop14(metamacro_tail(__VA_ARGS__))
|
||||
#define metamacro_drop16(...) metamacro_drop15(metamacro_tail(__VA_ARGS__))
|
||||
#define metamacro_drop17(...) metamacro_drop16(metamacro_tail(__VA_ARGS__))
|
||||
#define metamacro_drop18(...) metamacro_drop17(metamacro_tail(__VA_ARGS__))
|
||||
#define metamacro_drop19(...) metamacro_drop18(metamacro_tail(__VA_ARGS__))
|
||||
#define metamacro_drop20(...) metamacro_drop19(metamacro_tail(__VA_ARGS__))
|
||||
|
||||
#endif
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* This file is part of the SDWebImage package.
|
||||
* (c) Olivier Poitrey <rs@dailymotion.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
#import "SDWebImageCompat.h"
|
||||
|
||||
@interface UIColor (HexString)
|
||||
|
||||
/**
|
||||
Convenience way to get hex string from color. The output should always be 32-bit RGBA hex string like `#00000000`.
|
||||
*/
|
||||
@property (nonatomic, copy, readonly, nonnull) NSString *sd_hexString;
|
||||
|
||||
@end
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* This file is part of the SDWebImage package.
|
||||
* (c) Olivier Poitrey <rs@dailymotion.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
#import "UIColor+HexString.h"
|
||||
|
||||
@implementation UIColor (HexString)
|
||||
|
||||
- (NSString *)sd_hexString {
|
||||
CGFloat red, green, blue, alpha;
|
||||
#if SD_UIKIT
|
||||
if (![self getRed:&red green:&green blue:&blue alpha:&alpha]) {
|
||||
[self getWhite:&red alpha:&alpha];
|
||||
green = red;
|
||||
blue = red;
|
||||
}
|
||||
#else
|
||||
@try {
|
||||
[self getRed:&red green:&green blue:&blue alpha:&alpha];
|
||||
}
|
||||
@catch (NSException *exception) {
|
||||
[self getWhite:&red alpha:&alpha];
|
||||
green = red;
|
||||
blue = red;
|
||||
}
|
||||
#endif
|
||||
|
||||
red = roundf(red * 255.f);
|
||||
green = roundf(green * 255.f);
|
||||
blue = roundf(blue * 255.f);
|
||||
alpha = roundf(alpha * 255.f);
|
||||
|
||||
uint hex = ((uint)alpha << 24) | ((uint)red << 16) | ((uint)green << 8) | ((uint)blue);
|
||||
|
||||
return [NSString stringWithFormat:@"#%08x", hex];
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* This file is part of the SDWebImage package.
|
||||
* (c) Olivier Poitrey <rs@dailymotion.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
#import "SDWebImageCompat.h"
|
||||
#import "SDImageCoder.h"
|
||||
|
||||
|
||||
/**
|
||||
This is the protocol for SDAnimatedImage class only but not for SDAnimatedImageCoder. If you want to provide a custom animated image class with full advanced function, you can conform to this instead of the base protocol.
|
||||
*/
|
||||
@protocol SDAnimatedImage <SDAnimatedImageProvider>
|
||||
|
||||
@required
|
||||
/**
|
||||
Initializes and returns the image object with the specified data, scale factor and possible animation decoding options.
|
||||
@note We use this to create animated image instance for normal animation decoding.
|
||||
|
||||
@param data The data object containing the image data.
|
||||
@param scale The scale factor to assume when interpreting the image data. Applying a scale factor of 1.0 results in an image whose size matches the pixel-based dimensions of the image. Applying a different scale factor changes the size of the image as reported by the `size` property.
|
||||
@param options A dictionary containing any animation decoding options.
|
||||
@return An initialized object
|
||||
*/
|
||||
- (nullable instancetype)initWithData:(nonnull NSData *)data scale:(CGFloat)scale options:(nullable SDImageCoderOptions *)options;
|
||||
|
||||
/**
|
||||
Initializes the image with an animated coder. You can use the coder to decode the image frame later.
|
||||
@note We use this with animated coder which conforms to `SDProgressiveImageCoder` for progressive animation decoding.
|
||||
|
||||
@param animatedCoder An animated coder which conform `SDAnimatedImageCoder` protocol
|
||||
@param scale The scale factor to assume when interpreting the image data. Applying a scale factor of 1.0 results in an image whose size matches the pixel-based dimensions of the image. Applying a different scale factor changes the size of the image as reported by the `size` property.
|
||||
@return An initialized object
|
||||
*/
|
||||
- (nullable instancetype)initWithAnimatedCoder:(nonnull id<SDAnimatedImageCoder>)animatedCoder scale:(CGFloat)scale;
|
||||
|
||||
@optional
|
||||
// These methods are used for optional advanced feature, like image frame preloading.
|
||||
/**
|
||||
Pre-load all animated image frame into memory. Then later frame image request can directly return the frame for index without decoding.
|
||||
This method may be called on background thread.
|
||||
|
||||
@note If one image instance is shared by lots of imageViews, the CPU performance for large animated image will drop down because the request frame index will be random (not in order) and the decoder should take extra effort to keep it re-entrant. You can use this to reduce CPU usage if need. Attention this will consume more memory usage.
|
||||
*/
|
||||
- (void)preloadAllFrames;
|
||||
|
||||
/**
|
||||
Unload all animated image frame from memory if are already pre-loaded. Then later frame image request need decoding. You can use this to free up the memory usage if need.
|
||||
*/
|
||||
- (void)unloadAllFrames;
|
||||
|
||||
/**
|
||||
Returns a Boolean value indicating whether all animated image frames are already pre-loaded into memory.
|
||||
*/
|
||||
@property (nonatomic, assign, readonly, getter=isAllFramesLoaded) BOOL allFramesLoaded;
|
||||
|
||||
@end
|
||||
|
||||
@interface SDAnimatedImage : UIImage <SDAnimatedImage>
|
||||
|
||||
// This class override these methods from UIImage(NSImage), and it supports NSSecureCoding.
|
||||
// You should use these methods to create a new animated image. Use other methods just call super instead.
|
||||
+ (nullable instancetype)imageNamed:(nonnull NSString *)name; // Cache in memory, no Asset Catalog support
|
||||
#if __has_include(<UIKit/UITraitCollection.h>)
|
||||
+ (nullable instancetype)imageNamed:(nonnull NSString *)name inBundle:(nullable NSBundle *)bundle compatibleWithTraitCollection:(nullable UITraitCollection *)traitCollection; // Cache in memory, no Asset Catalog support
|
||||
#else
|
||||
+ (nullable instancetype)imageNamed:(nonnull NSString *)name inBundle:(nullable NSBundle *)bundle; // Cache in memory, no Asset Catalog support
|
||||
#endif
|
||||
+ (nullable instancetype)imageWithContentsOfFile:(nonnull NSString *)path;
|
||||
+ (nullable instancetype)imageWithData:(nonnull NSData *)data;
|
||||
+ (nullable instancetype)imageWithData:(nonnull NSData *)data scale:(CGFloat)scale;
|
||||
- (nullable instancetype)initWithContentsOfFile:(nonnull NSString *)path;
|
||||
- (nullable instancetype)initWithData:(nonnull NSData *)data;
|
||||
- (nullable instancetype)initWithData:(nonnull NSData *)data scale:(CGFloat)scale;
|
||||
|
||||
/**
|
||||
Current animated image format.
|
||||
*/
|
||||
@property (nonatomic, assign, readonly) SDImageFormat animatedImageFormat;
|
||||
|
||||
/**
|
||||
Current animated image data, you can use this instead of CGImage to create another instance.
|
||||
If the current image is not animated image, this value is nil.
|
||||
*/
|
||||
@property (nonatomic, copy, readonly, nullable) NSData *animatedImageData;
|
||||
|
||||
/**
|
||||
The scale factor of the image.
|
||||
|
||||
@note For UIKit, this just call super instead.
|
||||
@note For AppKit, `NSImage` can contains multiple image representations with different scales. However, this class does not do that from the design. We processs the scale like UIKit. This wil actually be calculated from image size and pixel size.
|
||||
*/
|
||||
@property (nonatomic, readonly) CGFloat scale;
|
||||
|
||||
// By default, animated image frames are returned by decoding just in time without keeping into memory. But you can choose to preload them into memory as well, See the decsription in `SDAnimatedImage` protocol.
|
||||
// After preloaded, there is no huge difference on performance between this and UIImage's `animatedImageWithImages:duration:`. But UIImage's animation have some issues such like blanking and pausing during segue when using in `UIImageView`. It's recommend to use only if need.
|
||||
- (void)preloadAllFrames;
|
||||
- (void)unloadAllFrames;
|
||||
@property (nonatomic, assign, readonly, getter=isAllFramesLoaded) BOOL allFramesLoaded;
|
||||
|
||||
@end
|
|
@ -0,0 +1,292 @@
|
|||
/*
|
||||
* This file is part of the SDWebImage package.
|
||||
* (c) Olivier Poitrey <rs@dailymotion.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
#import "SDAnimatedImage.h"
|
||||
#import "NSImage+Compatibility.h"
|
||||
#import "SDImageCoder.h"
|
||||
#import "SDImageCodersManager.h"
|
||||
#import "SDImageFrame.h"
|
||||
#import "UIImage+MemoryCacheCost.h"
|
||||
#import "SDImageAssetManager.h"
|
||||
#import "objc/runtime.h"
|
||||
|
||||
static CGFloat SDImageScaleFromPath(NSString *string) {
|
||||
if (string.length == 0 || [string hasSuffix:@"/"]) return 1;
|
||||
NSString *name = string.stringByDeletingPathExtension;
|
||||
__block CGFloat scale = 1;
|
||||
|
||||
NSRegularExpression *pattern = [NSRegularExpression regularExpressionWithPattern:@"@[0-9]+\\.?[0-9]*x$" options:NSRegularExpressionAnchorsMatchLines error:nil];
|
||||
[pattern enumerateMatchesInString:name options:kNilOptions range:NSMakeRange(0, name.length) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
|
||||
if (result.range.location >= 3) {
|
||||
scale = [string substringWithRange:NSMakeRange(result.range.location + 1, result.range.length - 2)].doubleValue;
|
||||
}
|
||||
}];
|
||||
|
||||
return scale;
|
||||
}
|
||||
|
||||
@interface SDAnimatedImage ()
|
||||
|
||||
@property (nonatomic, strong) id<SDAnimatedImageCoder> coder;
|
||||
@property (nonatomic, assign, readwrite) SDImageFormat animatedImageFormat;
|
||||
@property (atomic, copy) NSArray<SDImageFrame *> *loadedAnimatedImageFrames; // Mark as atomic to keep thread-safe
|
||||
@property (nonatomic, assign, getter=isAllFramesLoaded) BOOL allFramesLoaded;
|
||||
|
||||
@end
|
||||
|
||||
@implementation SDAnimatedImage
|
||||
@dynamic scale; // call super
|
||||
|
||||
#pragma mark - UIImage override method
|
||||
+ (instancetype)imageNamed:(NSString *)name {
|
||||
#if __has_include(<UIKit/UITraitCollection.h>)
|
||||
return [self imageNamed:name inBundle:nil compatibleWithTraitCollection:nil];
|
||||
#else
|
||||
return [self imageNamed:name inBundle:nil];
|
||||
#endif
|
||||
}
|
||||
|
||||
#if __has_include(<UIKit/UITraitCollection.h>)
|
||||
+ (instancetype)imageNamed:(NSString *)name inBundle:(NSBundle *)bundle compatibleWithTraitCollection:(UITraitCollection *)traitCollection {
|
||||
if (!traitCollection) {
|
||||
traitCollection = UIScreen.mainScreen.traitCollection;
|
||||
}
|
||||
CGFloat scale = traitCollection.displayScale;
|
||||
return [self imageNamed:name inBundle:bundle scale:scale];
|
||||
}
|
||||
#else
|
||||
+ (instancetype)imageNamed:(NSString *)name inBundle:(NSBundle *)bundle {
|
||||
return [self imageNamed:name inBundle:bundle scale:0];
|
||||
}
|
||||
#endif
|
||||
|
||||
// 0 scale means automatically check
|
||||
+ (instancetype)imageNamed:(NSString *)name inBundle:(NSBundle *)bundle scale:(CGFloat)scale {
|
||||
if (!name) {
|
||||
return nil;
|
||||
}
|
||||
if (!bundle) {
|
||||
bundle = [NSBundle mainBundle];
|
||||
}
|
||||
SDImageAssetManager *assetManager = [SDImageAssetManager sharedAssetManager];
|
||||
SDAnimatedImage *image = (SDAnimatedImage *)[assetManager imageForName:name];
|
||||
if ([image isKindOfClass:[SDAnimatedImage class]]) {
|
||||
return image;
|
||||
}
|
||||
NSString *path = [assetManager getPathForName:name bundle:bundle preferredScale:&scale];
|
||||
if (!path) {
|
||||
return image;
|
||||
}
|
||||
NSData *data = [NSData dataWithContentsOfFile:path];
|
||||
if (!data) {
|
||||
return image;
|
||||
}
|
||||
image = [[self alloc] initWithData:data scale:scale];
|
||||
if (image) {
|
||||
[assetManager storeImage:image forName:name];
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
+ (instancetype)imageWithContentsOfFile:(NSString *)path {
|
||||
return [[self alloc] initWithContentsOfFile:path];
|
||||
}
|
||||
|
||||
+ (instancetype)imageWithData:(NSData *)data {
|
||||
return [[self alloc] initWithData:data];
|
||||
}
|
||||
|
||||
+ (instancetype)imageWithData:(NSData *)data scale:(CGFloat)scale {
|
||||
return [[self alloc] initWithData:data scale:scale];
|
||||
}
|
||||
|
||||
- (instancetype)initWithContentsOfFile:(NSString *)path {
|
||||
NSData *data = [NSData dataWithContentsOfFile:path];
|
||||
return [self initWithData:data scale:SDImageScaleFromPath(path)];
|
||||
}
|
||||
|
||||
- (instancetype)initWithData:(NSData *)data {
|
||||
return [self initWithData:data scale:1];
|
||||
}
|
||||
|
||||
- (instancetype)initWithData:(NSData *)data scale:(CGFloat)scale {
|
||||
return [self initWithData:data scale:scale options:nil];
|
||||
}
|
||||
|
||||
- (instancetype)initWithData:(NSData *)data scale:(CGFloat)scale options:(SDImageCoderOptions *)options {
|
||||
if (!data || data.length == 0) {
|
||||
return nil;
|
||||
}
|
||||
data = [data copy]; // avoid mutable data
|
||||
id<SDAnimatedImageCoder> animatedCoder = nil;
|
||||
for (id<SDImageCoder>coder in [SDImageCodersManager sharedManager].coders) {
|
||||
if ([coder conformsToProtocol:@protocol(SDAnimatedImageCoder)]) {
|
||||
if ([coder canDecodeFromData:data]) {
|
||||
if (!options) {
|
||||
options = @{SDImageCoderDecodeScaleFactor : @(scale)};
|
||||
}
|
||||
animatedCoder = [[[coder class] alloc] initWithAnimatedImageData:data options:options];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!animatedCoder) {
|
||||
return nil;
|
||||
}
|
||||
return [self initWithAnimatedCoder:animatedCoder scale:scale];
|
||||
}
|
||||
|
||||
- (instancetype)initWithAnimatedCoder:(id<SDAnimatedImageCoder>)animatedCoder scale:(CGFloat)scale {
|
||||
if (!animatedCoder) {
|
||||
return nil;
|
||||
}
|
||||
if (scale <= 0) {
|
||||
scale = 1;
|
||||
}
|
||||
UIImage *image = [animatedCoder animatedImageFrameAtIndex:0];
|
||||
if (!image) {
|
||||
return nil;
|
||||
}
|
||||
#if SD_MAC
|
||||
self = [super initWithCGImage:image.CGImage scale:scale orientation:kCGImagePropertyOrientationUp];
|
||||
#else
|
||||
self = [super initWithCGImage:image.CGImage scale:scale orientation:image.imageOrientation];
|
||||
#endif
|
||||
if (self) {
|
||||
_coder = animatedCoder;
|
||||
NSData *data = [animatedCoder animatedImageData];
|
||||
SDImageFormat format = [NSData sd_imageFormatForImageData:data];
|
||||
_animatedImageFormat = format;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - Preload
|
||||
- (void)preloadAllFrames {
|
||||
if (!self.isAllFramesLoaded) {
|
||||
NSMutableArray<SDImageFrame *> *frames = [NSMutableArray arrayWithCapacity:self.animatedImageFrameCount];
|
||||
for (size_t i = 0; i < self.animatedImageFrameCount; i++) {
|
||||
UIImage *image = [self animatedImageFrameAtIndex:i];
|
||||
NSTimeInterval duration = [self animatedImageDurationAtIndex:i];
|
||||
SDImageFrame *frame = [SDImageFrame frameWithImage:image duration:duration]; // through the image should be nonnull, used as nullable for `animatedImageFrameAtIndex:`
|
||||
[frames addObject:frame];
|
||||
}
|
||||
self.loadedAnimatedImageFrames = frames;
|
||||
self.allFramesLoaded = YES;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)unloadAllFrames {
|
||||
if (self.isAllFramesLoaded) {
|
||||
self.loadedAnimatedImageFrames = nil;
|
||||
self.allFramesLoaded = NO;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - NSSecureCoding
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
||||
self = [super initWithCoder:aDecoder];
|
||||
if (self) {
|
||||
NSData *animatedImageData = [aDecoder decodeObjectOfClass:[NSData class] forKey:NSStringFromSelector(@selector(animatedImageData))];
|
||||
CGFloat scale = self.scale;
|
||||
if (!animatedImageData) {
|
||||
return self;
|
||||
}
|
||||
id<SDAnimatedImageCoder> animatedCoder = nil;
|
||||
for (id<SDImageCoder>coder in [SDImageCodersManager sharedManager].coders) {
|
||||
if ([coder conformsToProtocol:@protocol(SDAnimatedImageCoder)]) {
|
||||
if ([coder canDecodeFromData:animatedImageData]) {
|
||||
animatedCoder = [[[coder class] alloc] initWithAnimatedImageData:animatedImageData options:@{SDImageCoderDecodeScaleFactor : @(scale)}];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!animatedCoder) {
|
||||
return self;
|
||||
}
|
||||
_coder = animatedCoder;
|
||||
SDImageFormat format = [NSData sd_imageFormatForImageData:animatedImageData];
|
||||
_animatedImageFormat = format;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||
[super encodeWithCoder:aCoder];
|
||||
NSData *animatedImageData = self.animatedImageData;
|
||||
if (animatedImageData) {
|
||||
[aCoder encodeObject:animatedImageData forKey:NSStringFromSelector(@selector(animatedImageData))];
|
||||
}
|
||||
}
|
||||
|
||||
+ (BOOL)supportsSecureCoding {
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark - SDAnimatedImage
|
||||
|
||||
- (NSData *)animatedImageData {
|
||||
return [self.coder animatedImageData];
|
||||
}
|
||||
|
||||
- (NSUInteger)animatedImageLoopCount {
|
||||
return [self.coder animatedImageLoopCount];
|
||||
}
|
||||
|
||||
- (NSUInteger)animatedImageFrameCount {
|
||||
return [self.coder animatedImageFrameCount];
|
||||
}
|
||||
|
||||
- (UIImage *)animatedImageFrameAtIndex:(NSUInteger)index {
|
||||
if (index >= self.animatedImageFrameCount) {
|
||||
return nil;
|
||||
}
|
||||
if (self.isAllFramesLoaded) {
|
||||
SDImageFrame *frame = [self.loadedAnimatedImageFrames objectAtIndex:index];
|
||||
return frame.image;
|
||||
}
|
||||
return [self.coder animatedImageFrameAtIndex:index];
|
||||
}
|
||||
|
||||
- (NSTimeInterval)animatedImageDurationAtIndex:(NSUInteger)index {
|
||||
if (index >= self.animatedImageFrameCount) {
|
||||
return 0;
|
||||
}
|
||||
if (self.isAllFramesLoaded) {
|
||||
SDImageFrame *frame = [self.loadedAnimatedImageFrames objectAtIndex:index];
|
||||
return frame.duration;
|
||||
}
|
||||
return [self.coder animatedImageDurationAtIndex:index];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation SDAnimatedImage (MemoryCacheCost)
|
||||
|
||||
- (NSUInteger)sd_memoryCost {
|
||||
NSNumber *value = objc_getAssociatedObject(self, @selector(sd_memoryCost));
|
||||
if (value != nil) {
|
||||
return value.unsignedIntegerValue;
|
||||
}
|
||||
|
||||
CGImageRef imageRef = self.CGImage;
|
||||
if (!imageRef) {
|
||||
return 0;
|
||||
}
|
||||
NSUInteger bytesPerFrame = CGImageGetBytesPerRow(imageRef) * CGImageGetHeight(imageRef);
|
||||
NSUInteger frameCount = 1;
|
||||
if (self.isAllFramesLoaded) {
|
||||
frameCount = self.animatedImageFrameCount;
|
||||
}
|
||||
frameCount = frameCount > 0 ? frameCount : 1;
|
||||
NSUInteger cost = bytesPerFrame * frameCount;
|
||||
return cost;
|
||||
}
|
||||
|
||||
@end
|
|
@ -11,7 +11,8 @@
|
|||
#if SD_MAC
|
||||
|
||||
// A subclass of `NSBitmapImageRep` to fix that GIF loop count issue because `NSBitmapImageRep` will reset `NSImageCurrentFrameDuration` by using `kCGImagePropertyGIFDelayTime` but not `kCGImagePropertyGIFUnclampedDelayTime`.
|
||||
// Built in GIF coder use this instead of `NSBitmapImageRep` for better GIF rendering. If you do not want this, only enable `SDWebImageImageIOCoder`, which just call `NSImage` API and actually use `NSBitmapImageRep` for GIF image.
|
||||
// Built in GIF coder use this instead of `NSBitmapImageRep` for better GIF rendering. If you do not want this, only enable `SDImageIOCoder`, which just call `NSImage` API and actually use `NSBitmapImageRep` for GIF image.
|
||||
// This also support APNG format using `SDImageAPNGCoder`. Which provide full alpha-channel support and the correct duration match the `kCGImagePropertyAPNGUnclampedDelayTime`.
|
||||
|
||||
@interface SDAnimatedImageRep : NSBitmapImageRep
|
||||
|
||||
|
|
|
@ -10,13 +10,8 @@
|
|||
|
||||
#if SD_MAC
|
||||
|
||||
#import "SDWebImageGIFCoder.h"
|
||||
|
||||
@interface SDWebImageGIFCoder ()
|
||||
|
||||
- (float)sd_frameDurationAtIndex:(NSUInteger)index source:(CGImageSourceRef)source;
|
||||
|
||||
@end
|
||||
#import "SDImageGIFCoderInternal.h"
|
||||
#import "SDImageAPNGCoderInternal.h"
|
||||
|
||||
@interface SDAnimatedImageRep ()
|
||||
|
||||
|
@ -26,6 +21,43 @@
|
|||
|
||||
@implementation SDAnimatedImageRep
|
||||
|
||||
// `NSBitmapImageRep`'s `imageRepWithData:` is not designed initlizer
|
||||
+ (instancetype)imageRepWithData:(NSData *)data {
|
||||
SDAnimatedImageRep *imageRep = [[SDAnimatedImageRep alloc] initWithData:data];
|
||||
return imageRep;
|
||||
}
|
||||
|
||||
// We should override init method for `NSBitmapImageRep` to do initlize about animated image format
|
||||
- (instancetype)initWithData:(NSData *)data {
|
||||
self = [super initWithData:data];
|
||||
if (self) {
|
||||
CGImageSourceRef imageSource = self.imageSource;
|
||||
if (!imageSource) {
|
||||
return self;
|
||||
}
|
||||
NSUInteger frameCount = CGImageSourceGetCount(imageSource);
|
||||
if (frameCount <= 1) {
|
||||
return self;
|
||||
}
|
||||
CFStringRef type = CGImageSourceGetType(imageSource);
|
||||
if (!type) {
|
||||
return self;
|
||||
}
|
||||
if (CFStringCompare(type, kUTTypeGIF, 0) == kCFCompareEqualTo) {
|
||||
// GIF
|
||||
// Do nothing because NSBitmapImageRep support it
|
||||
} else if (CFStringCompare(type, kUTTypePNG, 0) == kCFCompareEqualTo) {
|
||||
// APNG
|
||||
// Do initilize about frame count, current frame/duration and loop count
|
||||
[self setProperty:NSImageFrameCount withValue:@(frameCount)];
|
||||
[self setProperty:NSImageCurrentFrame withValue:@(0)];
|
||||
NSUInteger loopCount = [[SDImageAPNGCoder sharedCoder] sd_imageLoopCountWithSource:imageSource];
|
||||
[self setProperty:NSImageLoopCount withValue:@(loopCount)];
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
// `NSBitmapImageRep` will use `kCGImagePropertyGIFDelayTime` whenever you call `setProperty:withValue:` with `NSImageCurrentFrame` to change the current frame. We override it and use the actual `kCGImagePropertyGIFUnclampedDelayTime` if need.
|
||||
- (void)setProperty:(NSBitmapImageRepPropertyKey)property withValue:(id)value {
|
||||
[super setProperty:property withValue:value];
|
||||
|
@ -42,9 +74,12 @@
|
|||
}
|
||||
NSUInteger index = [value unsignedIntegerValue];
|
||||
float frameDuration = 0;
|
||||
// Through we currently process GIF only, in the 5.x we support APNG so we keep the extensibility
|
||||
if (CFStringCompare(type, kUTTypeGIF, 0) == kCFCompareEqualTo) {
|
||||
frameDuration = [[SDWebImageGIFCoder sharedCoder] sd_frameDurationAtIndex:index source:imageSource];
|
||||
// GIF
|
||||
frameDuration = [[SDImageGIFCoder sharedCoder] sd_frameDurationAtIndex:index source:imageSource];
|
||||
} else if (CFStringCompare(type, kUTTypePNG, 0) == kCFCompareEqualTo) {
|
||||
// APNG
|
||||
frameDuration = [[SDImageAPNGCoder sharedCoder] sd_frameDurationAtIndex:index source:imageSource];
|
||||
}
|
||||
if (!frameDuration) {
|
||||
return;
|
||||
|
@ -55,9 +90,12 @@
|
|||
}
|
||||
|
||||
- (CGImageSourceRef)imageSource {
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
if (_tiffData) {
|
||||
return (__bridge CGImageSourceRef)(_tiffData);
|
||||
}
|
||||
#pragma GCC diagnostic pop
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
* This file is part of the SDWebImage package.
|
||||
* (c) Olivier Poitrey <rs@dailymotion.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
#import "SDAnimatedImageView.h"
|
||||
|
||||
#if SD_UIKIT || SD_MAC
|
||||
|
||||
#import "SDWebImageManager.h"
|
||||
|
||||
@interface SDAnimatedImageView (WebCache)
|
||||
|
||||
/**
|
||||
* Set the imageView `image` with an `url`.
|
||||
*
|
||||
* The download is asynchronous and cached.
|
||||
*
|
||||
* @param url The url for the image.
|
||||
*/
|
||||
- (void)sd_setImageWithURL:(nullable NSURL *)url NS_REFINED_FOR_SWIFT;
|
||||
|
||||
/**
|
||||
* Set the imageView `image` with an `url` and a placeholder.
|
||||
*
|
||||
* The download is asynchronous and cached.
|
||||
*
|
||||
* @param url The url for the image.
|
||||
* @param placeholder The image to be set initially, until the image request finishes.
|
||||
* @see sd_setImageWithURL:placeholderImage:options:
|
||||
*/
|
||||
- (void)sd_setImageWithURL:(nullable NSURL *)url
|
||||
placeholderImage:(nullable UIImage *)placeholder NS_REFINED_FOR_SWIFT;
|
||||
|
||||
/**
|
||||
* Set the imageView `image` with an `url`, placeholder and custom options.
|
||||
*
|
||||
* The download is asynchronous and cached.
|
||||
*
|
||||
* @param url The url for the image.
|
||||
* @param placeholder The image to be set initially, until the image request finishes.
|
||||
* @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values.
|
||||
*/
|
||||
- (void)sd_setImageWithURL:(nullable NSURL *)url
|
||||
placeholderImage:(nullable UIImage *)placeholder
|
||||
options:(SDWebImageOptions)options NS_REFINED_FOR_SWIFT;
|
||||
|
||||
/**
|
||||
* Set the imageView `image` with an `url`, placeholder, custom options and context.
|
||||
*
|
||||
* The download is asynchronous and cached.
|
||||
*
|
||||
* @param url The url for the image.
|
||||
* @param placeholder The image to be set initially, until the image request finishes.
|
||||
* @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values.
|
||||
* @param context A context contains different options to perform specify changes or processes, see `SDWebImageContextOption`. This hold the extra objects which `options` enum can not hold.
|
||||
*/
|
||||
- (void)sd_setImageWithURL:(nullable NSURL *)url
|
||||
placeholderImage:(nullable UIImage *)placeholder
|
||||
options:(SDWebImageOptions)options
|
||||
context:(nullable SDWebImageContext *)context;
|
||||
|
||||
/**
|
||||
* Set the imageView `image` with an `url`.
|
||||
*
|
||||
* The download is asynchronous and cached.
|
||||
*
|
||||
* @param url The url for the image.
|
||||
* @param completedBlock A block called when operation has been completed. This block has no return value
|
||||
* and takes the requested UIImage as first parameter. In case of error the image parameter
|
||||
* is nil and the second parameter may contain an NSError. The third parameter is a Boolean
|
||||
* indicating if the image was retrieved from the local cache or from the network.
|
||||
* The fourth parameter is the original image url.
|
||||
*/
|
||||
- (void)sd_setImageWithURL:(nullable NSURL *)url
|
||||
completed:(nullable SDExternalCompletionBlock)completedBlock;
|
||||
|
||||
/**
|
||||
* Set the imageView `image` with an `url`, placeholder.
|
||||
*
|
||||
* The download is asynchronous and cached.
|
||||
*
|
||||
* @param url The url for the image.
|
||||
* @param placeholder The image to be set initially, until the image request finishes.
|
||||
* @param completedBlock A block called when operation has been completed. This block has no return value
|
||||
* and takes the requested UIImage as first parameter. In case of error the image parameter
|
||||
* is nil and the second parameter may contain an NSError. The third parameter is a Boolean
|
||||
* indicating if the image was retrieved from the local cache or from the network.
|
||||
* The fourth parameter is the original image url.
|
||||
*/
|
||||
- (void)sd_setImageWithURL:(nullable NSURL *)url
|
||||
placeholderImage:(nullable UIImage *)placeholder
|
||||
completed:(nullable SDExternalCompletionBlock)completedBlock NS_REFINED_FOR_SWIFT;
|
||||
|
||||
/**
|
||||
* Set the imageView `image` with an `url`, placeholder and custom options.
|
||||
*
|
||||
* The download is asynchronous and cached.
|
||||
*
|
||||
* @param url The url for the image.
|
||||
* @param placeholder The image to be set initially, until the image request finishes.
|
||||
* @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values.
|
||||
* @param completedBlock A block called when operation has been completed. This block has no return value
|
||||
* and takes the requested UIImage as first parameter. In case of error the image parameter
|
||||
* is nil and the second parameter may contain an NSError. The third parameter is a Boolean
|
||||
* indicating if the image was retrieved from the local cache or from the network.
|
||||
* The fourth parameter is the original image url.
|
||||
*/
|
||||
- (void)sd_setImageWithURL:(nullable NSURL *)url
|
||||
placeholderImage:(nullable UIImage *)placeholder
|
||||
options:(SDWebImageOptions)options
|
||||
completed:(nullable SDExternalCompletionBlock)completedBlock;
|
||||
|
||||
/**
|
||||
* Set the imageView `image` with an `url`, placeholder and custom options.
|
||||
*
|
||||
* The download is asynchronous and cached.
|
||||
*
|
||||
* @param url The url for the image.
|
||||
* @param placeholder The image to be set initially, until the image request finishes.
|
||||
* @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values.
|
||||
* @param progressBlock A block called while image is downloading
|
||||
* @note the progress block is executed on a background queue
|
||||
* @param completedBlock A block called when operation has been completed. This block has no return value
|
||||
* and takes the requested UIImage as first parameter. In case of error the image parameter
|
||||
* is nil and the second parameter may contain an NSError. The third parameter is a Boolean
|
||||
* indicating if the image was retrieved from the local cache or from the network.
|
||||
* The fourth parameter is the original image url.
|
||||
*/
|
||||
- (void)sd_setImageWithURL:(nullable NSURL *)url
|
||||
placeholderImage:(nullable UIImage *)placeholder
|
||||
options:(SDWebImageOptions)options
|
||||
progress:(nullable SDImageLoaderProgressBlock)progressBlock
|
||||
completed:(nullable SDExternalCompletionBlock)completedBlock;
|
||||
|
||||
/**
|
||||
* Set the imageView `image` with an `url`, placeholder, custom options and context.
|
||||
*
|
||||
* The download is asynchronous and cached.
|
||||
*
|
||||
* @param url The url for the image.
|
||||
* @param placeholder The image to be set initially, until the image request finishes.
|
||||
* @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values.
|
||||
* @param context A context contains different options to perform specify changes or processes, see `SDWebImageContextOption`. This hold the extra objects which `options` enum can not hold.
|
||||
* @param progressBlock A block called while image is downloading
|
||||
* @note the progress block is executed on a background queue
|
||||
* @param completedBlock A block called when operation has been completed. This block has no return value
|
||||
* and takes the requested UIImage as first parameter. In case of error the image parameter
|
||||
* is nil and the second parameter may contain an NSError. The third parameter is a Boolean
|
||||
* indicating if the image was retrieved from the local cache or from the network.
|
||||
* The fourth parameter is the original image url.
|
||||
*/
|
||||
- (void)sd_setImageWithURL:(nullable NSURL *)url
|
||||
placeholderImage:(nullable UIImage *)placeholder
|
||||
options:(SDWebImageOptions)options
|
||||
context:(nullable SDWebImageContext *)context
|
||||
progress:(nullable SDImageLoaderProgressBlock)progressBlock
|
||||
completed:(nullable SDExternalCompletionBlock)completedBlock;
|
||||
|
||||
@end
|
||||
|
||||
#endif
|