├── CDDGroupAvatar.gif ├── Demo └── CDDGroupAvatar │ ├── Pods │ ├── Headers │ │ ├── Private │ │ │ └── SDWebImage │ │ │ │ ├── SDWebImage.h │ │ │ │ ├── SDDiskCache.h │ │ │ │ ├── SDImageCache.h │ │ │ │ ├── SDImageCoder.h │ │ │ │ ├── SDImageFrame.h │ │ │ │ ├── SDImageLoader.h │ │ │ │ ├── SDMemoryCache.h │ │ │ │ ├── SDWeakProxy.h │ │ │ │ ├── UIImage+GIF.h │ │ │ │ ├── SDAnimatedImage.h │ │ │ │ ├── SDImageGIFCoder.h │ │ │ │ ├── SDImageGraphics.h │ │ │ │ ├── SDImageIOCoder.h │ │ │ │ ├── SDWebImageError.h │ │ │ │ ├── SDmetamacros.h │ │ │ │ ├── UIView+WebCache.h │ │ │ │ ├── NSButton+WebCache.h │ │ │ │ ├── SDAnimatedImageRep.h │ │ │ │ ├── SDImageAPNGCoder.h │ │ │ │ ├── SDImageCacheConfig.h │ │ │ │ ├── SDImageCacheDefine.h │ │ │ │ ├── SDImageCoderHelper.h │ │ │ │ ├── SDImageTransformer.h │ │ │ │ ├── SDInternalMacros.h │ │ │ │ ├── SDWebImageCompat.h │ │ │ │ ├── SDWebImageDefine.h │ │ │ │ ├── SDWebImageManager.h │ │ │ │ ├── UIButton+WebCache.h │ │ │ │ ├── UIImage+Metadata.h │ │ │ │ ├── UIImage+Transform.h │ │ │ │ ├── SDAnimatedImageView.h │ │ │ │ ├── SDImageAssetManager.h │ │ │ │ ├── SDImageCachesManager.h │ │ │ │ ├── SDImageCodersManager.h │ │ │ │ ├── SDWebImageDownloader.h │ │ │ │ ├── SDWebImageIndicator.h │ │ │ │ ├── SDWebImageOperation.h │ │ │ │ ├── SDWebImagePrefetcher.h │ │ │ │ ├── SDWebImageTransition.h │ │ │ │ ├── UIImage+ForceDecode.h │ │ │ │ ├── UIImage+MultiFormat.h │ │ │ │ ├── UIImageView+WebCache.h │ │ │ │ ├── NSData+ImageContentType.h │ │ │ │ ├── NSImage+Compatibility.h │ │ │ │ ├── SDAsyncBlockOperation.h │ │ │ │ ├── SDImageLoadersManager.h │ │ │ │ ├── UIImage+MemoryCacheCost.h │ │ │ │ ├── SDWebImageCacheKeyFilter.h │ │ │ │ ├── SDWebImageCacheSerializer.h │ │ │ │ ├── UIView+WebCacheOperation.h │ │ │ │ ├── SDAnimatedImageView+WebCache.h │ │ │ │ ├── SDWebImageDownloaderConfig.h │ │ │ │ ├── SDImageCachesManagerOperation.h │ │ │ │ ├── SDWebImageDownloaderOperation.h │ │ │ │ ├── UIImageView+HighlightedWebCache.h │ │ │ │ └── SDWebImageDownloaderRequestModifier.h │ │ └── Public │ │ │ └── SDWebImage │ │ │ ├── SDWebImage.h │ │ │ ├── SDDiskCache.h │ │ │ ├── UIImage+GIF.h │ │ │ ├── SDImageCache.h │ │ │ ├── SDImageCoder.h │ │ │ ├── SDImageFrame.h │ │ │ ├── SDImageLoader.h │ │ │ ├── SDMemoryCache.h │ │ │ ├── SDAnimatedImage.h │ │ │ ├── SDImageAPNGCoder.h │ │ │ ├── SDImageGIFCoder.h │ │ │ ├── SDImageGraphics.h │ │ │ ├── SDImageIOCoder.h │ │ │ ├── SDWebImageCompat.h │ │ │ ├── SDWebImageDefine.h │ │ │ ├── SDWebImageError.h │ │ │ ├── UIImage+Metadata.h │ │ │ ├── UIView+WebCache.h │ │ │ ├── NSButton+WebCache.h │ │ │ ├── SDAnimatedImageRep.h │ │ │ ├── SDImageCacheConfig.h │ │ │ ├── SDImageCacheDefine.h │ │ │ ├── SDImageCoderHelper.h │ │ │ ├── SDImageTransformer.h │ │ │ ├── SDWebImageManager.h │ │ │ ├── UIButton+WebCache.h │ │ │ ├── UIImage+Transform.h │ │ │ ├── NSImage+Compatibility.h │ │ │ ├── SDAnimatedImageView.h │ │ │ ├── SDImageCachesManager.h │ │ │ ├── SDImageCodersManager.h │ │ │ ├── SDImageLoadersManager.h │ │ │ ├── SDWebImageDownloader.h │ │ │ ├── SDWebImageIndicator.h │ │ │ ├── SDWebImageOperation.h │ │ │ ├── SDWebImagePrefetcher.h │ │ │ ├── SDWebImageTransition.h │ │ │ ├── UIImage+ForceDecode.h │ │ │ ├── UIImage+MultiFormat.h │ │ │ ├── UIImageView+WebCache.h │ │ │ ├── NSData+ImageContentType.h │ │ │ ├── UIImage+MemoryCacheCost.h │ │ │ ├── SDWebImageCacheKeyFilter.h │ │ │ ├── SDWebImageCacheSerializer.h │ │ │ ├── SDWebImageDownloaderConfig.h │ │ │ ├── UIView+WebCacheOperation.h │ │ │ ├── SDAnimatedImageView+WebCache.h │ │ │ ├── SDWebImageDownloaderOperation.h │ │ │ ├── UIImageView+HighlightedWebCache.h │ │ │ └── SDWebImageDownloaderRequestModifier.h │ ├── Target Support Files │ │ ├── SDWebImage │ │ │ ├── SDWebImage-dummy.m │ │ │ └── SDWebImage-prefix.pch │ │ └── Pods-CDDGroupAvatar │ │ │ ├── Pods-CDDGroupAvatar-dummy.m │ │ │ ├── Pods-CDDGroupAvatar.debug.xcconfig │ │ │ ├── Pods-CDDGroupAvatar.release.xcconfig │ │ │ ├── Pods-CDDGroupAvatar-acknowledgements.markdown │ │ │ └── Pods-CDDGroupAvatar-acknowledgements.plist │ ├── Manifest.lock │ └── SDWebImage │ │ ├── SDWebImage │ │ └── Private │ │ │ ├── SDInternalMacros.m │ │ │ ├── SDWeakProxy.h │ │ │ ├── SDImageCachesManagerOperation.h │ │ │ ├── SDAsyncBlockOperation.h │ │ │ ├── SDImageAssetManager.h │ │ │ ├── SDWeakProxy.m │ │ │ ├── SDImageCachesManagerOperation.m │ │ │ ├── SDAsyncBlockOperation.m │ │ │ ├── SDInternalMacros.h │ │ │ └── SDImageAssetManager.m │ │ ├── LICENSE │ │ └── WebImage │ │ └── SDWebImage.h │ ├── CDDGroupAvatar │ ├── Assets.xcassets │ │ ├── Contents.json │ │ ├── man.imageset │ │ │ ├── man@2x.png │ │ │ ├── man@3x.png │ │ │ └── Contents.json │ │ ├── place.imageset │ │ │ ├── place@2x.png │ │ │ └── Contents.json │ │ ├── woman.imageset │ │ │ ├── woman@2x.png │ │ │ ├── woman@3x.png │ │ │ └── Contents.json │ │ ├── noCache1.imageset │ │ │ ├── noCache1.png │ │ │ └── Contents.json │ │ ├── noCache2.imageset │ │ │ ├── noCache2.png │ │ │ └── Contents.json │ │ ├── noCache3.imageset │ │ │ ├── noCache3.png │ │ │ └── Contents.json │ │ ├── noCache4.imageset │ │ │ ├── noCache4.png │ │ │ └── Contents.json │ │ ├── avatarholder.imageset │ │ │ ├── avatarholder.png │ │ │ └── Contents.json │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── PFS │ │ └── KMCGeigerCounter │ │ │ ├── KMCGeigerCounterTick.aiff │ │ │ ├── KMCGeigerCounter.h │ │ │ └── KMCGeigerCounter.m │ ├── ViewController.h │ ├── AppDelegate.h │ ├── main.m │ ├── DCTestViewController.h │ ├── Info.plist │ ├── Base.lproj │ │ └── LaunchScreen.storyboard │ ├── AppDelegate.m │ ├── DCTestViewController.m │ └── ViewController.m │ ├── Podfile │ ├── CDDGroupAvatar.xcodeproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ └── xcshareddata │ │ └── xcschemes │ │ └── CDDGroupAvatar.xcscheme │ ├── CDDGroupAvatar.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist │ └── Podfile.lock ├── CDDGroupAvatar ├── CacheGroupAvatar │ ├── DCImageCacheKey.m │ ├── DCAvatar.h │ ├── DCImageCacheKey.h │ ├── UIView+DCGroup.h │ ├── DCCacheAvatarHelper.h │ ├── DCAvatarManager.h │ ├── DCAvatarManager.m │ ├── UIImageView+DCGroup.m │ ├── UIImageView+DCGroup.h │ ├── UIButton+DCGroup.h │ ├── UIButton+DCGroup.m │ ├── DCCacheAvatarHelper.m │ └── UIView+DCGroup.m ├── NoCacheGroupAvatar │ ├── DCNoCacheAvatar.h │ ├── UIView+DCNoCacheGroup.h │ ├── DCNoCahceAvatarManager.h │ ├── UIImageView+DCNoCacheGroup.m │ ├── UIImageView+DCNoCacheGroup.h │ ├── DCNoCahceAvatarManager.m │ ├── UIButton+DCNoCacheGroup.h │ ├── UIButton+DCNoCacheGroup.m │ └── UIView+DCNoCacheGroup.m └── AvatarConfig │ ├── UIImage+DCAvatar.h │ ├── DCAvatarHelper.h │ ├── UIImage+DCAvatar.m │ ├── DCAvatarConfig.h │ └── DCAvatarHelper.m ├── .gitignore ├── CDDGroupAvatar.podspec ├── README.md └── LICENSE /CDDGroupAvatar.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RocketsChen/CDDGroupAvatar/HEAD/CDDGroupAvatar.gif -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/SDWebImage.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/WebImage/SDWebImage.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Public/SDWebImage/SDWebImage.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/WebImage/SDWebImage.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Public/SDWebImage/SDDiskCache.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDDiskCache.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Public/SDWebImage/UIImage+GIF.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/UIImage+GIF.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/SDDiskCache.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDDiskCache.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/SDImageCache.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDImageCache.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/SDImageCoder.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDImageCoder.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/SDImageFrame.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDImageFrame.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/SDImageLoader.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDImageLoader.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/SDMemoryCache.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDMemoryCache.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/SDWeakProxy.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Private/SDWeakProxy.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/UIImage+GIF.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/UIImage+GIF.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Public/SDWebImage/SDImageCache.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDImageCache.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Public/SDWebImage/SDImageCoder.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDImageCoder.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Public/SDWebImage/SDImageFrame.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDImageFrame.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Public/SDWebImage/SDImageLoader.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDImageLoader.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Public/SDWebImage/SDMemoryCache.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDMemoryCache.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/SDAnimatedImage.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDAnimatedImage.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/SDImageGIFCoder.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDImageGIFCoder.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/SDImageGraphics.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDImageGraphics.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/SDImageIOCoder.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDImageIOCoder.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/SDWebImageError.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDWebImageError.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/SDmetamacros.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Private/SDmetamacros.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/UIView+WebCache.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/UIView+WebCache.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Public/SDWebImage/SDAnimatedImage.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDAnimatedImage.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Public/SDWebImage/SDImageAPNGCoder.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDImageAPNGCoder.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Public/SDWebImage/SDImageGIFCoder.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDImageGIFCoder.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Public/SDWebImage/SDImageGraphics.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDImageGraphics.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Public/SDWebImage/SDImageIOCoder.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDImageIOCoder.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Public/SDWebImage/SDWebImageCompat.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDWebImageCompat.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Public/SDWebImage/SDWebImageDefine.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDWebImageDefine.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Public/SDWebImage/SDWebImageError.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDWebImageError.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Public/SDWebImage/UIImage+Metadata.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/UIImage+Metadata.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Public/SDWebImage/UIView+WebCache.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/UIView+WebCache.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/NSButton+WebCache.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/NSButton+WebCache.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/SDAnimatedImageRep.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDAnimatedImageRep.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/SDImageAPNGCoder.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDImageAPNGCoder.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/SDImageCacheConfig.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDImageCacheConfig.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/SDImageCacheDefine.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDImageCacheDefine.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/SDImageCoderHelper.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDImageCoderHelper.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/SDImageTransformer.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDImageTransformer.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/SDInternalMacros.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Private/SDInternalMacros.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/SDWebImageCompat.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDWebImageCompat.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/SDWebImageDefine.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDWebImageDefine.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/SDWebImageManager.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDWebImageManager.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/UIButton+WebCache.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/UIButton+WebCache.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/UIImage+Metadata.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/UIImage+Metadata.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/UIImage+Transform.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/UIImage+Transform.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Public/SDWebImage/NSButton+WebCache.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/NSButton+WebCache.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Public/SDWebImage/SDAnimatedImageRep.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDAnimatedImageRep.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Public/SDWebImage/SDImageCacheConfig.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDImageCacheConfig.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Public/SDWebImage/SDImageCacheDefine.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDImageCacheDefine.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Public/SDWebImage/SDImageCoderHelper.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDImageCoderHelper.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Public/SDWebImage/SDImageTransformer.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDImageTransformer.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Public/SDWebImage/SDWebImageManager.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDWebImageManager.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Public/SDWebImage/UIButton+WebCache.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/UIButton+WebCache.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Public/SDWebImage/UIImage+Transform.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/UIImage+Transform.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/SDAnimatedImageView.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDAnimatedImageView.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/SDImageAssetManager.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Private/SDImageAssetManager.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/SDImageCachesManager.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDImageCachesManager.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/SDImageCodersManager.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDImageCodersManager.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/SDWebImageDownloader.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDWebImageDownloader.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/SDWebImageIndicator.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDWebImageIndicator.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/SDWebImageOperation.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDWebImageOperation.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/SDWebImagePrefetcher.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDWebImagePrefetcher.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/SDWebImageTransition.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDWebImageTransition.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/UIImage+ForceDecode.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/UIImage+ForceDecode.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/UIImage+MultiFormat.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/UIImage+MultiFormat.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/UIImageView+WebCache.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/UIImageView+WebCache.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Public/SDWebImage/NSImage+Compatibility.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/NSImage+Compatibility.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Public/SDWebImage/SDAnimatedImageView.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDAnimatedImageView.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Public/SDWebImage/SDImageCachesManager.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDImageCachesManager.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Public/SDWebImage/SDImageCodersManager.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDImageCodersManager.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Public/SDWebImage/SDImageLoadersManager.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDImageLoadersManager.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Public/SDWebImage/SDWebImageDownloader.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDWebImageDownloader.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Public/SDWebImage/SDWebImageIndicator.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDWebImageIndicator.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Public/SDWebImage/SDWebImageOperation.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDWebImageOperation.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Public/SDWebImage/SDWebImagePrefetcher.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDWebImagePrefetcher.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Public/SDWebImage/SDWebImageTransition.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDWebImageTransition.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Public/SDWebImage/UIImage+ForceDecode.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/UIImage+ForceDecode.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Public/SDWebImage/UIImage+MultiFormat.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/UIImage+MultiFormat.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Public/SDWebImage/UIImageView+WebCache.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/UIImageView+WebCache.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/NSData+ImageContentType.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/NSData+ImageContentType.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/NSImage+Compatibility.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/NSImage+Compatibility.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/SDAsyncBlockOperation.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Private/SDAsyncBlockOperation.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/SDImageLoadersManager.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDImageLoadersManager.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/UIImage+MemoryCacheCost.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/UIImage+MemoryCacheCost.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Public/SDWebImage/NSData+ImageContentType.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/NSData+ImageContentType.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Public/SDWebImage/UIImage+MemoryCacheCost.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/UIImage+MemoryCacheCost.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/SDWebImageCacheKeyFilter.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDWebImageCacheKeyFilter.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/SDWebImageCacheSerializer.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDWebImageCacheSerializer.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/UIView+WebCacheOperation.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/UIView+WebCacheOperation.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Public/SDWebImage/SDWebImageCacheKeyFilter.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDWebImageCacheKeyFilter.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Public/SDWebImage/SDWebImageCacheSerializer.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDWebImageCacheSerializer.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Public/SDWebImage/SDWebImageDownloaderConfig.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDWebImageDownloaderConfig.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Public/SDWebImage/UIView+WebCacheOperation.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/UIView+WebCacheOperation.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/CDDGroupAvatar/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/SDAnimatedImageView+WebCache.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDAnimatedImageView+WebCache.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/SDWebImageDownloaderConfig.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDWebImageDownloaderConfig.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Public/SDWebImage/SDAnimatedImageView+WebCache.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDAnimatedImageView+WebCache.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/SDImageCachesManagerOperation.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Private/SDImageCachesManagerOperation.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/SDWebImageDownloaderOperation.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDWebImageDownloaderOperation.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Public/SDWebImage/SDWebImageDownloaderOperation.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDWebImageDownloaderOperation.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Public/SDWebImage/UIImageView+HighlightedWebCache.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/UIImageView+HighlightedWebCache.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/UIImageView+HighlightedWebCache.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/UIImageView+HighlightedWebCache.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Private/SDWebImage/SDWebImageDownloaderRequestModifier.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDWebImageDownloaderRequestModifier.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Headers/Public/SDWebImage/SDWebImageDownloaderRequestModifier.h: -------------------------------------------------------------------------------- 1 | ../../../SDWebImage/SDWebImage/Core/SDWebImageDownloaderRequestModifier.h -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment the next line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | target 'CDDGroupAvatar' do 5 | 6 | pod 'SDWebImage' 7 | 8 | end 9 | -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/CDDGroupAvatar/Assets.xcassets/man.imageset/man@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RocketsChen/CDDGroupAvatar/HEAD/Demo/CDDGroupAvatar/CDDGroupAvatar/Assets.xcassets/man.imageset/man@2x.png -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/CDDGroupAvatar/Assets.xcassets/man.imageset/man@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RocketsChen/CDDGroupAvatar/HEAD/Demo/CDDGroupAvatar/CDDGroupAvatar/Assets.xcassets/man.imageset/man@3x.png -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/CDDGroupAvatar/Assets.xcassets/place.imageset/place@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RocketsChen/CDDGroupAvatar/HEAD/Demo/CDDGroupAvatar/CDDGroupAvatar/Assets.xcassets/place.imageset/place@2x.png -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/CDDGroupAvatar/Assets.xcassets/woman.imageset/woman@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RocketsChen/CDDGroupAvatar/HEAD/Demo/CDDGroupAvatar/CDDGroupAvatar/Assets.xcassets/woman.imageset/woman@2x.png -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/CDDGroupAvatar/Assets.xcassets/woman.imageset/woman@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RocketsChen/CDDGroupAvatar/HEAD/Demo/CDDGroupAvatar/CDDGroupAvatar/Assets.xcassets/woman.imageset/woman@3x.png -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Target Support Files/SDWebImage/SDWebImage-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_SDWebImage : NSObject 3 | @end 4 | @implementation PodsDummy_SDWebImage 5 | @end 6 | -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/CDDGroupAvatar/Assets.xcassets/noCache1.imageset/noCache1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RocketsChen/CDDGroupAvatar/HEAD/Demo/CDDGroupAvatar/CDDGroupAvatar/Assets.xcassets/noCache1.imageset/noCache1.png -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/CDDGroupAvatar/Assets.xcassets/noCache2.imageset/noCache2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RocketsChen/CDDGroupAvatar/HEAD/Demo/CDDGroupAvatar/CDDGroupAvatar/Assets.xcassets/noCache2.imageset/noCache2.png -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/CDDGroupAvatar/Assets.xcassets/noCache3.imageset/noCache3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RocketsChen/CDDGroupAvatar/HEAD/Demo/CDDGroupAvatar/CDDGroupAvatar/Assets.xcassets/noCache3.imageset/noCache3.png -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/CDDGroupAvatar/Assets.xcassets/noCache4.imageset/noCache4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RocketsChen/CDDGroupAvatar/HEAD/Demo/CDDGroupAvatar/CDDGroupAvatar/Assets.xcassets/noCache4.imageset/noCache4.png -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/CDDGroupAvatar/PFS/KMCGeigerCounter/KMCGeigerCounterTick.aiff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RocketsChen/CDDGroupAvatar/HEAD/Demo/CDDGroupAvatar/CDDGroupAvatar/PFS/KMCGeigerCounter/KMCGeigerCounterTick.aiff -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/CDDGroupAvatar/Assets.xcassets/avatarholder.imageset/avatarholder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RocketsChen/CDDGroupAvatar/HEAD/Demo/CDDGroupAvatar/CDDGroupAvatar/Assets.xcassets/avatarholder.imageset/avatarholder.png -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/CDDGroupAvatar.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Target Support Files/Pods-CDDGroupAvatar/Pods-CDDGroupAvatar-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_CDDGroupAvatar : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_CDDGroupAvatar 5 | @end 6 | -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Target Support Files/SDWebImage/SDWebImage-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/CDDGroupAvatar/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // CDDGroupAvatar 4 | // 5 | // Created by 陈甸甸 on 2019/7/18. 6 | // Copyright © 2019 RocketsChen. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/CDDGroupAvatar.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/CDDGroupAvatar.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/CDDGroupAvatar.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/CDDGroupAvatar/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // CDDGroupAvatar 4 | // 5 | // Created by 陈甸甸 on 2019/7/18. 6 | // Copyright © 2019 RocketsChen. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /CDDGroupAvatar/CacheGroupAvatar/DCImageCacheKey.m: -------------------------------------------------------------------------------- 1 | // 2 | // DCImageCacheKey.m 3 | // CDDGroupAvatar 4 | // 5 | // Created by 陈甸甸 on 2022/6/29. 6 | // Copyright © 2022 RocketsChen. All rights reserved. 7 | // 8 | 9 | #import "DCImageCacheKey.h" 10 | 11 | @implementation DCImageCacheKey 12 | 13 | - (nullable NSString *)cacheKeyForURL:(nonnull NSURL *)url { 14 | return _cacheKey; 15 | } 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - SDWebImage (5.13.0): 3 | - SDWebImage/Core (= 5.13.0) 4 | - SDWebImage/Core (5.13.0) 5 | 6 | DEPENDENCIES: 7 | - SDWebImage 8 | 9 | SPEC REPOS: 10 | trunk: 11 | - SDWebImage 12 | 13 | SPEC CHECKSUMS: 14 | SDWebImage: 0327043dbb9533e75f2eff8445b3df0f2ceca6ac 15 | 16 | PODFILE CHECKSUM: 6883976436d16a44cc07ce954dda8b6bd823c707 17 | 18 | COCOAPODS: 1.11.3 19 | -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Manifest.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - SDWebImage (5.13.0): 3 | - SDWebImage/Core (= 5.13.0) 4 | - SDWebImage/Core (5.13.0) 5 | 6 | DEPENDENCIES: 7 | - SDWebImage 8 | 9 | SPEC REPOS: 10 | trunk: 11 | - SDWebImage 12 | 13 | SPEC CHECKSUMS: 14 | SDWebImage: 0327043dbb9533e75f2eff8445b3df0f2ceca6ac 15 | 16 | PODFILE CHECKSUM: 6883976436d16a44cc07ce954dda8b6bd823c707 17 | 18 | COCOAPODS: 1.11.3 19 | -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/CDDGroupAvatar/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // CDDGroupAvatar 4 | // 5 | // Created by 陈甸甸 on 2019/7/18. 6 | // Copyright © 2019 RocketsChen. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/SDWebImage/SDWebImage/Private/SDInternalMacros.m: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the SDWebImage package. 3 | * (c) Olivier Poitrey 4 | * 5 | * For the full copyright and license information, please view the LICENSE 6 | * file that was distributed with this source code. 7 | */ 8 | 9 | #import "SDInternalMacros.h" 10 | 11 | void sd_executeCleanupBlock (__strong sd_cleanupBlock_t *block) { 12 | (*block)(); 13 | } 14 | -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/CDDGroupAvatar/Assets.xcassets/noCache1.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "noCache1.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/CDDGroupAvatar/Assets.xcassets/noCache2.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "noCache2.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/CDDGroupAvatar/Assets.xcassets/noCache3.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "noCache3.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/CDDGroupAvatar/Assets.xcassets/noCache4.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "noCache4.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/CDDGroupAvatar/Assets.xcassets/place.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "place@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/CDDGroupAvatar/Assets.xcassets/avatarholder.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "avatarholder.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /CDDGroupAvatar/CacheGroupAvatar/DCAvatar.h: -------------------------------------------------------------------------------- 1 | // 2 | // DCAvatar.h 3 | // CDDGroupAvatar 4 | // 5 | // Created by 陈甸甸 on 2019/7/20. 6 | // Copyright © 2019 RocketsChen. All rights reserved. 7 | // 8 | 9 | #import "DCAvatarConfig.h" 10 | 11 | 12 | #import "DCAvatarManager.h" 13 | #import "DCCacheAvatarHelper.h" 14 | 15 | #import "UIImage+DCAvatar.h" 16 | #import "UIView+DCGroup.h" 17 | #import "UIImageView+DCGroup.h" 18 | #import "UIButton+DCGroup.h" 19 | #import "DCImageCacheKey.h" 20 | -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/CDDGroupAvatar/Assets.xcassets/man.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "man@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "man@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/CDDGroupAvatar/Assets.xcassets/woman.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "woman@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "woman@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /CDDGroupAvatar/NoCacheGroupAvatar/DCNoCacheAvatar.h: -------------------------------------------------------------------------------- 1 | // 2 | // DCNoCacheAvatar.h 3 | // CDDGroupAvatar 4 | // 5 | // Created by 陈甸甸 on 2019/7/20. 6 | // Copyright © 2019 RocketsChen. All rights reserved. 7 | // 8 | 9 | 10 | #import "DCAvatarConfig.h" 11 | 12 | #import "DCAvatarHelper.h" 13 | #import "DCNoCahceAvatarManager.h" 14 | 15 | #import "UIImage+DCAvatar.h" 16 | #import "UIView+DCNoCacheGroup.h" 17 | #import "UIImageView+DCNoCacheGroup.h" 18 | #import "UIButton+DCNoCacheGroup.h" 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | .DS_Store 3 | */build/* 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.xccheckout 14 | *.moved-aside 15 | DerivedData 16 | .idea/ 17 | *.hmap 18 | 19 | Carthage 20 | 21 | CocoaPods 22 | Pods 23 | *.xcworkspace 24 | 25 | # Swift Package Manager 26 | .build 27 | Packages 28 | Package.pins 29 | 30 | # R.Swift 31 | *.generated.swift 32 | 33 | ## Obj-C/Swift specific 34 | *.hmap 35 | *.ipa 36 | *.dSYM.zip 37 | *.dSYM 38 | 39 | # node 40 | node_modules/ -------------------------------------------------------------------------------- /CDDGroupAvatar/CacheGroupAvatar/DCImageCacheKey.h: -------------------------------------------------------------------------------- 1 | // 2 | // DCImageCacheKey.h 3 | // CDDGroupAvatar 4 | // 5 | // Created by 陈甸甸 on 2022/6/29. 6 | // Copyright © 2022 RocketsChen. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #if __has_include() 12 | #import 13 | #else 14 | #import "SDWebImage.h" 15 | #endif 16 | 17 | NS_ASSUME_NONNULL_BEGIN 18 | 19 | @interface DCImageCacheKey : NSObject 20 | 21 | @property (nonatomic, strong) NSString *cacheKey; 22 | 23 | @end 24 | 25 | NS_ASSUME_NONNULL_END 26 | -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/SDWebImage/SDWebImage/Private/SDWeakProxy.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the SDWebImage package. 3 | * (c) Olivier Poitrey 4 | * 5 | * For the full copyright and license information, please view the LICENSE 6 | * file that was distributed with this source code. 7 | */ 8 | 9 | #import 10 | #import "SDWebImageCompat.h" 11 | 12 | /// A weak proxy which forward all the message to the target 13 | @interface SDWeakProxy : NSProxy 14 | 15 | @property (nonatomic, weak, readonly, nullable) id target; 16 | 17 | - (nonnull instancetype)initWithTarget:(nonnull id)target; 18 | + (nonnull instancetype)proxyWithTarget:(nonnull id)target; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /CDDGroupAvatar/AvatarConfig/UIImage+DCAvatar.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+DCAvatar.h 3 | // CDDGroupAvatar 4 | // 5 | // Created by 陈甸甸 on 2019/7/19. 6 | // Copyright © 2019 RocketsChen. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface UIImage (DCAvatar) 12 | 13 | /** 14 | 切割图片 15 | */ 16 | - (UIImage *)dc_cutImageViewSize:(CGSize)size clipRect:(CGRect)rect; 17 | 18 | 19 | /** 20 | 获取占位图 21 | */ 22 | - (UIImage *)dc_backItemPlaceholderImage:(id)placeholder groupCount:(NSInteger)groupCount groupIndex:(NSInteger)index; 23 | 24 | 25 | /** 26 | 给图片加外圈圆 27 | */ 28 | - (UIImage *)dc_cgContextAddArcToPointImageBorderWidth:(CGFloat)borderWidth borderColor:(UIColor *)borderColor; 29 | 30 | 31 | @end 32 | 33 | -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/SDWebImage/SDWebImage/Private/SDImageCachesManagerOperation.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the SDWebImage package. 3 | * (c) Olivier Poitrey 4 | * 5 | * For the full copyright and license information, please view the LICENSE 6 | * file that was distributed with this source code. 7 | */ 8 | 9 | #import 10 | #import "SDWebImageCompat.h" 11 | 12 | /// This is used for operation management, but not for operation queue execute 13 | @interface SDImageCachesManagerOperation : NSOperation 14 | 15 | @property (nonatomic, assign, readonly) NSUInteger pendingCount; 16 | 17 | - (void)beginWithTotalCount:(NSUInteger)totalCount; 18 | - (void)completeOne; 19 | - (void)done; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /CDDGroupAvatar/NoCacheGroupAvatar/UIView+DCNoCacheGroup.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+DCNoCacheGroup.h 3 | // CDDGroupAvatar 4 | // 5 | // Created by 陈甸甸 on 2019/12/8. 6 | // Copyright © 2019 RocketsChen. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "DCNoCacheAvatar.h" 11 | 12 | @interface UIView (DCNoCacheGroup) 13 | 14 | /** 15 | 设置群头像 16 | 17 | @param groupId 群头像id 18 | @param groupSource 群头像数据源数组 19 | @param setImageBlock 绘制好的群头像图片 20 | @param completedBlock *itemImageArray, NSString *cacheId> 21 | */ 22 | - (void)dc_setNoCacheAvatarWithGroupId:(NSString *)groupId Source:(NSArray *)groupSource setImageBlock:(GroupSetImageBlock)setImageBlock completed:(GroupImageBlock)completedBlock; 23 | 24 | @end 25 | 26 | -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Target Support Files/Pods-CDDGroupAvatar/Pods-CDDGroupAvatar.debug.xcconfig: -------------------------------------------------------------------------------- 1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/SDWebImage" 4 | LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage" 5 | OTHER_LDFLAGS = $(inherited) -ObjC -l"SDWebImage" -framework "ImageIO" 6 | PODS_BUILD_DIR = ${BUILD_DIR} 7 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 9 | PODS_ROOT = ${SRCROOT}/Pods 10 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 11 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 12 | -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Target Support Files/Pods-CDDGroupAvatar/Pods-CDDGroupAvatar.release.xcconfig: -------------------------------------------------------------------------------- 1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/SDWebImage" 4 | LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage" 5 | OTHER_LDFLAGS = $(inherited) -ObjC -l"SDWebImage" -framework "ImageIO" 6 | PODS_BUILD_DIR = ${BUILD_DIR} 7 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 9 | PODS_ROOT = ${SRCROOT}/Pods 10 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 11 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 12 | -------------------------------------------------------------------------------- /CDDGroupAvatar/NoCacheGroupAvatar/DCNoCahceAvatarManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // DCNoCahceAvatarManager.h 3 | // CDDGroupAvatar 4 | // 5 | // Created by 陈甸甸 on 2019/7/20. 6 | // Copyright © 2019 RocketsChen. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "DCNoCacheAvatar.h" 11 | 12 | 13 | @interface DCNoCahceAvatarManager : NSObject 14 | 15 | 16 | + (DCNoCahceAvatarManager *)sharedAvatar; 17 | 18 | #pragma mark - DCAvatarManager属性 19 | 20 | /* 头像类型枚举(默认微信样式) */ 21 | @property (assign , nonatomic) DCGroupAvatarType groupAvatarType; 22 | 23 | 24 | /* 头像背景(默认微信背景色) */ 25 | @property (nonatomic, strong) UIColor *avatarBgColor; 26 | 27 | 28 | /* 微信和QQ群内小头像间距(默认值:2) */ 29 | @property (nonatomic, assign) CGFloat distanceBetweenAvatar; 30 | 31 | 32 | /* 微博外边圈宽度(默认:10) */ 33 | @property (nonatomic, assign) CGFloat bordWidth; 34 | 35 | 36 | @end 37 | 38 | -------------------------------------------------------------------------------- /CDDGroupAvatar/NoCacheGroupAvatar/UIImageView+DCNoCacheGroup.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIImageView+DCNoCacheGroup.m 3 | // CDDGroupAvatar 4 | // 5 | // Created by 陈甸甸 on 2019/12/8. 6 | // Copyright © 2019 RocketsChen. All rights reserved. 7 | // 8 | 9 | #import "UIImageView+DCNoCacheGroup.h" 10 | 11 | 12 | @implementation UIImageView (DCNoCacheGroup) 13 | 14 | - (void)dc_setNoCacheImageAvatarWithGroupId:(NSString *)groupId Source:(NSArray *)groupSource 15 | { 16 | [self dc_setNoCacheImageAvatarWithGroupId:groupId Source:groupSource completed:nil]; 17 | } 18 | 19 | 20 | - (void)dc_setNoCacheImageAvatarWithGroupId:(NSString *)groupId Source:(NSArray *)groupSource completed:(GroupImageBlock)completedBlock 21 | { 22 | [self dc_setNoCacheAvatarWithGroupId:groupId Source:groupSource setImageBlock:nil completed:completedBlock]; 23 | } 24 | 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/SDWebImage/SDWebImage/Private/SDAsyncBlockOperation.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the SDWebImage package. 3 | * (c) Olivier Poitrey 4 | * 5 | * For the full copyright and license information, please view the LICENSE 6 | * file that was distributed with this source code. 7 | */ 8 | 9 | #import "SDWebImageCompat.h" 10 | 11 | @class SDAsyncBlockOperation; 12 | typedef void (^SDAsyncBlock)(SDAsyncBlockOperation * __nonnull asyncOperation); 13 | 14 | /// A async block operation, success after you call `completer` (not like `NSBlockOperation` which is for sync block, success on return) 15 | @interface SDAsyncBlockOperation : NSOperation 16 | 17 | - (nonnull instancetype)initWithBlock:(nonnull SDAsyncBlock)block; 18 | + (nonnull instancetype)blockOperationWithBlock:(nonnull SDAsyncBlock)block; 19 | - (void)complete; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/CDDGroupAvatar/DCTestViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // DCTestViewController.h 3 | // CDDGroupAvatar 4 | // 5 | // Created by 陈甸甸 on 2019/7/28. 6 | //Copyright © 2019 RocketsChen. All rights reserved. 7 | // 8 | 9 | #import 10 | @interface DCTestViewController : UITableViewController 11 | 12 | @end 13 | 14 | 15 | 16 | @interface DCTestItem : NSObject 17 | 18 | /* groupId */ 19 | @property (strong , nonatomic)NSString *groupId; 20 | 21 | /* groupSource */ 22 | @property (strong , nonatomic)NSArray *groupSource; 23 | 24 | @end 25 | 26 | 27 | @interface DCTestCell : UITableViewCell 28 | 29 | /* groupIamgeView */ 30 | @property (strong , nonatomic)UIImageView *groupIamgeView; 31 | 32 | /* groupId */ 33 | @property (strong , nonatomic)UILabel *groupIdLabel; 34 | 35 | /* cacheId */ 36 | @property (strong , nonatomic)UILabel *cacheIdLabel; 37 | 38 | @end 39 | 40 | -------------------------------------------------------------------------------- /CDDGroupAvatar/NoCacheGroupAvatar/UIImageView+DCNoCacheGroup.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIImageView+DCNoCacheGroup.h 3 | // CDDGroupAvatar 4 | // 5 | // Created by 陈甸甸 on 2019/12/8. 6 | // Copyright © 2019 RocketsChen. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "UIView+DCNoCacheGroup.h" 11 | 12 | @interface UIImageView (DCNoCacheGroup) 13 | 14 | 15 | /** 16 | 设置群头像 17 | 18 | @param groupId 群头像id 19 | @param groupSource 群头像数据源数组 20 | */ 21 | - (void)dc_setNoCacheImageAvatarWithGroupId:(NSString *)groupId Source:(NSArray *)groupSource; 22 | 23 | 24 | /** 25 | 设置群头像 26 | 27 | @param groupId 群头像id 28 | @param groupSource 群头像数据源数组 29 | @param completedBlock *itemImageArray, NSString *cacheId> 30 | */ 31 | - (void)dc_setNoCacheImageAvatarWithGroupId:(NSString *)groupId Source:(NSArray *)groupSource completed:(GroupImageBlock)completedBlock; 32 | 33 | 34 | @end 35 | 36 | -------------------------------------------------------------------------------- /CDDGroupAvatar/CacheGroupAvatar/UIView+DCGroup.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+DCGroup.h 3 | // CDDGroupAvatar 4 | // 5 | // Created by 陈甸甸 on 2019/7/24. 6 | // Copyright © 2019 RocketsChen. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "DCAvatar.h" 11 | 12 | 13 | @interface UIView (DCGroup) 14 | 15 | /** 16 | 设置群头像 17 | 18 | @param groupId 群头像id 19 | @param groupSource 群头像数据源数组 20 | @param cacheKeys 自定义缓存 例:@[@"md51",@"md52"] 用于特殊需求自定义缓存路径-cacheKeys参数 21 | @param placeholder 占位图 例:@[@"p1",@"p2"] 或者 @[image1,image2] 权重大于 placeholderImage属性 22 | @param options 加载图片选项,详情可见DCGroupAvatarCacheType枚举 23 | @param setImageBlock 绘制好的群头像图片 24 | @param completedBlock *itemImageArray, NSString *cacheId> 25 | */ 26 | - (void)dc_setAvatarWithGroupId:(NSString *)groupId Source:(NSArray *)groupSource cacheKeys:(NSArray *)cacheKeys itemPlaceholder:(id)placeholder options:(DCGroupAvatarCacheType)options setImageBlock:(GroupSetImageBlock)setImageBlock completed:(GroupImageBlock)completedBlock; 27 | 28 | @end 29 | 30 | -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/SDWebImage/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009-2020 Olivier Poitrey rs@dailymotion.com 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is furnished 8 | to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | 21 | -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/SDWebImage/SDWebImage/Private/SDImageAssetManager.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the SDWebImage package. 3 | * (c) Olivier Poitrey 4 | * 5 | * For the full copyright and license information, please view the LICENSE 6 | * file that was distributed with this source code. 7 | */ 8 | 9 | #import 10 | #import "SDWebImageCompat.h" 11 | 12 | /// A Image-Asset manager to work like UIKit/AppKit's image cache behavior 13 | /// 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 :) 14 | @interface SDImageAssetManager : NSObject 15 | 16 | @property (nonatomic, strong, nonnull) NSMapTable *imageTable; 17 | 18 | + (nonnull instancetype)sharedAssetManager; 19 | - (nullable NSString *)getPathForName:(nonnull NSString *)name bundle:(nonnull NSBundle *)bundle preferredScale:(nonnull CGFloat *)scale; 20 | - (nullable UIImage *)imageForName:(nonnull NSString *)name; 21 | - (void)storeImage:(nonnull UIImage *)image forName:(nonnull NSString *)name; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /CDDGroupAvatar/CacheGroupAvatar/DCCacheAvatarHelper.h: -------------------------------------------------------------------------------- 1 | // 2 | // DCCacheAvatarHelper.h 3 | // 4 | // 5 | // Created by 陈甸甸 on 2019/12/10. 6 | // 7 | 8 | #import "DCAvatarHelper.h" 9 | #import "DCAvatar.h" 10 | 11 | @interface DCCacheAvatarHelper : DCAvatarHelper 12 | 13 | 14 | 15 | /** 16 | 批量加载群内部小头像 17 | */ 18 | + (void)dc_fetchLoadImageSource:(NSArray *)groupSource cacheKeys:(NSArray *)cacheKeys cacheGroupImage:(UIImage *)groupImage itemPlaceholder:(id)placeholder completedBlock:(FetchImageBlock)completedBlock; 19 | 20 | 21 | 22 | /** 23 | 获取群头像内部小头像缓存数组 24 | */ 25 | + (NSArray *)dc_fetchItemCacheArraySource:(NSArray *)groupSource; 26 | 27 | 28 | 29 | /** 30 | 批量加载群内部小头像(同步-M) 31 | 32 | @param groupSource 群头像数据源数组 33 | @param placeholder 占位图 例:@[@"p1",@"p2"] 或者 @[image1,image2] 权重大于 placeholderImage属性 34 | */ 35 | + (NSArray *)dc_synfetchLoadImageSource:(NSArray *)groupSource itemPlaceholder:(id)placeholder; 36 | 37 | 38 | 39 | /** 40 | 批量加载群内部小头像(异步-M) 41 | 42 | @param groupSource 群头像数据源数组 43 | @param placeholder 占位图 例:@[@"p1",@"p2"] 或者 @[image1,image2] 权重大于 placeholderImage属性 44 | */ 45 | + (void)dc_asynfetchLoadImageSource:(NSArray *)groupSource itemPlaceholder:(id)placeholder completedBlock:(AsynFetchImageBlock)completedBlock; 46 | 47 | 48 | 49 | 50 | @end 51 | 52 | -------------------------------------------------------------------------------- /CDDGroupAvatar.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'CDDGroupAvatar' 3 | s.version = '1.5.6' 4 | s.summary = 'iOS 群头像 / Easy to use' 5 | 6 | s.description = <<-DESC 7 | iOS 群头像功能,像加载一张图片那么简单。 8 | DESC 9 | 10 | s.homepage = 'https://github.com/RocketsChen/CDDGroupAvatar' 11 | s.license = 'MIT' #开源协议 12 | s.authors = {'RcoketsChen' => '1062749739@qq.com'} 13 | s.platform = :ios, '9.0' 14 | s.source = {:git => 'https://github.com/RocketsChen/CDDGroupAvatar.git', :tag => '1.5.6'} 15 | s.requires_arc = true 16 | s.frameworks = 'UIKit' 17 | s.default_subspec = 'Cache' 18 | 19 | s.subspec 'NoCache' do |ss| 20 | 21 | ss.source_files = 'CDDGroupAvatar' , 'CDDGroupAvatar/AvatarConfig/*' , 'CDDGroupAvatar/NoCacheGroupAvatar/*' 22 | 23 | end 24 | 25 | 26 | s.subspec 'Cache' do |ss| 27 | 28 | ss.source_files = 'CDDGroupAvatar' , 'CDDGroupAvatar/AvatarConfig/*' , 'CDDGroupAvatar/CacheGroupAvatar/*' 29 | s.dependency 'SDWebImage' 30 | 31 | end 32 | 33 | 34 | s.subspec 'Core' do |ss| 35 | 36 | ss.source_files = 'CDDGroupAvatar' , 'CDDGroupAvatar/AvatarConfig/*' , 'CDDGroupAvatar/NoCacheGroupAvatar/*' , 'CDDGroupAvatar/CacheGroupAvatar/*' 37 | s.dependency 'SDWebImage' 38 | 39 | end 40 | 41 | end 42 | -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/CDDGroupAvatar/PFS/KMCGeigerCounter/KMCGeigerCounter.h: -------------------------------------------------------------------------------- 1 | // 2 | // KMCGeigerCounter.h 3 | // KMCGeigerCounter 4 | // 5 | // Created by Kevin Conner on 10/21/14. 6 | // Copyright (c) 2014 Kevin Conner. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | typedef NS_ENUM(NSUInteger, KMCGeigerCounterPosition) { 12 | KMCGeigerCounterPositionLeft, 13 | KMCGeigerCounterPositionMiddle, 14 | KMCGeigerCounterPositionRight 15 | }; 16 | 17 | @interface KMCGeigerCounter : NSObject 18 | 19 | // Set [KMCGeigerCounter sharedGeigerCounter].enabled = YES from -application:didFinishLaunchingWithOptions:. 20 | @property (nonatomic, assign, getter = isEnabled) BOOL enabled; 21 | 22 | // The meter draws over the status bar. Set the window level manually if your own custom windows obscure it. 23 | @property (nonatomic, assign) UIWindowLevel windowLevel; 24 | 25 | // Position of the meter in the status bar. Takes effect on next enable. 26 | @property (nonatomic, assign) KMCGeigerCounterPosition position; 27 | 28 | @property (nonatomic, readonly, getter = isRunning) BOOL running; 29 | @property (nonatomic, readonly) NSInteger droppedFrameCountInLastSecond; 30 | @property (nonatomic, readonly) NSInteger drawnFrameCountInLastSecond; // -1 until one second of frames have been collected 31 | 32 | + (instancetype)sharedGeigerCounter; 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /CDDGroupAvatar/NoCacheGroupAvatar/DCNoCahceAvatarManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // DCNoCahceAvatarManager.m 3 | // CDDGroupAvatar 4 | // 5 | // Created by 陈甸甸 on 2019/7/20. 6 | // Copyright © 2019 RocketsChen. All rights reserved. 7 | // 8 | 9 | #import "DCNoCahceAvatarManager.h" 10 | 11 | @implementation DCNoCahceAvatarManager 12 | 13 | + (DCNoCahceAvatarManager *)sharedAvatar { 14 | static dispatch_once_t once; 15 | static id sharedInstance; 16 | dispatch_once(&once, ^{ 17 | sharedInstance = [self new]; 18 | }); 19 | return sharedInstance; 20 | } 21 | 22 | - (instancetype)init { 23 | self = [super init]; 24 | if (self) { 25 | 26 | [self initBaseValue]; 27 | } 28 | return self; 29 | } 30 | 31 | 32 | - (void)initBaseValue { 33 | 34 | _bordWidth = DCWeiBoAvatarbordWidth; 35 | _distanceBetweenAvatar = DCDistanceBetweenAvatar; 36 | _avatarBgColor = [UIColor colorWithRed:238 / 255.0f green:238 / 255.0f blue:238 / 255.0f alpha:1.0f]; 37 | } 38 | 39 | 40 | - (void)setAvatarBgColor:(UIColor *)avatarBgColor 41 | { 42 | _avatarBgColor = avatarBgColor; 43 | } 44 | 45 | 46 | - (void)setDistanceBetweenAvatar:(CGFloat)distanceBetweenAvatar 47 | { 48 | _distanceBetweenAvatar = distanceBetweenAvatar; 49 | } 50 | 51 | - (void)setBordWidth:(CGFloat)bordWidth 52 | { 53 | _bordWidth = bordWidth; 54 | } 55 | 56 | @end 57 | -------------------------------------------------------------------------------- /CDDGroupAvatar/CacheGroupAvatar/DCAvatarManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // DCAvatarManager.h 3 | // CDDGroupAvatar 4 | // 5 | // Created by 陈甸甸 on 2019/7/20. 6 | // Copyright © 2019 RocketsChen. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "DCAvatar.h" 11 | 12 | #if __has_include() 13 | #import 14 | #else 15 | #import "SDWebImage.h" 16 | #endif 17 | 18 | @interface DCAvatarManager : NSObject 19 | 20 | 21 | + (DCAvatarManager *)sharedAvatar; 22 | 23 | #pragma mark - DCAvatarManager属性 24 | 25 | /* 请求的baseURL。这应该只包含URL的共体部分,例如http://www.example.com。 */ 26 | @property (strong , nonatomic)NSString *baseUrl; 27 | 28 | /* 头像类型枚举(默认微信样式) */ 29 | @property (assign , nonatomic) DCGroupAvatarType groupAvatarType; 30 | 31 | 32 | /* 头像背景(默认微信背景色) */ 33 | @property (nonatomic, strong) UIColor *avatarBgColor; 34 | 35 | 36 | /* 一次性设置小头像加载失败的占位图 : 权重低于类方法中的placeholder属性 placeholderImage < (id)placeholder */ 37 | @property (nonatomic, strong) UIImage *placeholderImage; 38 | 39 | 40 | /* 微信和QQ群内小头像间距(默认值:2) */ 41 | @property (nonatomic, assign) CGFloat distanceBetweenAvatar; 42 | 43 | 44 | /* 微博外边圈宽度(默认:10) */ 45 | @property (nonatomic, assign) CGFloat bordWidth; 46 | 47 | 48 | #pragma mark - SDWebImage依赖框架属性 49 | 50 | /* sd加载群内单个小图片属性 (默认:SDWebImageRetryFailed | SDWebImageLowPriority ) */ 51 | @property (assign , nonatomic) SDWebImageOptions sdImageOptions; 52 | 53 | @end 54 | 55 | -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Target Support Files/Pods-CDDGroupAvatar/Pods-CDDGroupAvatar-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | 4 | ## SDWebImage 5 | 6 | Copyright (c) 2009-2020 Olivier Poitrey rs@dailymotion.com 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is furnished 13 | to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in all 16 | copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | THE SOFTWARE. 25 | 26 | 27 | Generated by CocoaPods - https://cocoapods.org 28 | -------------------------------------------------------------------------------- /CDDGroupAvatar/NoCacheGroupAvatar/UIButton+DCNoCacheGroup.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIButton+DCNoCacheGroup.h 3 | // CDDGroupAvatar 4 | // 5 | // Created by 陈甸甸 on 2019/12/8. 6 | // Copyright © 2019 RocketsChen. All rights reserved. 7 | // 8 | 9 | 10 | #import 11 | #import "UIView+DCNoCacheGroup.h" 12 | 13 | @interface UIButton (DCNoCacheGroup) 14 | 15 | /** 16 | 设置群头像 17 | 18 | @param groupId 群头像id 19 | @param groupSource 群头像数据源数组 20 | @param state UIControlState 21 | */ 22 | - (void)dc_setNoCacheImageAvatarWithGroupId:(NSString *)groupId Source:(NSArray *)groupSource forState:(UIControlState)state; 23 | 24 | 25 | /** 26 | 设置群头像 27 | 28 | @param groupId 群头像id 29 | @param groupSource 群头像数据源数组 30 | @param state UIControlState 31 | @param completedBlock *itemImageArray, NSString *cacheId> 32 | */ 33 | - (void)dc_setNoCacheImageAvatarWithGroupId:(NSString *)groupId Source:(NSArray *)groupSource forState:(UIControlState)state completed:(GroupImageBlock)completedBlock; 34 | 35 | 36 | 37 | /** 38 | 设置群头像(按钮背景) 39 | */ 40 | - (void)dc_setNoCacheBackgroundImageAvatarWithGroupId:(NSString *)groupId Source:(NSArray *)groupSource forState:(UIControlState)state; 41 | 42 | 43 | - (void)dc_setNoCacheBackgroundImageAvatarWithGroupId:(NSString *)groupId Source:(NSArray *)groupSource forState:(UIControlState)state completed:(GroupImageBlock)completedBlock; 44 | 45 | 46 | @end 47 | 48 | -------------------------------------------------------------------------------- /CDDGroupAvatar/CacheGroupAvatar/DCAvatarManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // DCAvatarManager.m 3 | // CDDGroupAvatar 4 | // 5 | // Created by 陈甸甸 on 2019/7/20. 6 | // Copyright © 2019 RocketsChen. All rights reserved. 7 | // 8 | 9 | #import "DCAvatarManager.h" 10 | 11 | @implementation DCAvatarManager 12 | 13 | + (DCAvatarManager *)sharedAvatar { 14 | static dispatch_once_t once; 15 | static id sharedInstance; 16 | dispatch_once(&once, ^{ 17 | sharedInstance = [self new]; 18 | }); 19 | return sharedInstance; 20 | } 21 | 22 | 23 | - (instancetype)init { 24 | self = [super init]; 25 | if (self) { 26 | 27 | [self initBaseValue]; 28 | } 29 | return self; 30 | } 31 | 32 | 33 | - (void)initBaseValue { 34 | 35 | _baseUrl = @""; 36 | _placeholderImage = [UIImage new]; 37 | _bordWidth = DCWeiBoAvatarbordWidth; 38 | _distanceBetweenAvatar = DCDistanceBetweenAvatar; 39 | _sdImageOptions = SDWebImageRetryFailed | SDWebImageLowPriority; 40 | _avatarBgColor = [UIColor colorWithRed:238 / 255.0f green:238 / 255.0f blue:238 / 255.0f alpha:1.0f]; 41 | } 42 | 43 | 44 | - (void)setAvatarBgColor:(UIColor *)avatarBgColor 45 | { 46 | _avatarBgColor = avatarBgColor; 47 | } 48 | 49 | - (void)setPlaceholderImage:(UIImage *)placeholderImage 50 | { 51 | _placeholderImage = placeholderImage; 52 | } 53 | 54 | - (void)setDistanceBetweenAvatar:(CGFloat)distanceBetweenAvatar 55 | { 56 | _distanceBetweenAvatar = distanceBetweenAvatar; 57 | } 58 | 59 | - (void)setBordWidth:(CGFloat)bordWidth 60 | { 61 | _bordWidth = bordWidth; 62 | } 63 | 64 | 65 | @end 66 | -------------------------------------------------------------------------------- /CDDGroupAvatar/AvatarConfig/DCAvatarHelper.h: -------------------------------------------------------------------------------- 1 | // 2 | // DCAvatarHelper.h 3 | // DCAvatarHelper 4 | // 5 | // Created by 陈甸甸 on 2019/7/18. 6 | // Copyright © 2019 RocketsChen. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "DCAvatarConfig.h" 11 | 12 | 13 | @interface DCAvatarHelper : NSObject 14 | 15 | /** 16 | 计算Type_QQ头像尺寸 17 | */ 18 | + (CGSize)dc_calculateSizeQQAvatarGroupCount:(NSInteger)groupCount index:(NSInteger)index containerSize:(CGSize)containerSize distanceBetweenAvatar:(CGFloat)distance; 19 | 20 | /** 21 | 计算Type_WeChat头像尺寸 22 | */ 23 | + (CGSize)dc_calculateSizeWeChatAvatarGroupCount:(NSInteger)groupCount containerSize:(CGSize)containerSize distanceBetweenAvatar:(CGFloat)distance; 24 | 25 | /** 26 | 计算Type_WeiBo圆半径 27 | */ 28 | + (CGFloat)dc_calculateRadiusWeiBoAvatarGroupCount:(NSInteger)groupCount containerSize:(CGSize)containerSize distanceBetweenAvatar:(CGFloat)distance; 29 | 30 | 31 | /** 32 | 计算Type_WeiBo小头像位置 33 | */ 34 | + (CGPoint)dc_calculateWeiBoAvatarGroupCount:(NSInteger)groupCount index:(NSInteger)index containerSize:(CGSize)containerSize distanceBetweenAvatar:(CGFloat)distance; 35 | 36 | /** 37 | 计算Type_WeChat/QQ小头像位置 38 | */ 39 | + (CGPoint)dc_calculatePointAvatarGroupCount:(NSInteger)groupCount index:(NSInteger)index containerSize:(CGSize)containerSize distanceBetweenAvatar:(CGFloat)distance avatarType:(DCGroupAvatarType)groupAvatarType; 40 | 41 | 42 | 43 | /** 44 | 获取群头像最大数组数量 45 | */ 46 | + (NSArray *)dc_getTypefMaxCount:(NSArray *)groupSource avatarType:(DCGroupAvatarType)groupAvatarType; 47 | 48 | 49 | /** 50 | 判断图片属性 51 | */ 52 | + (BOOL)dc_getCGImageRefContainsAlpha:(CGImageRef)imageRef; 53 | 54 | /** 55 | MD5加密 56 | */ 57 | + (NSString *)dc_cacheMd5:(NSString *)key; 58 | 59 | 60 | /** 61 | 颜色十六进制转换 62 | */ 63 | + (NSString *)dc_hexColor:(UIColor *)color; 64 | 65 | 66 | @end 67 | 68 | -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/CDDGroupAvatar/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | 群头像框架 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(MARKETING_VERSION) 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | NSAppTransportSecurity 26 | 27 | NSAllowsArbitraryLoads 28 | 29 | 30 | UILaunchStoryboardName 31 | LaunchScreen 32 | UIMainStoryboardFile 33 | Main 34 | UIRequiredDeviceCapabilities 35 | 36 | armv7 37 | 38 | UISupportedInterfaceOrientations 39 | 40 | UIInterfaceOrientationPortrait 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | UISupportedInterfaceOrientations~ipad 45 | 46 | UIInterfaceOrientationPortrait 47 | UIInterfaceOrientationPortraitUpsideDown 48 | UIInterfaceOrientationLandscapeLeft 49 | UIInterfaceOrientationLandscapeRight 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /CDDGroupAvatar/NoCacheGroupAvatar/UIButton+DCNoCacheGroup.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIButton+DCNoCacheGroup.m 3 | // CDDGroupAvatar 4 | // 5 | // Created by 陈甸甸 on 2019/12/8. 6 | // Copyright © 2019 RocketsChen. All rights reserved. 7 | // 8 | 9 | #import "UIButton+DCNoCacheGroup.h" 10 | 11 | #import "UIView+DCNoCacheGroup.h" 12 | 13 | @implementation UIButton (DCNoCacheGroup) 14 | 15 | - (void)dc_setNoCacheImageAvatarWithGroupId:(NSString *)groupId Source:(NSArray *)groupSource forState:(UIControlState)state 16 | { 17 | [self dc_setNoCacheImageAvatarWithGroupId:groupId Source:groupSource forState:state completed:nil]; 18 | } 19 | 20 | 21 | - (void)dc_setNoCacheImageAvatarWithGroupId:(NSString *)groupId Source:(NSArray *)groupSource forState:(UIControlState)state completed:(GroupImageBlock)completedBlock 22 | { 23 | @ga_weakify(self); 24 | [self dc_setNoCacheAvatarWithGroupId:groupId Source:groupSource setImageBlock:^(UIImage *setImage) { 25 | @ga_strongify(self); 26 | [self setImage:setImage forState:state]; 27 | } completed:completedBlock]; 28 | } 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | - (void)dc_setNoCacheBackgroundImageAvatarWithGroupId:(NSString *)groupId Source:(NSArray *)groupSource forState:(UIControlState)state 37 | { 38 | 39 | [self dc_setNoCacheBackgroundImageAvatarWithGroupId:groupId Source:groupSource forState:state completed:nil]; 40 | } 41 | 42 | 43 | - (void)dc_setNoCacheBackgroundImageAvatarWithGroupId:(NSString *)groupId Source:(NSArray *)groupSource forState:(UIControlState)state completed:(GroupImageBlock)completedBlock 44 | { 45 | @ga_weakify(self); 46 | [self dc_setNoCacheAvatarWithGroupId:groupId Source:groupSource setImageBlock:^(UIImage *setImage) { 47 | @ga_strongify(self); 48 | [self setBackgroundImage:setImage forState:state]; 49 | } completed:completedBlock]; 50 | } 51 | 52 | 53 | @end 54 | -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/CDDGroupAvatar/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /CDDGroupAvatar/CacheGroupAvatar/UIImageView+DCGroup.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIImageView+DCGroup.m 3 | // CDDGroupAvatar 4 | // 5 | // Created by 陈甸甸 on 2019/7/20. 6 | // Copyright © 2019 RocketsChen. All rights reserved. 7 | // 8 | 9 | #import "UIImageView+DCGroup.h" 10 | 11 | 12 | @implementation UIImageView (DCGroup) 13 | 14 | 15 | - (void)dc_setImageAvatarWithGroupId:(NSString *)groupId Source:(NSArray *)groupSource 16 | { 17 | [self dc_setImageAvatarWithGroupId:groupId Source:groupSource itemPlaceholder:nil options:0 completed:nil]; 18 | } 19 | 20 | 21 | - (void)dc_setImageAvatarWithGroupId:(NSString *)groupId Source:(NSArray *)groupSource completed:(GroupImageBlock)completedBlock 22 | { 23 | [self dc_setImageAvatarWithGroupId:groupId Source:groupSource itemPlaceholder:nil options:0 completed:completedBlock]; 24 | } 25 | 26 | 27 | - (void)dc_setImageAvatarWithGroupId:(NSString *)groupId Source:(NSArray *)groupSource itemPlaceholder:(id)placeholder 28 | { 29 | [self dc_setImageAvatarWithGroupId:groupId Source:groupSource itemPlaceholder:placeholder options:0 completed:nil]; 30 | } 31 | 32 | 33 | - (void)dc_setImageAvatarWithGroupId:(NSString *)groupId Source:(NSArray *)groupSource itemPlaceholder:(id)placeholder options:(DCGroupAvatarCacheType)options completed:(GroupImageBlock)completedBlock 34 | { 35 | [self dc_setAvatarWithGroupId:groupId Source:groupSource cacheKeys:nil itemPlaceholder:placeholder options:options setImageBlock:nil completed:completedBlock]; 36 | } 37 | 38 | - (void)dc_setImageAvatarWithGroupId:(NSString *)groupId Source:(NSArray *)groupSource cacheKeys:(NSArray *)cacheKeys itemPlaceholder:(id)placeholder options:(DCGroupAvatarCacheType)options completed:(GroupImageBlock)completedBlock 39 | { 40 | [self dc_setAvatarWithGroupId:groupId Source:groupSource cacheKeys:cacheKeys itemPlaceholder:placeholder options:options setImageBlock:nil completed:completedBlock]; 41 | } 42 | 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/SDWebImage/SDWebImage/Private/SDWeakProxy.m: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the SDWebImage package. 3 | * (c) Olivier Poitrey 4 | * 5 | * For the full copyright and license information, please view the LICENSE 6 | * file that was distributed with this source code. 7 | */ 8 | 9 | #import "SDWeakProxy.h" 10 | 11 | @implementation SDWeakProxy 12 | 13 | - (instancetype)initWithTarget:(id)target { 14 | _target = target; 15 | return self; 16 | } 17 | 18 | + (instancetype)proxyWithTarget:(id)target { 19 | return [[SDWeakProxy alloc] initWithTarget:target]; 20 | } 21 | 22 | - (id)forwardingTargetForSelector:(SEL)selector { 23 | return _target; 24 | } 25 | 26 | - (void)forwardInvocation:(NSInvocation *)invocation { 27 | void *null = NULL; 28 | [invocation setReturnValue:&null]; 29 | } 30 | 31 | - (NSMethodSignature *)methodSignatureForSelector:(SEL)selector { 32 | return [NSObject instanceMethodSignatureForSelector:@selector(init)]; 33 | } 34 | 35 | - (BOOL)respondsToSelector:(SEL)aSelector { 36 | return [_target respondsToSelector:aSelector]; 37 | } 38 | 39 | - (BOOL)isEqual:(id)object { 40 | return [_target isEqual:object]; 41 | } 42 | 43 | - (NSUInteger)hash { 44 | return [_target hash]; 45 | } 46 | 47 | - (Class)superclass { 48 | return [_target superclass]; 49 | } 50 | 51 | - (Class)class { 52 | return [_target class]; 53 | } 54 | 55 | - (BOOL)isKindOfClass:(Class)aClass { 56 | return [_target isKindOfClass:aClass]; 57 | } 58 | 59 | - (BOOL)isMemberOfClass:(Class)aClass { 60 | return [_target isMemberOfClass:aClass]; 61 | } 62 | 63 | - (BOOL)conformsToProtocol:(Protocol *)aProtocol { 64 | return [_target conformsToProtocol:aProtocol]; 65 | } 66 | 67 | - (BOOL)isProxy { 68 | return YES; 69 | } 70 | 71 | - (NSString *)description { 72 | return [_target description]; 73 | } 74 | 75 | - (NSString *)debugDescription { 76 | return [_target debugDescription]; 77 | } 78 | 79 | @end 80 | -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/CDDGroupAvatar/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/SDWebImage/SDWebImage/Private/SDImageCachesManagerOperation.m: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the SDWebImage package. 3 | * (c) Olivier Poitrey 4 | * 5 | * For the full copyright and license information, please view the LICENSE 6 | * file that was distributed with this source code. 7 | */ 8 | 9 | #import "SDImageCachesManagerOperation.h" 10 | #import "SDInternalMacros.h" 11 | 12 | @implementation SDImageCachesManagerOperation { 13 | SD_LOCK_DECLARE(_pendingCountLock); 14 | } 15 | 16 | @synthesize executing = _executing; 17 | @synthesize finished = _finished; 18 | @synthesize cancelled = _cancelled; 19 | @synthesize pendingCount = _pendingCount; 20 | 21 | - (instancetype)init { 22 | if (self = [super init]) { 23 | SD_LOCK_INIT(_pendingCountLock); 24 | _pendingCount = 0; 25 | } 26 | return self; 27 | } 28 | 29 | - (void)beginWithTotalCount:(NSUInteger)totalCount { 30 | self.executing = YES; 31 | self.finished = NO; 32 | _pendingCount = totalCount; 33 | } 34 | 35 | - (NSUInteger)pendingCount { 36 | SD_LOCK(_pendingCountLock); 37 | NSUInteger pendingCount = _pendingCount; 38 | SD_UNLOCK(_pendingCountLock); 39 | return pendingCount; 40 | } 41 | 42 | - (void)completeOne { 43 | SD_LOCK(_pendingCountLock); 44 | _pendingCount = _pendingCount > 0 ? _pendingCount - 1 : 0; 45 | SD_UNLOCK(_pendingCountLock); 46 | } 47 | 48 | - (void)cancel { 49 | self.cancelled = YES; 50 | [self reset]; 51 | } 52 | 53 | - (void)done { 54 | self.finished = YES; 55 | self.executing = NO; 56 | [self reset]; 57 | } 58 | 59 | - (void)reset { 60 | SD_LOCK(_pendingCountLock); 61 | _pendingCount = 0; 62 | SD_UNLOCK(_pendingCountLock); 63 | } 64 | 65 | - (void)setFinished:(BOOL)finished { 66 | [self willChangeValueForKey:@"isFinished"]; 67 | _finished = finished; 68 | [self didChangeValueForKey:@"isFinished"]; 69 | } 70 | 71 | - (void)setExecuting:(BOOL)executing { 72 | [self willChangeValueForKey:@"isExecuting"]; 73 | _executing = executing; 74 | [self didChangeValueForKey:@"isExecuting"]; 75 | } 76 | 77 | - (void)setCancelled:(BOOL)cancelled { 78 | [self willChangeValueForKey:@"isCancelled"]; 79 | _cancelled = cancelled; 80 | [self didChangeValueForKey:@"isCancelled"]; 81 | } 82 | 83 | @end 84 | -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/Target Support Files/Pods-CDDGroupAvatar/Pods-CDDGroupAvatar-acknowledgements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreferenceSpecifiers 6 | 7 | 8 | FooterText 9 | This application makes use of the following third party libraries: 10 | Title 11 | Acknowledgements 12 | Type 13 | PSGroupSpecifier 14 | 15 | 16 | FooterText 17 | Copyright (c) 2009-2020 Olivier Poitrey rs@dailymotion.com 18 | 19 | Permission is hereby granted, free of charge, to any person obtaining a copy 20 | of this software and associated documentation files (the "Software"), to deal 21 | in the Software without restriction, including without limitation the rights 22 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 23 | copies of the Software, and to permit persons to whom the Software is furnished 24 | to do so, subject to the following conditions: 25 | 26 | The above copyright notice and this permission notice shall be included in all 27 | copies or substantial portions of the Software. 28 | 29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 35 | THE SOFTWARE. 36 | 37 | 38 | License 39 | MIT 40 | Title 41 | SDWebImage 42 | Type 43 | PSGroupSpecifier 44 | 45 | 46 | FooterText 47 | Generated by CocoaPods - https://cocoapods.org 48 | Title 49 | 50 | Type 51 | PSGroupSpecifier 52 | 53 | 54 | StringsTable 55 | Acknowledgements 56 | Title 57 | Acknowledgements 58 | 59 | 60 | -------------------------------------------------------------------------------- /CDDGroupAvatar/CacheGroupAvatar/UIImageView+DCGroup.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIImageView+DCGroup.h 3 | // CDDGroupAvatar 4 | // 5 | // Created by 陈甸甸 on 2019/7/20. 6 | // Copyright © 2019 RocketsChen. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "UIView+DCGroup.h" 11 | 12 | @interface UIImageView (DCGroup) 13 | 14 | /** 15 | 设置群头像 16 | 17 | @param groupId 群头像id 18 | @param groupSource 群头像数据源数组 19 | */ 20 | - (void)dc_setImageAvatarWithGroupId:(NSString *)groupId Source:(NSArray *)groupSource; 21 | 22 | 23 | /** 24 | 设置群头像 25 | 26 | @param groupId 群头像id 27 | @param groupSource 群头像数据源数组 28 | @param completedBlock *itemImageArray, NSString *cacheId> 29 | */ 30 | - (void)dc_setImageAvatarWithGroupId:(NSString *)groupId Source:(NSArray *)groupSource completed:(GroupImageBlock)completedBlock; 31 | 32 | 33 | /** 34 | 设置群头像 35 | 36 | @param groupId 群头像id 37 | @param groupSource 群头像数据源数组 38 | @param placeholder 占位图 例:@[@"p1",@"p2"] 或者 @[image1,image2] 权重大于 placeholderImage属性 39 | */ 40 | - (void)dc_setImageAvatarWithGroupId:(NSString *)groupId Source:(NSArray *)groupSource itemPlaceholder:(id)placeholder; 41 | 42 | 43 | /** 44 | 设置群头像 45 | 46 | @param groupId 群头像id 47 | @param groupSource 群头像数据源数组 48 | @param placeholder 占位图 例:@[@"p1",@"p2"] 或者 @[image1,image2] 权重大于 placeholderImage属性 49 | @param options 加载图片选项,详情可见DCGroupAvatarCacheType枚举 50 | @param completedBlock *itemImageArray, NSString *cacheId> 51 | */ 52 | - (void)dc_setImageAvatarWithGroupId:(NSString *)groupId Source:(NSArray *)groupSource itemPlaceholder:(id)placeholder options:(DCGroupAvatarCacheType)options completed:(GroupImageBlock)completedBlock; 53 | 54 | 55 | /** 56 | 设置群头像 57 | 58 | @param groupId 群头像id 59 | @param groupSource 群头像数据源数组 60 | @param placeholder 占位图 例:@[@"p1",@"p2"] 或者 @[image1,image2] 权重大于 placeholderImage属性 61 | @param cacheKeys 自定义缓存 例:@[@"md51",@"md52"] 用于特殊需求自定义缓存路径-cacheKeys参数 62 | @param options 加载图片选项,详情可见DCGroupAvatarCacheType枚举 63 | @param completedBlock *itemImageArray, NSString *cacheId> 64 | */ 65 | - (void)dc_setImageAvatarWithGroupId:(NSString *)groupId Source:(NSArray *)groupSource cacheKeys:(NSArray *)cacheKeys itemPlaceholder:(id)placeholder options:(DCGroupAvatarCacheType)options completed:(GroupImageBlock)completedBlock; 66 | 67 | @end 68 | 69 | -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/CDDGroupAvatar/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // CDDGroupAvatar 4 | // 5 | // Created by 陈甸甸 on 2019/7/18. 6 | // Copyright © 2019 RocketsChen. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | #if defined(DEBUG)||defined(_DEBUG) 11 | #import "KMCGeigerCounter.h" 12 | #endif 13 | 14 | @interface AppDelegate () 15 | 16 | @end 17 | 18 | @implementation AppDelegate 19 | 20 | 21 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 22 | 23 | #if defined(DEBUG)||defined(_DEBUG) //仅仅在模拟器上跑测试会显示FPS 24 | [KMCGeigerCounter sharedGeigerCounter].position = KMCGeigerCounterPositionMiddle; 25 | [KMCGeigerCounter sharedGeigerCounter].enabled = YES; 26 | #endif 27 | 28 | 29 | return YES; 30 | } 31 | 32 | 33 | - (void)applicationWillResignActive:(UIApplication *)application { 34 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 35 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 36 | } 37 | 38 | 39 | - (void)applicationDidEnterBackground:(UIApplication *)application { 40 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 41 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 42 | } 43 | 44 | 45 | - (void)applicationWillEnterForeground:(UIApplication *)application { 46 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 47 | } 48 | 49 | 50 | - (void)applicationDidBecomeActive:(UIApplication *)application { 51 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 52 | } 53 | 54 | 55 | - (void)applicationWillTerminate:(UIApplication *)application { 56 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 57 | } 58 | 59 | 60 | @end 61 | -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/SDWebImage/SDWebImage/Private/SDAsyncBlockOperation.m: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the SDWebImage package. 3 | * (c) Olivier Poitrey 4 | * 5 | * For the full copyright and license information, please view the LICENSE 6 | * file that was distributed with this source code. 7 | */ 8 | 9 | #import "SDAsyncBlockOperation.h" 10 | 11 | @interface SDAsyncBlockOperation () 12 | 13 | @property (assign, nonatomic, getter = isExecuting) BOOL executing; 14 | @property (assign, nonatomic, getter = isFinished) BOOL finished; 15 | @property (nonatomic, copy, nonnull) SDAsyncBlock executionBlock; 16 | 17 | @end 18 | 19 | @implementation SDAsyncBlockOperation 20 | 21 | @synthesize executing = _executing; 22 | @synthesize finished = _finished; 23 | 24 | - (nonnull instancetype)initWithBlock:(nonnull SDAsyncBlock)block { 25 | self = [super init]; 26 | if (self) { 27 | self.executionBlock = block; 28 | } 29 | return self; 30 | } 31 | 32 | + (nonnull instancetype)blockOperationWithBlock:(nonnull SDAsyncBlock)block { 33 | SDAsyncBlockOperation *operation = [[SDAsyncBlockOperation alloc] initWithBlock:block]; 34 | return operation; 35 | } 36 | 37 | - (void)start { 38 | @synchronized (self) { 39 | if (self.isCancelled) { 40 | self.finished = YES; 41 | return; 42 | } 43 | 44 | self.finished = NO; 45 | self.executing = YES; 46 | 47 | if (self.executionBlock) { 48 | self.executionBlock(self); 49 | } else { 50 | self.executing = NO; 51 | self.finished = YES; 52 | } 53 | } 54 | } 55 | 56 | - (void)cancel { 57 | @synchronized (self) { 58 | [super cancel]; 59 | if (self.isExecuting) { 60 | self.executing = NO; 61 | self.finished = YES; 62 | } 63 | } 64 | } 65 | 66 | 67 | - (void)complete { 68 | @synchronized (self) { 69 | if (self.isExecuting) { 70 | self.finished = YES; 71 | self.executing = NO; 72 | } 73 | } 74 | } 75 | 76 | - (void)setFinished:(BOOL)finished { 77 | [self willChangeValueForKey:@"isFinished"]; 78 | _finished = finished; 79 | [self didChangeValueForKey:@"isFinished"]; 80 | } 81 | 82 | - (void)setExecuting:(BOOL)executing { 83 | [self willChangeValueForKey:@"isExecuting"]; 84 | _executing = executing; 85 | [self didChangeValueForKey:@"isExecuting"]; 86 | } 87 | 88 | - (BOOL)isConcurrent { 89 | return YES; 90 | } 91 | 92 | @end 93 | -------------------------------------------------------------------------------- /CDDGroupAvatar/AvatarConfig/UIImage+DCAvatar.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+DCAvatar.m 3 | // CDDGroupAvatar 4 | // 5 | // Created by 陈甸甸 on 2019/7/19. 6 | // Copyright © 2019 RocketsChen. All rights reserved. 7 | // 8 | 9 | #import "UIImage+DCAvatar.h" 10 | 11 | @implementation UIImage (DCAvatar) 12 | 13 | 14 | - (UIImage *)dc_cutImageViewSize:(CGSize)size clipRect:(CGRect)rect { 15 | 16 | UIImage *clipImage = self; 17 | 18 | CGFloat scale_width = self.size.width / size.width; 19 | CGFloat scale_height = self.size.height / size.height; 20 | CGRect clipRect = CGRectMake(rect.origin.x * scale_width,rect.origin.y * scale_height,rect.size.width * scale_width,rect.size.height * scale_height); 21 | UIGraphicsBeginImageContext(clipRect.size); 22 | [self drawAtPoint:CGPointMake(- clipRect.origin.x, - clipRect.origin.y)]; 23 | clipImage = UIGraphicsGetImageFromCurrentImageContext(); 24 | 25 | UIGraphicsEndImageContext(); 26 | 27 | return clipImage; 28 | } 29 | 30 | 31 | - (UIImage *)dc_backItemPlaceholderImage:(id)placeholder groupCount:(NSInteger)groupCount groupIndex:(NSInteger)index; 32 | { 33 | UIImage *itemPlaceholder = self; 34 | 35 | if ([placeholder isKindOfClass:[NSString class]]) { 36 | 37 | itemPlaceholder = [UIImage imageNamed:placeholder]; 38 | 39 | }else if ([placeholder isKindOfClass:[NSArray class]]) { 40 | 41 | NSArray *placeholderArray = (NSArray *)placeholder; 42 | 43 | if (placeholderArray.count >= groupCount) { 44 | 45 | id item = placeholder[index]; 46 | 47 | if ([item isKindOfClass:[NSString class]]) { 48 | itemPlaceholder = [UIImage imageNamed:(NSString *)item]; 49 | }else if ([item isKindOfClass:[UIImage class]]){ 50 | itemPlaceholder = (UIImage *)item; 51 | } 52 | } 53 | }else if ([placeholder isKindOfClass:[UIImage class]]) { 54 | 55 | itemPlaceholder = (UIImage *)placeholder; 56 | } 57 | return itemPlaceholder; 58 | } 59 | 60 | 61 | - (UIImage *)dc_cgContextAddArcToPointImageBorderWidth:(CGFloat)borderWidth borderColor:(UIColor *)borderColor 62 | { 63 | UIImage *avatarImage = self; 64 | 65 | CGSize size = CGSizeMake(avatarImage.size.width + 2 * borderWidth, avatarImage.size.height + 2 * borderWidth); 66 | UIGraphicsBeginImageContextWithOptions(size, NO, 0); 67 | UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, size.width, size.height)]; 68 | [borderColor set]; 69 | [path fill]; 70 | path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(borderWidth, borderWidth, avatarImage.size.width, avatarImage.size.height)]; 71 | [path addClip]; 72 | [avatarImage drawInRect:CGRectMake(borderWidth, borderWidth, avatarImage.size.width, avatarImage.size.height)]; 73 | avatarImage = UIGraphicsGetImageFromCurrentImageContext(); 74 | 75 | UIGraphicsEndImageContext(); 76 | 77 | return avatarImage; 78 | } 79 | 80 | 81 | 82 | 83 | 84 | @end 85 | -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/CDDGroupAvatar.xcodeproj/xcshareddata/xcschemes/CDDGroupAvatar.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CDDGroupAvatar 2 | 3 | 4 | [![CocoaPods](https://img.shields.io/cocoapods/v/CDDGroupAvatar.svg)](https://cocoapods.org/pods/CDDGroupAvatar) [![CocoaPods](https://img.shields.io/cocoapods/p/CDDGroupAvatar.svg)](https://github.com/indulgeIn/CDDGroupAvatar)  5 | 6 | #### 这框架的初衷是想使群头像的实现尽可能的能像`SDWebImage`加载一张图片那么简单 7 | 8 | #### Swift版本: 9 | 10 | [Swift版本传送门](https://github.com/RocketsChen/CDDGroupAvatarSwift) 11 | 12 | #### 博客地址: 13 | 14 | [iOS 群头像框架 — CDDGroupAvatar](https://www.jianshu.com/p/f1acb0c0fb97) 15 | 16 | ![GIF](https://github.com/RocketsChen/CDDGroupAvatar/blob/master/CDDGroupAvatar.gif) 17 | 18 | #### 安装: 19 | 20 | * CocoaPods 21 | 22 | 1:在 Podfile 中添加 pod '`CDDGroupAvatar`',执行 pod install 或 pod update。 23 | 24 | * 如果只需要无缓存版本:pod '`CDDGroupAvatar/NoCache`,更多详情可以查看podspec文件 25 | 26 | * 手动导入 27 | 28 | 1:将demo项目中的 `CDDGroupAvatar` 文件夹所有内容拖入你的工程中。 29 | 2:集成 SDWebImage 框架。 30 | 31 | * 用法 32 | 33 | 1:导入`#import `可以拥有全部功能。 34 | 2:调用对应控件的类方法。 35 | 3:如果有使用上的疑问,可以下载演示demo进行查看。 36 | 37 | #### 代码: 38 | 39 | ``` 40 | #import 41 | ... 42 | 43 | // UIImageView 44 | [self.avImageViewW8 dc_setImageAvatarWithGroupId:@"avImageViewW8" Source:_groupNum8]; 45 | 46 | // UIButton 47 | // Image 48 | [self.avaButton dc_setImageAvatarWithGroupId:@"avaButton" Source:_groupNum9 forState:0]; 49 | // Background 50 | [self.avaBgButton dc_setBackgroundImageAvatarWithGroupId:@"avaBgButton" Source:_groupNum4 forState:0]; 51 | ``` 52 | 53 | ## 版本更新 54 | 55 | | version | note | 56 | | :----: | :----: | 57 | | 1.1.0 | Start ~ 🤔| 58 | | 1.2.0 | Add Methods;Fix Bug。| 59 | | 1.3.0 | 支持ImageView和Button,初步完成框架。[博客](https://www.jianshu.com/p/f1acb0c0fb97)| 60 | | 1.4.0 | Add:同步获取所有小头像方法;| 61 | | 1.5.2 | Add:新增无缓存版本,type - NoCache,去除SDWebImage依赖。[博客](https://www.jianshu.com/p/e89dbb49c0ba)| 62 | | 1.5.3 | Remove:SDWebImage默认版本。| 63 | | 1.5.4 | Add:QQ_Type:Image切圈。| 64 | | 1.5.6 | Add:自定义缓存cache | 65 | 66 | 67 | #### 1.4.0: 68 | 69 | ``` 70 | /** 71 | 批量加载群内部小头像(同步-M) 72 | 73 | @param groupSource 群头像数据源数组 74 | @param placeholder 占位图 例:@[@"p1",@"p2"] 或者 @[image1,image2] 权重大于 placeholderImage属性 75 | */ 76 | + (NSArray *)dc_synfetchLoadImageSource:(NSArray *)groupSource itemPlaceholder:(id)placeholder; 77 | 78 | /** 79 | 批量加载群内部小头像(异步-M) 80 | 81 | @param groupSource 群头像数据源数组 82 | @param placeholder 占位图 例:@[@"p1",@"p2"] 或者 @[image1,image2] 权重大于 placeholderImage属性 83 | */ 84 | + (void)dc_asynfetchLoadImageSource:(NSArray *)groupSource itemPlaceholder:(id)placeholder completedBlock:(AsynFetchImageBlock)completedBlock; 85 | ``` 86 | 87 | 88 | #### 1.5.2: 89 | 90 | ##### 提供NoCache版本,脱离SDWebImage依赖,用户可自行决定加载方式和缓存 91 | 92 | ``` 93 | [self.ncImageViewW4 dc_setNoCacheImageAvatarWithGroupId:@"avImageViewW4" Source:@[[UIImage imageNamed:@"noCache1"],[UIImage imageNamed:@"noCache2"],[UIImage imageNamed:@"noCache3"],[UIImage imageNamed:@"noCache4"]]]; 94 | ``` 95 | 96 | 97 | 98 | #### 关于版本: 99 | 100 | 目前`iOS`和`Swift`版本均已开源,后续会继续优化完善~ 101 | 102 | 欢迎 Star✨ 103 | 104 | 105 | 106 | 107 | 108 | #### Agreement 109 | 110 | * ` CDDGroupAvatar` licensed under the MIT license is used. Refer to [LICENSE](https://opensource.org/licenses/MIT) for more information. 111 | 112 | -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/SDWebImage/WebImage/SDWebImage.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the SDWebImage package. 3 | * (c) Olivier Poitrey 4 | * (c) Florent Vilmart 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | #import 11 | 12 | //! Project version number for SDWebImage. 13 | FOUNDATION_EXPORT double SDWebImageVersionNumber; 14 | 15 | //! Project version string for SDWebImage. 16 | FOUNDATION_EXPORT const unsigned char SDWebImageVersionString[]; 17 | 18 | // In this header, you should import all the public headers of your framework using statements like #import 19 | 20 | #import 21 | #import 22 | #import 23 | #import 24 | #import 25 | #import 26 | #import 27 | #import 28 | #import 29 | #import 30 | #import 31 | #import 32 | #import 33 | #import 34 | #import 35 | #import 36 | #import 37 | #import 38 | #import 39 | #import 40 | #import 41 | #import 42 | #import 43 | #import 44 | #import 45 | #import 46 | #import 47 | #import 48 | #import 49 | #import 50 | #import 51 | #import 52 | #import 53 | #import 54 | #import 55 | #import 56 | #import 57 | #import 58 | #import 59 | #import 60 | #import 61 | #import 62 | #import 63 | #import 64 | #import 65 | #import 66 | #import 67 | #import 68 | #import 69 | #import 70 | #import 71 | #import 72 | #import 73 | #import 74 | 75 | // Mac 76 | #if __has_include() 77 | #import 78 | #endif 79 | #if __has_include() 80 | #import 81 | #endif 82 | #if __has_include() 83 | #import 84 | #endif 85 | 86 | // MapKit 87 | #if __has_include() 88 | #import 89 | #endif 90 | -------------------------------------------------------------------------------- /CDDGroupAvatar/CacheGroupAvatar/UIButton+DCGroup.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIButton+DCGroup.h 3 | // CDDGroupAvatar 4 | // 5 | // Created by 陈甸甸 on 2019/7/24. 6 | // Copyright © 2019 RocketsChen. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "UIView+DCGroup.h" 11 | 12 | @interface UIButton (DCGroup) 13 | 14 | 15 | /** 16 | 设置群头像 17 | 18 | @param groupId 群头像id 19 | @param groupSource 群头像数据源数组 20 | @param state UIControlState 21 | */ 22 | - (void)dc_setImageAvatarWithGroupId:(NSString *)groupId Source:(NSArray *)groupSource forState:(UIControlState)state; 23 | 24 | 25 | /** 26 | 设置群头像 27 | 28 | @param groupId 群头像id 29 | @param groupSource 群头像数据源数组 30 | @param state UIControlState 31 | @param completedBlock *itemImageArray, NSString *cacheId> 32 | */ 33 | - (void)dc_setImageAvatarWithGroupId:(NSString *)groupId Source:(NSArray *)groupSource forState:(UIControlState)state completed:(GroupImageBlock)completedBlock; 34 | 35 | 36 | /** 37 | 设置群头像 38 | 39 | @param groupId 群头像id 40 | @param groupSource 群头像数据源数组 41 | @param state UIControlState 42 | @param placeholder 占位图 例:@[@"p1",@"p2"] 或者 @[image1,image2] 权重大于 placeholderImage属性 43 | */ 44 | - (void)dc_setImageAvatarWithGroupId:(NSString *)groupId Source:(NSArray *)groupSource forState:(UIControlState)state itemPlaceholder:(id)placeholder; 45 | 46 | 47 | /** 48 | 设置群头像 49 | 50 | @param groupId 群头像id 51 | @param groupSource 群头像数据源数组 52 | @param state UIControlState 53 | @param placeholder 占位图 例:@[@"p1",@"p2"] 或者 @[image1,image2] 权重大于 placeholderImage属性 54 | @param options 加载图片选项,详情可见DCGroupAvatarCacheType枚举 55 | @param completedBlock *itemImageArray, NSString *cacheId> 56 | */ 57 | - (void)dc_setImageAvatarWithGroupId:(NSString *)groupId Source:(NSArray *)groupSource forState:(UIControlState)state itemPlaceholder:(id)placeholder options:(DCGroupAvatarCacheType)options completed:(GroupImageBlock)completedBlock; 58 | 59 | /** 60 | 设置群头像 61 | 62 | @param groupId 群头像id 63 | @param groupSource 群头像数据源数组 64 | @param cacheKeys 自定义缓存 例:@[@"md51",@"md52"] 用于特殊需求自定义缓存路径-cacheKeys参数 65 | @param state UIControlState 66 | @param placeholder 占位图 例:@[@"p1",@"p2"] 或者 @[image1,image2] 权重大于 placeholderImage属性 67 | @param options 加载图片选项,详情可见DCGroupAvatarCacheType枚举 68 | @param completedBlock *itemImageArray, NSString *cacheId> 69 | */ 70 | - (void)dc_setImageAvatarWithGroupId:(NSString *)groupId Source:(NSArray *)groupSource cacheKeys:(NSArray *)cacheKeys forState:(UIControlState)state itemPlaceholder:(id)placeholder options:(DCGroupAvatarCacheType)options completed:(GroupImageBlock)completedBlock; 71 | 72 | 73 | /** 74 | 设置群头像(按钮背景) 75 | */ 76 | - (void)dc_setBackgroundImageAvatarWithGroupId:(NSString *)groupId Source:(NSArray *)groupSource forState:(UIControlState)state; 77 | 78 | 79 | - (void)dc_setBackgroundImageAvatarWithGroupId:(NSString *)groupId Source:(NSArray *)groupSource forState:(UIControlState)state completed:(GroupImageBlock)completedBlock; 80 | 81 | 82 | - (void)dc_setBackgroundImageAvatarWithGroupId:(NSString *)groupId Source:(NSArray *)groupSource forState:(UIControlState)state itemPlaceholder:(id)placeholder; 83 | 84 | 85 | - (void)dc_setBackgroundImageAvatarWithGroupId:(NSString *)groupId Source:(NSArray *)groupSource forState:(UIControlState)state itemPlaceholder:(id)placeholder options:(DCGroupAvatarCacheType)options completed:(GroupImageBlock)completedBlock; 86 | 87 | - (void)dc_setBackgroundImageAvatarWithGroupId:(NSString *)groupId Source:(NSArray *)groupSource cacheKeys:(NSArray *)cacheKeys forState:(UIControlState)state itemPlaceholder:(id)placeholder options:(DCGroupAvatarCacheType)options completed:(GroupImageBlock)completedBlock; 88 | 89 | @end 90 | 91 | -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/SDWebImage/SDWebImage/Private/SDInternalMacros.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the SDWebImage package. 3 | * (c) Olivier Poitrey 4 | * 5 | * For the full copyright and license information, please view the LICENSE 6 | * file that was distributed with this source code. 7 | */ 8 | 9 | #import 10 | #import 11 | #import 12 | #import "SDmetamacros.h" 13 | 14 | #define SD_USE_OS_UNFAIR_LOCK TARGET_OS_MACCATALYST ||\ 15 | (__IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_10_0) ||\ 16 | (__MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_12) ||\ 17 | (__TV_OS_VERSION_MIN_REQUIRED >= __TVOS_10_0) ||\ 18 | (__WATCH_OS_VERSION_MIN_REQUIRED >= __WATCHOS_3_0) 19 | 20 | #ifndef SD_LOCK_DECLARE 21 | #if SD_USE_OS_UNFAIR_LOCK 22 | #define SD_LOCK_DECLARE(lock) os_unfair_lock lock 23 | #else 24 | #define SD_LOCK_DECLARE(lock) os_unfair_lock lock API_AVAILABLE(ios(10.0), tvos(10), watchos(3), macos(10.12)); \ 25 | OSSpinLock lock##_deprecated; 26 | #endif 27 | #endif 28 | 29 | #ifndef SD_LOCK_DECLARE_STATIC 30 | #if SD_USE_OS_UNFAIR_LOCK 31 | #define SD_LOCK_DECLARE_STATIC(lock) static os_unfair_lock lock 32 | #else 33 | #define SD_LOCK_DECLARE_STATIC(lock) static os_unfair_lock lock API_AVAILABLE(ios(10.0), tvos(10), watchos(3), macos(10.12)); \ 34 | static OSSpinLock lock##_deprecated; 35 | #endif 36 | #endif 37 | 38 | #ifndef SD_LOCK_INIT 39 | #if SD_USE_OS_UNFAIR_LOCK 40 | #define SD_LOCK_INIT(lock) lock = OS_UNFAIR_LOCK_INIT 41 | #else 42 | #define SD_LOCK_INIT(lock) if (@available(iOS 10, tvOS 10, watchOS 3, macOS 10.12, *)) lock = OS_UNFAIR_LOCK_INIT; \ 43 | else lock##_deprecated = OS_SPINLOCK_INIT; 44 | #endif 45 | #endif 46 | 47 | #ifndef SD_LOCK 48 | #if SD_USE_OS_UNFAIR_LOCK 49 | #define SD_LOCK(lock) os_unfair_lock_lock(&lock) 50 | #else 51 | #define SD_LOCK(lock) if (@available(iOS 10, tvOS 10, watchOS 3, macOS 10.12, *)) os_unfair_lock_lock(&lock); \ 52 | else OSSpinLockLock(&lock##_deprecated); 53 | #endif 54 | #endif 55 | 56 | #ifndef SD_UNLOCK 57 | #if SD_USE_OS_UNFAIR_LOCK 58 | #define SD_UNLOCK(lock) os_unfair_lock_unlock(&lock) 59 | #else 60 | #define SD_UNLOCK(lock) if (@available(iOS 10, tvOS 10, watchOS 3, macOS 10.12, *)) os_unfair_lock_unlock(&lock); \ 61 | else OSSpinLockUnlock(&lock##_deprecated); 62 | #endif 63 | #endif 64 | 65 | #ifndef SD_OPTIONS_CONTAINS 66 | #define SD_OPTIONS_CONTAINS(options, value) (((options) & (value)) == (value)) 67 | #endif 68 | 69 | #ifndef SD_CSTRING 70 | #define SD_CSTRING(str) #str 71 | #endif 72 | 73 | #ifndef SD_NSSTRING 74 | #define SD_NSSTRING(str) @(SD_CSTRING(str)) 75 | #endif 76 | 77 | #ifndef SD_SEL_SPI 78 | #define SD_SEL_SPI(name) NSSelectorFromString([NSString stringWithFormat:@"_%@", SD_NSSTRING(name)]) 79 | #endif 80 | 81 | #ifndef weakify 82 | #define weakify(...) \ 83 | sd_keywordify \ 84 | metamacro_foreach_cxt(sd_weakify_,, __weak, __VA_ARGS__) 85 | #endif 86 | 87 | #ifndef strongify 88 | #define strongify(...) \ 89 | sd_keywordify \ 90 | _Pragma("clang diagnostic push") \ 91 | _Pragma("clang diagnostic ignored \"-Wshadow\"") \ 92 | metamacro_foreach(sd_strongify_,, __VA_ARGS__) \ 93 | _Pragma("clang diagnostic pop") 94 | #endif 95 | 96 | #define sd_weakify_(INDEX, CONTEXT, VAR) \ 97 | CONTEXT __typeof__(VAR) metamacro_concat(VAR, _weak_) = (VAR); 98 | 99 | #define sd_strongify_(INDEX, VAR) \ 100 | __strong __typeof__(VAR) VAR = metamacro_concat(VAR, _weak_); 101 | 102 | #if DEBUG 103 | #define sd_keywordify autoreleasepool {} 104 | #else 105 | #define sd_keywordify try {} @catch (...) {} 106 | #endif 107 | 108 | #ifndef onExit 109 | #define onExit \ 110 | sd_keywordify \ 111 | __strong sd_cleanupBlock_t metamacro_concat(sd_exitBlock_, __LINE__) __attribute__((cleanup(sd_executeCleanupBlock), unused)) = ^ 112 | #endif 113 | 114 | typedef void (^sd_cleanupBlock_t)(void); 115 | 116 | #if defined(__cplusplus) 117 | extern "C" { 118 | #endif 119 | void sd_executeCleanupBlock (__strong sd_cleanupBlock_t *block); 120 | #if defined(__cplusplus) 121 | } 122 | #endif 123 | -------------------------------------------------------------------------------- /CDDGroupAvatar/CacheGroupAvatar/UIButton+DCGroup.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIButton+DCGroup.m 3 | // CDDGroupAvatar 4 | // 5 | // Created by 陈甸甸 on 2019/7/24. 6 | // Copyright © 2019 RocketsChen. All rights reserved. 7 | // 8 | 9 | #import "UIButton+DCGroup.h" 10 | 11 | @implementation UIButton (DCGroup) 12 | 13 | 14 | - (void)dc_setImageAvatarWithGroupId:(NSString *)groupId Source:(NSArray *)groupSource forState:(UIControlState)state 15 | { 16 | [self dc_setImageAvatarWithGroupId:groupId Source:groupSource forState:state itemPlaceholder:nil options:0 completed:nil]; 17 | } 18 | 19 | 20 | - (void)dc_setImageAvatarWithGroupId:(NSString *)groupId Source:(NSArray *)groupSource forState:(UIControlState)state completed:(GroupImageBlock)completedBlock 21 | { 22 | [self dc_setImageAvatarWithGroupId:groupId Source:groupSource forState:state itemPlaceholder:nil options:0 completed:completedBlock]; 23 | } 24 | 25 | 26 | - (void)dc_setImageAvatarWithGroupId:(NSString *)groupId Source:(NSArray *)groupSource forState:(UIControlState)state itemPlaceholder:(id)placeholder 27 | { 28 | [self dc_setImageAvatarWithGroupId:groupId Source:groupSource forState:state itemPlaceholder:placeholder options:0 completed:nil]; 29 | } 30 | 31 | 32 | - (void)dc_setImageAvatarWithGroupId:(NSString *)groupId Source:(NSArray *)groupSource forState:(UIControlState)state itemPlaceholder:(id)placeholder options:(DCGroupAvatarCacheType)options completed:(GroupImageBlock)completedBlock 33 | { 34 | [self dc_setImageAvatarWithGroupId:groupId Source:groupSource cacheKeys:nil forState:state itemPlaceholder:placeholder options:options completed:completedBlock]; 35 | } 36 | 37 | 38 | - (void)dc_setImageAvatarWithGroupId:(NSString *)groupId Source:(NSArray *)groupSource cacheKeys:(NSArray *)cacheKeys forState:(UIControlState)state itemPlaceholder:(id)placeholder options:(DCGroupAvatarCacheType)options completed:(GroupImageBlock)completedBlock 39 | { 40 | @ga_weakify(self); 41 | [self dc_setAvatarWithGroupId:groupId Source:groupSource cacheKeys:cacheKeys itemPlaceholder:placeholder options:options setImageBlock:^(UIImage *setImage) { 42 | @ga_strongify(self); 43 | [self setImage:setImage forState:state]; 44 | } completed:completedBlock]; 45 | } 46 | 47 | 48 | 49 | - (void)dc_setBackgroundImageAvatarWithGroupId:(NSString *)groupId Source:(NSArray *)groupSource forState:(UIControlState)state 50 | { 51 | 52 | [self dc_setBackgroundImageAvatarWithGroupId:groupId Source:groupSource forState:state itemPlaceholder:nil options:0 completed:nil]; 53 | } 54 | 55 | 56 | - (void)dc_setBackgroundImageAvatarWithGroupId:(NSString *)groupId Source:(NSArray *)groupSource forState:(UIControlState)state completed:(GroupImageBlock)completedBlock 57 | { 58 | 59 | [self dc_setBackgroundImageAvatarWithGroupId:groupId Source:groupSource forState:state itemPlaceholder:nil options:0 completed:completedBlock]; 60 | } 61 | 62 | 63 | - (void)dc_setBackgroundImageAvatarWithGroupId:(NSString *)groupId Source:(NSArray *)groupSource forState:(UIControlState)state itemPlaceholder:(id)placeholder 64 | { 65 | [self dc_setBackgroundImageAvatarWithGroupId:groupId Source:groupSource forState:state itemPlaceholder:placeholder options:0 completed:nil]; 66 | } 67 | 68 | 69 | - (void)dc_setBackgroundImageAvatarWithGroupId:(NSString *)groupId Source:(NSArray *)groupSource forState:(UIControlState)state itemPlaceholder:(id)placeholder options:(DCGroupAvatarCacheType)options completed:(GroupImageBlock)completedBlock 70 | { 71 | [self dc_setBackgroundImageAvatarWithGroupId:groupId Source:groupSource cacheKeys:nil forState:state itemPlaceholder:placeholder options:options completed:completedBlock]; 72 | } 73 | 74 | - (void)dc_setBackgroundImageAvatarWithGroupId:(NSString *)groupId Source:(NSArray *)groupSource cacheKeys:(NSArray *)cacheKeys forState:(UIControlState)state itemPlaceholder:(id)placeholder options:(DCGroupAvatarCacheType)options completed:(GroupImageBlock)completedBlock 75 | { 76 | @ga_weakify(self); 77 | [self dc_setAvatarWithGroupId:groupId Source:groupSource cacheKeys:cacheKeys itemPlaceholder:placeholder options:options setImageBlock:^(UIImage *setImage) { 78 | @ga_strongify(self); 79 | [self setBackgroundImage:setImage forState:state]; 80 | } completed:completedBlock]; 81 | } 82 | 83 | 84 | @end 85 | -------------------------------------------------------------------------------- /CDDGroupAvatar/CacheGroupAvatar/DCCacheAvatarHelper.m: -------------------------------------------------------------------------------- 1 | // 2 | // DCCacheAvatarHelper.m 3 | // 4 | // 5 | // Created by 陈甸甸 on 2019/12/10. 6 | // 7 | 8 | #import "DCCacheAvatarHelper.h" 9 | 10 | 11 | #if __has_include() 12 | #import 13 | #else 14 | #import "SDWebImage.h" 15 | #endif 16 | 17 | @implementation DCCacheAvatarHelper 18 | 19 | 20 | 21 | + (NSArray *)dc_fetchItemCacheArraySource:(NSArray *)groupSource 22 | { 23 | UIImage *itemIamge; 24 | NSMutableArray *cacheArray = [NSMutableArray array]; 25 | for (NSString *strImg in groupSource) { 26 | itemIamge = [[SDImageCache sharedImageCache] imageFromCacheForKey:DCURLStr(strImg)]; 27 | if (!itemIamge) { 28 | itemIamge = (![DCAvatarManager sharedAvatar].placeholderImage) ? [UIImage new] : [DCAvatarManager sharedAvatar].placeholderImage; 29 | } 30 | [cacheArray addObject:itemIamge]; 31 | } 32 | return cacheArray; 33 | } 34 | 35 | 36 | + (void)dc_fetchLoadImageSource:(NSArray *)groupSource cacheKeys:(NSArray *)cacheKeys cacheGroupImage:(UIImage *)groupImage itemPlaceholder:(id)placeholder completedBlock:(FetchImageBlock)completedBlock{ 37 | 38 | NSMutableArray *groupImages = [NSMutableArray arrayWithArray:groupSource]; 39 | 40 | __block int32_t groupSum = 0 , placeholderSum = 0; 41 | __block SDWebImageOptions sdImageOptions = [DCAvatarManager sharedAvatar].sdImageOptions; 42 | __block BOOL succeed = NO; 43 | 44 | FetchImageParamsBlock callCompletedBlock = ^{ // block 45 | if (completedBlock) { 46 | completedBlock(groupImages, succeed); 47 | } 48 | }; 49 | 50 | [groupSource enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { 51 | @autoreleasepool { 52 | UIImage *placeholderImage = [[DCAvatarManager sharedAvatar].placeholderImage dc_backItemPlaceholderImage:placeholder groupCount:groupSource.count groupIndex:idx]; 53 | 54 | if (!groupImage) { 55 | placeholderSum++; 56 | [groupImages replaceObjectAtIndex:idx withObject:placeholderImage]; 57 | if (placeholderSum == groupSource.count) { 58 | dispatch_main_async_safe(callCompletedBlock) 59 | } 60 | } 61 | __block NSString *strImg = (NSString *)obj; 62 | 63 | NSString *cacheKey = cacheKeys[idx]; 64 | SDWebImageContext *imageContext = nil; 65 | if (cacheKey.length > 0) { 66 | DCImageCacheKey *cache = [DCImageCacheKey new]; 67 | cache.cacheKey = cacheKey; 68 | imageContext = [SDWebImageContext dictionaryWithObject:cache forKey:SDWebImageContextCacheKeyFilter]; 69 | } 70 | [[SDWebImageManager sharedManager] loadImageWithURL:[NSURL URLWithString:DCURLStr(strImg)] options:sdImageOptions context:imageContext progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { 71 | @autoreleasepool { 72 | groupSum++; 73 | if (error) { 74 | image = placeholderImage; 75 | }else{ 76 | succeed = YES; 77 | } 78 | [groupImages replaceObjectAtIndex:idx withObject:image]; 79 | if (groupSum == groupSource.count) { 80 | dispatch_main_async_safe(callCompletedBlock) 81 | } 82 | } 83 | }]; 84 | } 85 | }]; 86 | } 87 | 88 | 89 | 90 | + (NSArray *)dc_synfetchLoadImageSource:(NSArray *)groupSource itemPlaceholder:(id)placeholder 91 | { 92 | __block NSMutableArray *allItemImages; 93 | dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); 94 | [self dc_fetchLoadImageSource:groupSource cacheKeys:nil cacheGroupImage:nil itemPlaceholder:placeholder completedBlock:^(NSArray *unitImages, BOOL succeed) { 95 | allItemImages = [NSMutableArray arrayWithArray:unitImages]; 96 | dispatch_semaphore_signal(semaphore); 97 | }]; 98 | 99 | dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); 100 | return allItemImages; 101 | } 102 | 103 | 104 | + (void)dc_asynfetchLoadImageSource:(NSArray *)groupSource itemPlaceholder:(id)placeholder completedBlock:(AsynFetchImageBlock)completedBlock 105 | { 106 | [self dc_fetchLoadImageSource:groupSource cacheKeys:nil cacheGroupImage:nil itemPlaceholder:placeholder completedBlock:^(NSArray *unitImages, BOOL succeed) { 107 | dispatch_async(dispatch_get_main_queue(), ^{ 108 | completedBlock(unitImages); 109 | }); 110 | }]; 111 | } 112 | 113 | 114 | 115 | @end 116 | -------------------------------------------------------------------------------- /CDDGroupAvatar/AvatarConfig/DCAvatarConfig.h: -------------------------------------------------------------------------------- 1 | // 2 | // DCAvatarConfig.h 3 | // CDDGroupAvatar 4 | // 5 | // Created by 陈甸甸 on 2019/7/20. 6 | // Copyright © 2019 RocketsChen. All rights reserved. 7 | // 8 | 9 | #ifndef DCAvatarConfig_h 10 | #define DCAvatarConfig_h 11 | 12 | // Block 13 | 14 | typedef void(^GroupImageBlock)(NSString *groupId, UIImage *groupImage, NSArray *itemImageArray, NSString *cacheId); 15 | 16 | typedef void(^GroupSetImageBlock)(UIImage *setImage); 17 | 18 | typedef void(^GroupImageParamsBlock)(void); 19 | 20 | 21 | typedef void(^FetchImageBlock)(NSArray *unitImages, BOOL succeed); 22 | 23 | typedef void(^AsynFetchImageBlock)(NSArray *unitImages); 24 | 25 | typedef void(^FetchImageParamsBlock)(void); 26 | 27 | // static 28 | 29 | static int32_t DCMaxWeChatCount = 9; 30 | static int32_t DCMaxQQCount = 4; 31 | static int32_t DCMaxWeiBoCount = 4; 32 | 33 | static int32_t DCMaxWeChatColumn = 3; 34 | 35 | static CGFloat DCDistanceBetweenAvatar = 2; 36 | static CGFloat DCWeiBoAvatarbordWidth = 10; 37 | 38 | 39 | 40 | // ENUM 41 | 42 | 43 | /** 44 | 头像类型枚举 45 | 46 | - DCGroupAvatarWeChatType: 微信 47 | - DCGroupAvatarNewQQType: QQ(以中心点分割的半圆拼接) 48 | - DCGroupAvatarOldQQType: WeiBo(圆拼接) 49 | */ 50 | typedef NS_ENUM(NSUInteger, DCGroupAvatarType) { 51 | DCGroupAvatarWeChatType = 0, 52 | DCGroupAvatarQQType = 1, 53 | DCGroupAvatarWeiBoType = 2, 54 | }; 55 | 56 | 57 | 58 | /** 59 | 加载图片枚举 * cache 60 | 61 | - SDCGroupAvatarDefaultCached: 默认:走缓存 取到返回 没有则获取最新 62 | - SDCGroupAvatarRefreshCached: 先读缓存再获取最新 63 | */ 64 | typedef NS_ENUM(NSUInteger, DCGroupAvatarCacheType) { 65 | 66 | DCGroupAvatarCachedDefault = 0, 67 | 68 | DCGroupAvatarCachedRefresh = 1, 69 | }; 70 | 71 | 72 | 73 | /** 74 | 组内头像的数量 75 | 76 | - DCNumberOfGroupAvatarOne: 1 77 | - DCNumberOfGroupAvatarTwo: 2 78 | - DCNumberOfGroupAvatarThree: 3 79 | - DCNumberOfGroupAvatarFour: 4 (QQ最大值) / (微博最大值) 80 | - DCNumberOfGroupAvatarFive: 5 81 | - DCNumberOfGroupAvatarSix: 6 82 | - DCNumberOfGroupAvatarSeven: 7 83 | - DCNumberOfGroupAvatarEight: 8 84 | - DCNumberOfGroupAvatarNine: 9 (微信最大值) 85 | */ 86 | typedef NS_ENUM(NSUInteger, DCNumberOfGroupAvatarType) { 87 | 88 | DCNumberOfGroupAvatarOne = 1, 89 | DCNumberOfGroupAvatarTwo = 2, 90 | DCNumberOfGroupAvatarThree = 3, 91 | DCNumberOfGroupAvatarFour = 4, 92 | DCNumberOfGroupAvatarFive = 5, 93 | DCNumberOfGroupAvatarSix = 6, 94 | DCNumberOfGroupAvatarSeven = 7, 95 | DCNumberOfGroupAvatarEight = 8, 96 | DCNumberOfGroupAvatarNine = 9, 97 | }; 98 | 99 | 100 | // define 101 | 102 | // * cache 103 | #define DCURLStr(avaStr) ([avaStr containsString:@"www."]) ? avaStr : [NSString stringWithFormat:@"%@%@",[DCAvatarManager sharedAvatar].baseUrl,avaStr] 104 | 105 | 106 | #define DCCacheIdMD5(groupId,groupSource) [DCAvatarHelper dc_cacheMd5:[NSString stringWithFormat:@"id%@_num%zd_lastObj%@_distance%.f_bordWidth%.f_bgColor%@",groupId,groupSource.count,groupSource.lastObject,[DCAvatarManager sharedAvatar].distanceBetweenAvatar,[DCAvatarManager sharedAvatar].bordWidth,[DCAvatarHelper dc_hexColor:[DCAvatarManager sharedAvatar].avatarBgColor]]] 107 | 108 | 109 | #define DCNoCacheIdMD5(groupId,groupSource) [DCAvatarHelper dc_cacheMd5:[NSString stringWithFormat:@"id%@_num%zd_lastObj%@_distance%.f_bordWidth%.f_bgColor%@",groupId,groupSource.count,groupSource.lastObject,[DCNoCahceAvatarManager sharedAvatar].distanceBetweenAvatar,[DCNoCahceAvatarManager sharedAvatar].bordWidth,[DCAvatarHelper dc_hexColor:[DCNoCahceAvatarManager sharedAvatar].avatarBgColor]]] 110 | 111 | 112 | 113 | #ifndef dispatch_main_async_safe 114 | #define dispatch_main_async_safe(block)\ 115 | if (dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL) == dispatch_queue_get_label(dispatch_get_main_queue())) {\ 116 | block();\ 117 | } else {\ 118 | dispatch_async(dispatch_get_main_queue(), block);\ 119 | } 120 | #endif 121 | 122 | #ifndef ga_weakify 123 | #if DEBUG 124 | #if __has_feature(objc_arc) 125 | #define ga_weakify(object) autoreleasepool{} __weak __typeof__(object) weak##_##object = object; 126 | #else 127 | #define ga_weakify(object) autoreleasepool{} __block __typeof__(object) block##_##object = object; 128 | #endif 129 | #else 130 | #if __has_feature(objc_arc) 131 | #define ga_weakify(object) try{} @finally{} {} __weak __typeof__(object) weak##_##object = object; 132 | #else 133 | #define ga_weakify(object) try{} @finally{} {} __block __typeof__(object) block##_##object = object; 134 | #endif 135 | #endif 136 | #endif 137 | 138 | #ifndef ga_strongify 139 | #if DEBUG 140 | #if __has_feature(objc_arc) 141 | #define ga_strongify(object) autoreleasepool{} __typeof__(object) object = weak##_##object; 142 | #else 143 | #define ga_strongify(object) autoreleasepool{} __typeof__(object) object = block##_##object; 144 | #endif 145 | #else 146 | #if __has_feature(objc_arc) 147 | #define ga_strongify(object) try{} @finally{} __typeof__(object) object = weak##_##object; 148 | #else 149 | #define ga_strongify(object) try{} @finally{} __typeof__(object) object = block##_##object; 150 | #endif 151 | #endif 152 | #endif 153 | 154 | 155 | #endif /* DCAvatarConfig_h */ 156 | -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/Pods/SDWebImage/SDWebImage/Private/SDImageAssetManager.m: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the SDWebImage package. 3 | * (c) Olivier Poitrey 4 | * 5 | * For the full copyright and license information, please view the LICENSE 6 | * file that was distributed with this source code. 7 | */ 8 | 9 | #import "SDImageAssetManager.h" 10 | #import "SDInternalMacros.h" 11 | 12 | static NSArray *SDBundlePreferredScales() { 13 | static NSArray *scales; 14 | static dispatch_once_t onceToken; 15 | dispatch_once(&onceToken, ^{ 16 | #if SD_WATCH 17 | CGFloat screenScale = [WKInterfaceDevice currentDevice].screenScale; 18 | #elif SD_UIKIT 19 | CGFloat screenScale = [UIScreen mainScreen].scale; 20 | #elif SD_MAC 21 | NSScreen *mainScreen = nil; 22 | if (@available(macOS 10.12, *)) { 23 | mainScreen = [NSScreen mainScreen]; 24 | } else { 25 | mainScreen = [NSScreen screens].firstObject; 26 | } 27 | CGFloat screenScale = mainScreen.backingScaleFactor ?: 1.0f; 28 | #endif 29 | if (screenScale <= 1) { 30 | scales = @[@1,@2,@3]; 31 | } else if (screenScale <= 2) { 32 | scales = @[@2,@3,@1]; 33 | } else { 34 | scales = @[@3,@2,@1]; 35 | } 36 | }); 37 | return scales; 38 | } 39 | 40 | @implementation SDImageAssetManager { 41 | SD_LOCK_DECLARE(_lock); 42 | } 43 | 44 | + (instancetype)sharedAssetManager { 45 | static dispatch_once_t onceToken; 46 | static SDImageAssetManager *assetManager; 47 | dispatch_once(&onceToken, ^{ 48 | assetManager = [[SDImageAssetManager alloc] init]; 49 | }); 50 | return assetManager; 51 | } 52 | 53 | - (instancetype)init { 54 | self = [super init]; 55 | if (self) { 56 | NSPointerFunctionsOptions valueOptions; 57 | #if SD_MAC 58 | // Apple says that NSImage use a weak reference to value 59 | valueOptions = NSPointerFunctionsWeakMemory; 60 | #else 61 | // Apple says that UIImage use a strong reference to value 62 | valueOptions = NSPointerFunctionsStrongMemory; 63 | #endif 64 | _imageTable = [NSMapTable mapTableWithKeyOptions:NSPointerFunctionsCopyIn valueOptions:valueOptions]; 65 | SD_LOCK_INIT(_lock); 66 | #if SD_UIKIT 67 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveMemoryWarning:) name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; 68 | #endif 69 | } 70 | return self; 71 | } 72 | 73 | - (void)dealloc { 74 | #if SD_UIKIT 75 | [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; 76 | #endif 77 | } 78 | 79 | - (void)didReceiveMemoryWarning:(NSNotification *)notification { 80 | SD_LOCK(_lock); 81 | [self.imageTable removeAllObjects]; 82 | SD_UNLOCK(_lock); 83 | } 84 | 85 | - (NSString *)getPathForName:(NSString *)name bundle:(NSBundle *)bundle preferredScale:(CGFloat *)scale { 86 | NSParameterAssert(name); 87 | NSParameterAssert(bundle); 88 | NSString *path; 89 | if (name.length == 0) { 90 | return path; 91 | } 92 | if ([name hasSuffix:@"/"]) { 93 | return path; 94 | } 95 | NSString *extension = name.pathExtension; 96 | if (extension.length == 0) { 97 | // If no extension, follow Apple's doc, check PNG format 98 | extension = @"png"; 99 | } 100 | name = [name stringByDeletingPathExtension]; 101 | 102 | CGFloat providedScale = *scale; 103 | NSArray *scales = SDBundlePreferredScales(); 104 | 105 | // Check if file name contains scale 106 | for (size_t i = 0; i < scales.count; i++) { 107 | NSNumber *scaleValue = scales[i]; 108 | if ([name hasSuffix:[NSString stringWithFormat:@"@%@x", scaleValue]]) { 109 | path = [bundle pathForResource:name ofType:extension]; 110 | if (path) { 111 | *scale = scaleValue.doubleValue; // override 112 | return path; 113 | } 114 | } 115 | } 116 | 117 | // Search with provided scale first 118 | if (providedScale != 0) { 119 | NSString *scaledName = [name stringByAppendingFormat:@"@%@x", @(providedScale)]; 120 | path = [bundle pathForResource:scaledName ofType:extension]; 121 | if (path) { 122 | return path; 123 | } 124 | } 125 | 126 | // Search with preferred scale 127 | for (size_t i = 0; i < scales.count; i++) { 128 | NSNumber *scaleValue = scales[i]; 129 | if (scaleValue.doubleValue == providedScale) { 130 | // Ignore provided scale 131 | continue; 132 | } 133 | NSString *scaledName = [name stringByAppendingFormat:@"@%@x", scaleValue]; 134 | path = [bundle pathForResource:scaledName ofType:extension]; 135 | if (path) { 136 | *scale = scaleValue.doubleValue; // override 137 | return path; 138 | } 139 | } 140 | 141 | // Search without scale 142 | path = [bundle pathForResource:name ofType:extension]; 143 | 144 | return path; 145 | } 146 | 147 | - (UIImage *)imageForName:(NSString *)name { 148 | NSParameterAssert(name); 149 | UIImage *image; 150 | SD_LOCK(_lock); 151 | image = [self.imageTable objectForKey:name]; 152 | SD_UNLOCK(_lock); 153 | return image; 154 | } 155 | 156 | - (void)storeImage:(UIImage *)image forName:(NSString *)name { 157 | NSParameterAssert(image); 158 | NSParameterAssert(name); 159 | SD_LOCK(_lock); 160 | [self.imageTable setObject:image forKey:name]; 161 | SD_UNLOCK(_lock); 162 | } 163 | 164 | @end 165 | -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/CDDGroupAvatar/DCTestViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // DCTestViewController.m 3 | // CDDGroupAvatar 4 | // 5 | // Created by 陈甸甸 on 2019/7/28. 6 | //Copyright © 2019 RocketsChen. All rights reserved. 7 | // 8 | 9 | #import "DCTestViewController.h" 10 | #import "UIImageView+DCGroup.h" 11 | #import "DCAvatarManager.h" 12 | 13 | @interface DCTestViewController () 14 | 15 | @property (strong , nonatomic)NSMutableArray *groupArray; 16 | 17 | @end 18 | 19 | @implementation DCTestViewController 20 | 21 | - (NSMutableArray *)groupArray 22 | { 23 | if (!_groupArray) { 24 | _groupArray = [NSMutableArray array]; 25 | } 26 | return _groupArray; 27 | } 28 | 29 | 30 | - (void)viewDidLoad { 31 | [super viewDidLoad]; 32 | 33 | 34 | [self setUpGroupData]; 35 | 36 | 37 | [DCAvatarManager sharedAvatar].distanceBetweenAvatar = 2; 38 | [DCAvatarManager sharedAvatar].groupAvatarType = DCGroupAvatarWeChatType; 39 | 40 | self.tableView.rowHeight = 80; 41 | [self.tableView registerClass:[DCTestCell class] forCellReuseIdentifier:[NSString stringWithUTF8String:object_getClassName([DCTestCell class])]]; 42 | 43 | self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"clean" style:UIBarButtonItemStyleDone target:self action:@selector(clean)]; 44 | [self.navigationItem.rightBarButtonItem setTintColor:[UIColor blackColor]]; 45 | 46 | 47 | // for (NSInteger i = 0; i < 100; ++i) { // 暴力测试刷新数据 48 | // @weakify(self); 49 | // [[SDImageCache sharedImageCache] clearWithCacheType:SDImageCacheTypeAll completion:^{ 50 | // @strongify(self); 51 | // [self.tableView reloadData]; 52 | // NSLog(@"-index--------%zd",i); 53 | // }]; 54 | // } 55 | } 56 | 57 | 58 | - (void)clean 59 | { 60 | @ga_weakify(self); 61 | [[SDImageCache sharedImageCache] clearWithCacheType:SDImageCacheTypeAll completion:^{ 62 | @ga_strongify(self); 63 | [self.tableView reloadData]; 64 | }]; 65 | } 66 | 67 | - (void)setUpGroupData 68 | { 69 | 70 | [DCAvatarManager sharedAvatar].baseUrl = @"http://ww1.sinaimg.cn/small/"; 71 | 72 | for (NSInteger i = 0; i < 3 * 8; ++i) { 73 | DCTestItem *item = [DCTestItem new]; 74 | item.groupId = [NSString stringWithFormat:@"群头id-%zd",i]; 75 | 76 | NSInteger index = i / 8; 77 | NSInteger count = i % 8; 78 | 79 | item.groupSource = [[self allArray][index] subarrayWithRange:NSMakeRange(0, MIN(((NSArray *)[self allArray][index]).count, count + 2))]; 80 | 81 | [self.groupArray addObject:item]; 82 | } 83 | } 84 | 85 | 86 | - (NSArray *)allArray 87 | { 88 | return @[@[@"006tNc79gy1g5fmoexlt6j30u00vxqrb.jpg",@"006tNc79gy1g5fmofi07aj30u00uwqqk.jpg",@"006tNc79gy1g5fln5crn5j30u00u00vh.jpg",@"006tNc79gy1g5fln52xz8j30u00u0411.jpg",@"006tNc79gy1g5fmtvyydxj30u00u0x6r.jpg",@"006tNc79gy1g5fmogr9fsj30u00uz4m9.jpg",@"006tNc79gy1g5fmogcjidj30u00wc7su.jpg",@"006tNc79gy1g5fmofvp9cj30u00w8kft.jpg",@"006tNc79gy1g5fmofvp9cj30u00w8kft.jpg"],@[@"006tNc79gy1g5fln52xz8j30u00u0411.jpg",@"006tNc79gy1g5fln5crn5j30u00u00vh.jpg",@"006tNc79gy1g5fli2qszgj30ku0ii0ua.jpg",@"006tNc79gy1g5fli1g0wtj30rs0rs416.jpg",@"006tNc79gy1g5fli2zfzwj30qo0qojvv.jpg",@"006tNc79gy1g5fli3fr0oj30u00u2goh.jpg",@"006tNc79gy1g56or92vvmj30u00u048a.jpg",@"006tNc79gy1g56mcmorgrj30rk0nm0ze.jpg",@"006tNc79gy1g57h4j42ppj30u00u00vy.jpg"],@[@"006tNc79gy1g57hfrnhe6j30u00w01eu.jpg",@"006tNc79gy1g56or92vvmj30u00u048a.jpg",@"006tNc79gy1g57h4j42ppj30u00u00vy.jpg",@"无效地址头像",@"006tNc79gy1g57h4j42ppj30u00u00vy.jpg",@"无效地址头像",@"006tNc79gy1g5fli2j5x4j30u00u2ack.jpg",@"006tNc79gy1g5fli3fr0oj30u00u2goh.jpg",@"006tNc79gy1g57h4j42ppj30u00u00vy.jpg"]]; 89 | } 90 | 91 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 92 | return self.groupArray.count; 93 | } 94 | 95 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 96 | 97 | DCTestCell *cell = [tableView dequeueReusableCellWithIdentifier:[NSString stringWithUTF8String:object_getClassName([DCTestCell class])] forIndexPath:indexPath]; 98 | 99 | DCTestItem *item = self.groupArray[indexPath.row]; 100 | 101 | [cell.groupIamgeView dc_setImageAvatarWithGroupId:item.groupId Source:item.groupSource completed:^(NSString *groupId, UIImage *groupImage, NSArray *itemImageArray, NSString *cacheId) { 102 | cell.cacheIdLabel.text = [NSString stringWithFormat:@"缓存id-%@",cacheId]; 103 | }]; 104 | 105 | // [cell.groupIamgeView dc_setImageAvatarWithGroupId:item.groupId Source:item.groupSource itemPlaceholder:nil options:DCGroupAvatarCachedRefresh completed:^(NSString *groupId, UIImage *groupImage, NSArray *itemImageArray, NSString *cacheId) { 106 | // cell.cacheIdLabel.text = [NSString stringWithFormat:@"缓存id-%@",cacheId]; 107 | // }]; 108 | 109 | cell.groupIdLabel.text = item.groupId; 110 | 111 | 112 | return cell; 113 | } 114 | 115 | 116 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 117 | { 118 | [tableView deselectRowAtIndexPath:indexPath animated:YES]; 119 | } 120 | 121 | 122 | @end 123 | 124 | 125 | 126 | 127 | @implementation DCTestItem 128 | 129 | 130 | @end 131 | 132 | 133 | 134 | @implementation DCTestCell 135 | 136 | - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { 137 | 138 | self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; 139 | if (self) { 140 | 141 | [self setUpUI]; 142 | } 143 | return self; 144 | } 145 | 146 | 147 | - (void)setUpUI 148 | { 149 | _groupIamgeView = [[UIImageView alloc] init]; 150 | [self.contentView addSubview:_groupIamgeView]; 151 | _groupIamgeView.frame = CGRectMake(12, 10, 60, 60); 152 | 153 | 154 | _groupIdLabel = [[UILabel alloc] init]; 155 | [self.contentView addSubview:_groupIdLabel]; 156 | _groupIdLabel.font = [UIFont systemFontOfSize:18]; 157 | 158 | 159 | _cacheIdLabel = [[UILabel alloc] init]; 160 | [self.contentView addSubview:_cacheIdLabel]; 161 | _cacheIdLabel.textColor = [UIColor lightGrayColor]; 162 | _cacheIdLabel.font = [UIFont systemFontOfSize:15]; 163 | } 164 | 165 | - (void)layoutSubviews { 166 | 167 | [super layoutSubviews]; 168 | 169 | _groupIdLabel.frame = CGRectMake(CGRectGetMaxX(_groupIamgeView.frame) + 10, 10, self.frame.size.width - (CGRectGetMaxX(_groupIamgeView.frame) + 30), 30); 170 | _cacheIdLabel.frame = CGRectMake(CGRectGetMaxX(_groupIamgeView.frame) + 10, CGRectGetMaxY(_groupIdLabel.frame) + 4, self.frame.size.width - (CGRectGetMaxX(_groupIamgeView.frame) + 30), 20); 171 | } 172 | 173 | @end 174 | -------------------------------------------------------------------------------- /CDDGroupAvatar/NoCacheGroupAvatar/UIView+DCNoCacheGroup.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+DCNoCacheGroup.m 3 | // CDDGroupAvatar 4 | // 5 | // Created by 陈甸甸 on 2019/12/8. 6 | // Copyright © 2019 RocketsChen. All rights reserved. 7 | // 8 | 9 | #import "UIView+DCNoCacheGroup.h" 10 | 11 | @implementation UIView (DCNoCacheGroup) 12 | 13 | - (void)dc_setNoCacheAvatarWithGroupId:(NSString *)groupId Source:(NSArray *)groupSource setImageBlock:(GroupSetImageBlock)setImageBlock completed:(GroupImageBlock)completedBlock 14 | { 15 | [self setUpNoCacheAllTypeAvatarGroupId:groupId Source:groupSource setImageBlock:setImageBlock completed:^(NSString *groupId, UIImage *groupImage, NSArray *itemImageArray, NSString *cacheId) { 16 | if (completedBlock) { 17 | completedBlock(groupId, groupImage, itemImageArray, cacheId); 18 | } 19 | }]; 20 | } 21 | 22 | 23 | - (void)setUpNoCacheAllTypeAvatarGroupId:(NSString *)groupId Source:(NSArray *)groupSource setImageBlock:(GroupSetImageBlock)setImageBlock completed:(GroupImageBlock)completedBlock 24 | { 25 | 26 | DCGroupAvatarType avatarType = [DCNoCahceAvatarManager sharedAvatar].groupAvatarType; 27 | 28 | groupSource = [DCAvatarHelper dc_getTypefMaxCount:groupSource avatarType:avatarType]; // MaxCount 29 | 30 | UIColor *avatarBgColor = [DCNoCahceAvatarManager sharedAvatar].avatarBgColor; 31 | 32 | CGFloat distance = [DCNoCahceAvatarManager sharedAvatar].distanceBetweenAvatar; 33 | 34 | __block UIImage *groupImage; 35 | GroupImageParamsBlock callCompletedBlock = ^{ // block 36 | if (!self) { return; } 37 | if (completedBlock) { 38 | completedBlock(groupId, groupImage, groupSource, DCNoCacheIdMD5(groupId, groupSource)); 39 | } 40 | }; 41 | 42 | CGSize itemAvaSize; 43 | CGPoint itemAvaPoint; 44 | 45 | CGSize containerSize = CGSizeMake(self.frame.size.width, self.frame.size.height); 46 | 47 | UIGraphicsBeginImageContextWithOptions(containerSize, NO, UIScreen.mainScreen.scale); 48 | CGContextRef ctx = UIGraphicsGetCurrentContext(); 49 | 50 | CGContextSetFillColorWithColor(ctx, avatarBgColor.CGColor); 51 | CGContextFillRect(ctx, CGRectMake(0, 0, containerSize.width, containerSize.height)); 52 | 53 | if (avatarType != DCGroupAvatarWeiBoType) { // WeChat / QQ 54 | 55 | if (avatarType == DCGroupAvatarWeChatType) { 56 | itemAvaSize = [DCAvatarHelper dc_calculateSizeWeChatAvatarGroupCount:groupSource.count containerSize:containerSize distanceBetweenAvatar:distance]; 57 | } 58 | 59 | for (NSInteger i = 0; i < groupSource.count; ++i) { 60 | @autoreleasepool { 61 | if (avatarType == DCGroupAvatarQQType) { 62 | itemAvaSize = [DCAvatarHelper dc_calculateSizeQQAvatarGroupCount:groupSource.count index:i containerSize:containerSize distanceBetweenAvatar:distance]; 63 | } 64 | UIImage *avatarImage = groupSource[i]; 65 | 66 | if (itemAvaSize.height != itemAvaSize.width) { // 当时不是1:1的时候需要裁减 默认是以中心和长的一边为准裁取短的 67 | 68 | CGFloat longEdge = MAX(itemAvaSize.height, itemAvaSize.width); 69 | CGFloat shortEdge = MIN(itemAvaSize.height, itemAvaSize.width); 70 | avatarImage = [avatarImage dc_cutImageViewSize:CGSizeMake(longEdge, longEdge) clipRect:CGRectMake((longEdge - shortEdge) * 0.5, 0, shortEdge, longEdge)]; 71 | } 72 | 73 | itemAvaPoint = [DCAvatarHelper dc_calculatePointAvatarGroupCount:groupSource.count index:i containerSize:containerSize distanceBetweenAvatar:distance avatarType:avatarType]; 74 | 75 | CGRect avaRect = CGRectMake(itemAvaPoint.x, itemAvaPoint.y, itemAvaSize.width, itemAvaSize.height); 76 | 77 | [avatarImage drawInRect:avaRect]; 78 | } 79 | } 80 | 81 | }else{ // WeiBo 82 | 83 | __block CGFloat bordWidth = [DCNoCahceAvatarManager sharedAvatar].bordWidth; 84 | 85 | CGFloat radius = [DCAvatarHelper dc_calculateRadiusWeiBoAvatarGroupCount:groupSource.count containerSize:containerSize distanceBetweenAvatar:distance]; 86 | 87 | for (NSInteger i = 0; i < groupSource.count; ++i) { 88 | @autoreleasepool { 89 | UIImage *avatarImage = [groupSource[i] dc_cgContextAddArcToPointImageBorderWidth:bordWidth borderColor:avatarBgColor]; // 画出外边框 90 | 91 | CGContextSaveGState(ctx); 92 | 93 | itemAvaPoint = [DCAvatarHelper dc_calculateWeiBoAvatarGroupCount:groupSource.count index:i containerSize:containerSize distanceBetweenAvatar:distance]; 94 | 95 | CGContextAddArc(ctx, itemAvaPoint.x, itemAvaPoint.y, radius, 0, M_PI * 2, 1); 96 | 97 | CGContextClosePath(ctx); 98 | CGContextClip(ctx); 99 | 100 | CGRect avatarRect = CGRectMake(itemAvaPoint.x - radius, itemAvaPoint.y - radius, radius * 2, radius * 2); 101 | 102 | [avatarImage drawInRect:avatarRect]; 103 | 104 | CGContextRestoreGState(ctx); 105 | } 106 | } 107 | } 108 | 109 | groupImage = UIGraphicsGetImageFromCurrentImageContext(); 110 | if (![DCAvatarHelper dc_getCGImageRefContainsAlpha:groupSource.firstObject.CGImage]) { 111 | groupImage = [UIImage imageWithData:UIImageJPEGRepresentation(groupImage, 1.0)]; 112 | } 113 | UIGraphicsEndImageContext(); 114 | 115 | if (avatarType == DCGroupAvatarQQType) { 116 | groupImage = [groupImage dc_cgContextAddArcToPointImageBorderWidth:0 borderColor:UIColor.clearColor]; 117 | } 118 | 119 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ 120 | dispatch_main_async_safe(^{ 121 | [self dc_noCachesetImage:groupImage setImageBlock:setImageBlock]; 122 | callCompletedBlock(); 123 | }); 124 | }); 125 | } 126 | 127 | 128 | 129 | - (void)dc_noCachesetImage:(UIImage *)groupImage setImageBlock:(GroupSetImageBlock)setImageBlock 130 | { 131 | if (!groupImage) return; 132 | UIView *view = self; 133 | GroupSetImageBlock finishSetBlock; 134 | 135 | if (setImageBlock) { 136 | finishSetBlock = setImageBlock; 137 | } else if ([view isKindOfClass:[UIImageView class]]) { 138 | UIImageView *imageView = (UIImageView *)view; 139 | finishSetBlock = ^(UIImage *setImage) { 140 | imageView.image = setImage; 141 | }; 142 | }else if ([view isKindOfClass:[UIButton class]]) { 143 | UIButton *button = (UIButton *)view; 144 | finishSetBlock = ^(UIImage *setImage) { 145 | [button setImage:setImage forState:UIControlStateNormal]; 146 | }; 147 | } 148 | if (finishSetBlock) { 149 | finishSetBlock(groupImage); 150 | } 151 | } 152 | 153 | @end 154 | -------------------------------------------------------------------------------- /CDDGroupAvatar/CacheGroupAvatar/UIView+DCGroup.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+DCGroup.m 3 | // CDDGroupAvatar 4 | // 5 | // Created by 陈甸甸 on 2019/7/24. 6 | // Copyright © 2019 RocketsChen. All rights reserved. 7 | // 8 | 9 | #import "UIView+DCGroup.h" 10 | 11 | #import "DCAvatarManager.h" 12 | #import "DCCacheAvatarHelper.h" 13 | #import "UIImage+DCAvatar.h" 14 | 15 | 16 | @implementation UIView (DCGroup) 17 | 18 | 19 | - (void)dc_setAvatarWithGroupId:(NSString *)groupId Source:(NSArray *)groupSource cacheKeys:(NSArray *)cacheKeys itemPlaceholder:(id)placeholder options:(DCGroupAvatarCacheType)options setImageBlock:(GroupSetImageBlock)setImageBlock completed:(GroupImageBlock)completedBlock 20 | { 21 | 22 | [self setUpAllTypeAvatarGroupId:groupId Source:groupSource cacheKeys:cacheKeys itemPlaceholder:placeholder options:options setImageBlock:setImageBlock completed:^(NSString *groupId, UIImage *groupImage, NSArray *itemImageArray, NSString *cacheId) { 23 | if (completedBlock) { 24 | completedBlock(groupId, groupImage, itemImageArray, cacheId); 25 | } 26 | }]; 27 | } 28 | 29 | 30 | - (void)setUpAllTypeAvatarGroupId:(NSString *)groupId Source:(NSArray *)groupSource cacheKeys:(NSArray *)cacheKeys itemPlaceholder:(id)placeholder options:(DCGroupAvatarCacheType)options setImageBlock:(GroupSetImageBlock)setImageBlock completed:(GroupImageBlock)completedBlock 31 | { 32 | @ga_weakify(self); 33 | __block DCGroupAvatarType avatarType = [DCAvatarManager sharedAvatar].groupAvatarType; 34 | 35 | groupSource = [DCAvatarHelper dc_getTypefMaxCount:groupSource avatarType:avatarType]; // MaxCount 36 | 37 | __block UIColor *avatarBgColor = [DCAvatarManager sharedAvatar].avatarBgColor; 38 | 39 | __block CGFloat distance = [DCAvatarManager sharedAvatar].distanceBetweenAvatar; 40 | 41 | __block UIImage *groupImage = [[SDImageCache sharedImageCache] imageFromCacheForKey:DCCacheIdMD5(groupId, groupSource)]; // Cache and Disk 42 | 43 | __block NSArray *groupUnitImages; 44 | 45 | dispatch_main_async_safe(^{ 46 | @ga_strongify(self); 47 | [self dc_setImage:groupImage setImageBlock:setImageBlock]; 48 | }); 49 | 50 | GroupImageParamsBlock callCompletedBlock = ^{ // block 51 | if (!self) { return; } 52 | if (completedBlock) { 53 | completedBlock(groupId, groupImage, groupUnitImages, DCCacheIdMD5(groupId, groupSource)); 54 | } 55 | }; 56 | 57 | 58 | if ((options == DCGroupAvatarCachedDefault) && groupImage) { 59 | 60 | groupUnitImages = [DCCacheAvatarHelper dc_fetchItemCacheArraySource:groupSource]; 61 | dispatch_main_async_safe(callCompletedBlock); 62 | 63 | return; 64 | } 65 | 66 | [DCCacheAvatarHelper dc_fetchLoadImageSource:groupSource cacheKeys:cacheKeys cacheGroupImage:groupImage itemPlaceholder:placeholder completedBlock:^(NSArray *unitImages, BOOL succeed) { 67 | @ga_strongify(self); 68 | 69 | groupUnitImages = unitImages; 70 | 71 | CGSize itemAvaSize; 72 | CGPoint itemAvaPoint; 73 | 74 | CGSize containerSize = CGSizeMake(self.frame.size.width, self.frame.size.height); 75 | 76 | UIGraphicsBeginImageContextWithOptions(containerSize, NO, UIScreen.mainScreen.scale); 77 | CGContextRef ctx = UIGraphicsGetCurrentContext(); 78 | 79 | CGContextSetFillColorWithColor(ctx, avatarBgColor.CGColor); 80 | CGContextFillRect(ctx, CGRectMake(0, 0, containerSize.width, containerSize.height)); 81 | 82 | 83 | if (avatarType != DCGroupAvatarWeiBoType) { // WeChat / QQ 84 | 85 | if (avatarType == DCGroupAvatarWeChatType) { 86 | itemAvaSize = [DCAvatarHelper dc_calculateSizeWeChatAvatarGroupCount:groupSource.count containerSize:containerSize distanceBetweenAvatar:distance]; 87 | } 88 | 89 | for (NSInteger i = 0; i < groupUnitImages.count; ++i) { 90 | @autoreleasepool { 91 | if (avatarType == DCGroupAvatarQQType) { 92 | itemAvaSize = [DCAvatarHelper dc_calculateSizeQQAvatarGroupCount:groupSource.count index:i containerSize:containerSize distanceBetweenAvatar:distance]; 93 | } 94 | UIImage *avatarImage = groupUnitImages[i]; 95 | 96 | if (itemAvaSize.height != itemAvaSize.width) { // 当时不是1:1的时候需要裁减 默认是以中心和长的一边为准裁取短的 97 | 98 | CGFloat longEdge = MAX(itemAvaSize.height, itemAvaSize.width); 99 | CGFloat shortEdge = MIN(itemAvaSize.height, itemAvaSize.width); 100 | avatarImage = [avatarImage dc_cutImageViewSize:CGSizeMake(longEdge, longEdge) clipRect:CGRectMake((longEdge - shortEdge) * 0.5, 0, shortEdge, longEdge)]; 101 | } 102 | 103 | itemAvaPoint = [DCAvatarHelper dc_calculatePointAvatarGroupCount:groupUnitImages.count index:i containerSize:containerSize distanceBetweenAvatar:distance avatarType:avatarType]; 104 | 105 | CGRect avaRect = CGRectMake(itemAvaPoint.x, itemAvaPoint.y, itemAvaSize.width, itemAvaSize.height); 106 | 107 | [avatarImage drawInRect:avaRect]; 108 | } 109 | } 110 | 111 | }else{ // WeiBo 112 | 113 | __block CGFloat bordWidth = [DCAvatarManager sharedAvatar].bordWidth; 114 | 115 | CGFloat radius = [DCAvatarHelper dc_calculateRadiusWeiBoAvatarGroupCount:groupSource.count containerSize:containerSize distanceBetweenAvatar:distance]; 116 | 117 | for (NSInteger i = 0; i < groupUnitImages.count; ++i) { 118 | @autoreleasepool { 119 | UIImage *avatarImage = [groupUnitImages[i] dc_cgContextAddArcToPointImageBorderWidth:bordWidth borderColor:avatarBgColor]; // 画出外边框 120 | 121 | CGContextSaveGState(ctx); 122 | 123 | itemAvaPoint = [DCAvatarHelper dc_calculateWeiBoAvatarGroupCount:groupSource.count index:i containerSize:containerSize distanceBetweenAvatar:distance]; 124 | 125 | CGContextAddArc(ctx, itemAvaPoint.x, itemAvaPoint.y, radius, 0, M_PI * 2, 1); 126 | 127 | CGContextClosePath(ctx); 128 | CGContextClip(ctx); 129 | 130 | CGRect avatarRect = CGRectMake(itemAvaPoint.x - radius, itemAvaPoint.y - radius, radius * 2, radius * 2); 131 | 132 | [avatarImage drawInRect:avatarRect]; 133 | 134 | CGContextRestoreGState(ctx); 135 | } 136 | } 137 | } 138 | 139 | groupImage = UIGraphicsGetImageFromCurrentImageContext(); 140 | if (![DCAvatarHelper dc_getCGImageRefContainsAlpha:unitImages.firstObject.CGImage]) { 141 | groupImage = [UIImage imageWithData:UIImageJPEGRepresentation(groupImage, 1.0)]; 142 | } 143 | UIGraphicsEndImageContext(); 144 | 145 | if (avatarType == DCGroupAvatarQQType) { 146 | groupImage = [groupImage dc_cgContextAddArcToPointImageBorderWidth:0 borderColor:UIColor.clearColor]; 147 | } 148 | 149 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ 150 | @autoreleasepool { 151 | if (succeed) { // 如果群内部头像全部加载失败则不存,成功后在存本地 152 | [[SDImageCache sharedImageCache] storeImage:groupImage forKey:DCCacheIdMD5(groupId, groupSource) toDisk:YES completion:nil]; // add Cache and Disk 153 | } 154 | } 155 | dispatch_main_async_safe(^{ 156 | 157 | [self dc_setImage:groupImage setImageBlock:setImageBlock]; 158 | callCompletedBlock(); 159 | }); 160 | }); 161 | 162 | }]; 163 | } 164 | 165 | 166 | - (void)dc_setImage:(UIImage *)groupImage setImageBlock:(GroupSetImageBlock)setImageBlock 167 | { 168 | if (!groupImage) return; 169 | UIView *view = self; 170 | GroupSetImageBlock finishSetBlock; 171 | 172 | if (setImageBlock) { 173 | finishSetBlock = setImageBlock; 174 | } else if ([view isKindOfClass:[UIImageView class]]) { 175 | UIImageView *imageView = (UIImageView *)view; 176 | finishSetBlock = ^(UIImage *setImage) { 177 | imageView.image = setImage; 178 | }; 179 | }else if ([view isKindOfClass:[UIButton class]]) { 180 | UIButton *button = (UIButton *)view; 181 | finishSetBlock = ^(UIImage *setImage) { 182 | [button setImage:setImage forState:UIControlStateNormal]; 183 | }; 184 | } 185 | if (finishSetBlock) { 186 | finishSetBlock(groupImage); 187 | } 188 | } 189 | 190 | 191 | @end 192 | -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/CDDGroupAvatar/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // CDDGroupAvatar 4 | // 5 | // Imageed by 陈甸甸 on 2019/7/18. 6 | // Copyright © 2019 RocketsChen. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "DCAvatar.h" 11 | #import "DCCacheAvatarHelper.h" 12 | #import "DCNoCacheAvatar.h" 13 | #import 14 | 15 | #import 16 | #import 17 | #import "DCTestViewController.h" 18 | 19 | @interface ViewController () 20 | { 21 | NSArray *_groupNum2; 22 | NSArray *_groupNum3; 23 | NSArray *_groupNum4; 24 | NSArray *_groupNum5; 25 | NSArray *_groupNum6; 26 | NSArray *_groupNum7; 27 | NSArray *_groupNum8; 28 | NSArray *_groupNum9; 29 | } 30 | 31 | // Button 32 | @property (weak, nonatomic) IBOutlet UIButton *avaButton; 33 | @property (weak, nonatomic) IBOutlet UIButton *avaBgButton; 34 | 35 | 36 | // QQ 37 | @property (weak, nonatomic) IBOutlet UIImageView *avImageViewNQ2; 38 | @property (weak, nonatomic) IBOutlet UIImageView *avImageViewNQ3; 39 | @property (weak, nonatomic) IBOutlet UIImageView *avImageViewNQ4; 40 | 41 | // WeBo 42 | @property (weak, nonatomic) IBOutlet UIImageView *avImageViewWeiBo2; 43 | @property (weak, nonatomic) IBOutlet UIImageView *avImageViewWeiBo3; 44 | @property (weak, nonatomic) IBOutlet UIImageView *avImageViewWeiBo4; 45 | 46 | // WeChat 47 | @property (weak, nonatomic) IBOutlet UIImageView *avImageViewW2; 48 | @property (weak, nonatomic) IBOutlet UIImageView *avImageViewW3; 49 | @property (weak, nonatomic) IBOutlet UIImageView *avImageViewW4; 50 | @property (weak, nonatomic) IBOutlet UIImageView *avImageViewW5; 51 | @property (weak, nonatomic) IBOutlet UIImageView *avImageViewW6; 52 | @property (weak, nonatomic) IBOutlet UIImageView *avImageViewW7; 53 | @property (weak, nonatomic) IBOutlet UIImageView *avImageViewW8; 54 | @property (weak, nonatomic) IBOutlet UIImageView *avImageViewW9; 55 | 56 | 57 | 58 | // NoCache 59 | @property (weak, nonatomic) IBOutlet UIImageView *ncImageViewW3; 60 | @property (weak, nonatomic) IBOutlet UIImageView *ncImageViewW4; 61 | 62 | 63 | @end 64 | 65 | @implementation ViewController 66 | 67 | - (void)viewDidLoad { 68 | [super viewDidLoad]; 69 | 70 | [self setUpNav]; 71 | 72 | [self setUpDataSource]; 73 | 74 | [self setUpLoadData]; 75 | 76 | [self setUpGetAllItemAva]; 77 | 78 | 79 | [self setUpNoCache]; 80 | 81 | } 82 | 83 | 84 | - (void)setUpNav 85 | { 86 | self.title = @"CDDGroupAvatar"; 87 | self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"table" style:UIBarButtonItemStyleDone target:self action:@selector(goToTest)]; 88 | [self.navigationItem.rightBarButtonItem setTintColor:[UIColor blackColor]]; 89 | 90 | self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"clean" style:UIBarButtonItemStyleDone target:self action:@selector(clean)]; 91 | [self.navigationItem.leftBarButtonItem setTintColor:[UIColor blackColor]]; 92 | } 93 | 94 | 95 | - (void)clean 96 | { 97 | @ga_weakify(self); 98 | [[SDImageCache sharedImageCache] clearWithCacheType:SDImageCacheTypeAll completion:^{ 99 | @ga_strongify(self); 100 | [self setUpLoadData]; 101 | }]; 102 | } 103 | 104 | 105 | 106 | - (void)setUpNoCache 107 | { 108 | 109 | [self.ncImageViewW3 dc_setNoCacheImageAvatarWithGroupId:@"avImageViewW3" Source:@[[UIImage imageNamed:@"noCache1"],[UIImage imageNamed:@"noCache2"],[UIImage imageNamed:@"noCache3"]] completed:^(NSString *groupId, UIImage *groupImage, NSArray *itemImageArray, NSString *cacheId) { 110 | NSLog(@"groupId:%@ -- 群头像:%@ 群内拼接小头像数组:%@ -- cacheId:%@",groupId, groupImage, itemImageArray , cacheId); 111 | }]; 112 | 113 | [self.ncImageViewW4 dc_setNoCacheImageAvatarWithGroupId:@"avImageViewW4" Source:@[[UIImage imageNamed:@"noCache1"],[UIImage imageNamed:@"noCache2"],[UIImage imageNamed:@"noCache3"],[UIImage imageNamed:@"noCache4"]]]; 114 | } 115 | 116 | 117 | 118 | - (void)setUpGetAllItemAva 119 | { 120 | NSArray *itemImages = [DCCacheAvatarHelper dc_synfetchLoadImageSource:_groupNum8 itemPlaceholder:nil]; 121 | [DCCacheAvatarHelper dc_asynfetchLoadImageSource:_groupNum9 itemPlaceholder:nil completedBlock:^(NSArray *unitImages) { 122 | 123 | }]; 124 | NSLog(@"群内小头像数组%@",itemImages); 125 | } 126 | 127 | 128 | - (void)setUpLoadData 129 | { 130 | [DCAvatarManager sharedAvatar].baseUrl = @"http://ww1.sinaimg.cn/small/"; 131 | [DCAvatarManager sharedAvatar].placeholderImage = [UIImage imageNamed:@"avatarholder"]; 132 | 133 | [self setUpWeiBo]; 134 | 135 | [self setUpNewQQ]; 136 | 137 | [self setUpWeChat]; 138 | 139 | [self setUpTestButton]; 140 | } 141 | 142 | 143 | - (void)setUpWeiBo 144 | { 145 | [DCAvatarManager sharedAvatar].groupAvatarType = DCGroupAvatarWeiBoType; 146 | [DCAvatarManager sharedAvatar].distanceBetweenAvatar = 2; 147 | 148 | [self.avImageViewWeiBo2 dc_setImageAvatarWithGroupId:@"avImageViewWeiBo2" Source:_groupNum2]; 149 | [self.avImageViewWeiBo3 dc_setImageAvatarWithGroupId:@"avImageViewWeiBo3" Source:_groupNum3]; 150 | [self.avImageViewWeiBo4 dc_setImageAvatarWithGroupId:@"avImageViewWeiBo4" Source:_groupNum4]; 151 | 152 | } 153 | 154 | - (void)setUpTestButton 155 | { 156 | [DCAvatarManager sharedAvatar].distanceBetweenAvatar = 2; 157 | [DCAvatarManager sharedAvatar].groupAvatarType = DCGroupAvatarWeChatType; 158 | 159 | [self.avaButton dc_setImageAvatarWithGroupId:@"avaButton" Source:_groupNum9 forState:0]; 160 | [self.avaBgButton dc_setBackgroundImageAvatarWithGroupId:@"avaBgButton" Source:@[@"006tNc79gy1g5fmoexlt6j30u00vxqrb.jpg"] forState:0]; 161 | } 162 | 163 | 164 | 165 | - (void)setUpNewQQ 166 | { 167 | [DCAvatarManager sharedAvatar].distanceBetweenAvatar = 1; 168 | [DCAvatarManager sharedAvatar].groupAvatarType = DCGroupAvatarQQType; 169 | [self.avImageViewNQ2 dc_setImageAvatarWithGroupId:@"avImageViewNQ2" Source:_groupNum2]; 170 | 171 | [self.avImageViewNQ3 dc_setImageAvatarWithGroupId:@"avImageViewNQ3" Source:_groupNum3]; 172 | 173 | [self.avImageViewNQ4 dc_setImageAvatarWithGroupId:@"avImageViewNQ4" Source:_groupNum4]; 174 | 175 | } 176 | 177 | 178 | - (void)setUpWeChat 179 | { 180 | [DCAvatarManager sharedAvatar].distanceBetweenAvatar = 2; 181 | [DCAvatarManager sharedAvatar].groupAvatarType = DCGroupAvatarWeChatType; 182 | 183 | // 传入无效地址测试 Placeholder属性 184 | [self.avImageViewW2 dc_setImageAvatarWithGroupId:@"avImageViewW2" Source:@[@"1",@"2"] itemPlaceholder:@[@"man",@"woman"] options:0 completed:nil]; 185 | 186 | [self.avImageViewW3 dc_setImageAvatarWithGroupId:@"avImageViewW3" Source:_groupNum3]; 187 | 188 | // options == DCGroupAvatarCachedRefresh 每次都刷新 189 | [self.avImageViewW4 dc_setImageAvatarWithGroupId:@"avImageViewW4" Source:_groupNum4 itemPlaceholder:@"place" options:DCGroupAvatarCachedRefresh completed:nil]; 190 | 191 | [self.avImageViewW5 dc_setImageAvatarWithGroupId:@"avImageViewW5" Source:_groupNum5]; 192 | [self.avImageViewW6 dc_setImageAvatarWithGroupId:@"avImageViewW6" Source:_groupNum6]; 193 | [self.avImageViewW7 dc_setImageAvatarWithGroupId:@"avImageViewW7" Source:_groupNum7]; 194 | [self.avImageViewW8 dc_setImageAvatarWithGroupId:@"avImageViewW8" Source:_groupNum8]; 195 | 196 | [self.avImageViewW9 dc_setImageAvatarWithGroupId:@"avImageViewW9" Source:_groupNum9 completed:^(NSString *groupId, UIImage *groupImage, NSArray *itemImageArray, NSString *cacheId) { 197 | NSLog(@"groupId:%@ -- 群头像:%@ 群内拼接小头像数组:%@ -- cacheId:%@",groupId, groupImage, itemImageArray , cacheId); 198 | }]; 199 | } 200 | 201 | #pragma mark - 数据源 202 | - (void)setUpDataSource 203 | { 204 | _groupNum2 = @[@"006tNc79gy1g56or92vvmj30u00u048a.jpg",@"006tNc79gy1g56mcmorgrj30rk0nm0ze.jpg"]; 205 | 206 | _groupNum3 = @[@"006tNc79gy1g56or92vvmj30u00u048a.jpg",@"006tNc79gy1g56mcmorgrj30rk0nm0ze.jpg",@"006tNc79gy1g57h4j42ppj30u00u00vy.jpg"]; 207 | 208 | _groupNum4 = @[@"006tNc79gy1g57h4j42ppj30u00u00vy.jpg",@"006tNc79gy1g56mcmorgrj30rk0nm0ze.jpg",@"006tNc79gy1g56or92vvmj30u00u048a.jpg",@"006tNc79gy1g57hfrnhe6j30u00w01eu.jpg"]; 209 | 210 | _groupNum5 = @[@"006tNc79gy1g56or92vvmj30u00u048a.jpg",@"006tNc79gy1g56mcmorgrj30rk0nm0ze.jpg",@"006tNc79gy1g57h4j42ppj30u00u00vy.jpg",@"006tNc79gy1g57hfrnhe6j30u00w01eu.jpg",@"006tNc79gy1g56or92vvmj30u00u048a.jpg"]; 211 | 212 | _groupNum6 = @[@"006tNc79gy1g56or92vvmj30u00u048a.jpg",@"006tNc79gy1g56mcmorgrj30rk0nm0ze.jpg",@"006tNc79gy1g57h4j42ppj30u00u00vy.jpg",@"006tNc79gy1g57hfrnhe6j30u00w01eu.jpg",@"006tNc79gy1g56or92vvmj30u00u048a.jpg",@"006tNc79gy1g57h4j42ppj30u00u00vy.jpg"]; 213 | 214 | _groupNum7 = @[@"006tNc79gy1g56or92vvmj30u00u048a.jpg",@"006tNc79gy1g56mcmorgrj30rk0nm0ze.jpg",@"006tNc79gy1g57h4j42ppj30u00u00vy.jpg",@"006tNc79gy1g57hfrnhe6j30u00w01eu.jpg",@"006tNc79gy1g56or92vvmj30u00u048a.jpg",@"006tNc79gy1g57h4j42ppj30u00u00vy.jpg",@"006tNc79gy1g56or92vvmj30u00u048a.jpg"]; 215 | 216 | _groupNum8 = @[@"006tNc79gy1g56or92vvmj30u00u048a.jpg",@"006tNc79gy1g56mcmorgrj30rk0nm0ze.jpg",@"006tNc79gy1g57h4j42ppj30u00u00vy.jpg",@"006tNc79gy1g57hfrnhe6j30u00w01eu.jpg",@"006tNc79gy1g56or92vvmj30u00u048a.jpg",@"006tNc79gy1g57h4j42ppj30u00u00vy.jpg",@"006tNc79gy1g56or92vvmj30u00u048a.jpg",@"006tNc79gy1g57h4j42ppj30u00u00vy.jpg"]; 217 | 218 | 219 | _groupNum9 = @[@"006tNc79gy1g56or92vvmj30u00u048a.jpg",@"006tNc79gy1g56mcmorgrj30rk0nm0ze.jpg",@"006tNc79gy1g57h4j42ppj30u00u00vy.jpg",@"006tNc79gy1g57hfrnhe6j30u00w01eu.jpg",@"006tNc79gy1g56or92vvmj30u00u048a.jpg",@"006tNc79gy1g57h4j42ppj30u00u00vy.jpg",@"006tNc79gy1g56or92vvmj30u00u048a.jpg",@"006tNc79gy1g57h4j42ppj30u00u00vy.jpg",@"006tNc79gy1g57h4j42ppj30u00u00vy.jpg"]; 220 | } 221 | 222 | 223 | - (void)goToTest 224 | { 225 | [self.navigationController pushViewController:[DCTestViewController new] animated:YES]; 226 | } 227 | 228 | @end 229 | -------------------------------------------------------------------------------- /Demo/CDDGroupAvatar/CDDGroupAvatar/PFS/KMCGeigerCounter/KMCGeigerCounter.m: -------------------------------------------------------------------------------- 1 | // 2 | // KMCGeigerCounter.m 3 | // KMCGeigerCounter 4 | // 5 | // Created by Kevin Conner on 10/21/14. 6 | // Copyright (c) 2014 Kevin Conner. All rights reserved. 7 | // 8 | 9 | #import "KMCGeigerCounter.h" 10 | #import 11 | 12 | #define isXDevice (([[UIScreen mainScreen] respondsToSelector:@selector(nativeBounds)] ? [UIScreen mainScreen].nativeBounds.size.height/[UIScreen mainScreen].nativeScale : [UIScreen mainScreen].bounds.size.height) > 800.0) 13 | 14 | @interface KMCGeigerCounter () 15 | 16 | @property (nonatomic, readwrite, assign, getter = isRunning) BOOL running; 17 | 18 | @property (nonatomic, strong) UIWindow *window; 19 | @property (nonatomic, strong) UILabel *meterLabel; 20 | @property (nonatomic, strong) UIColor *meterPerfectColor; 21 | @property (nonatomic, strong) UIColor *meterGoodColor; 22 | @property (nonatomic, strong) UIColor *meterBadColor; 23 | 24 | @property (nonatomic, strong) CADisplayLink *displayLink; 25 | @property (nonatomic, assign) SystemSoundID tickSoundID; 26 | 27 | @property (nonatomic, assign) NSInteger frameNumber; 28 | 29 | @property (nonatomic, assign) NSInteger hardwareFramesPerSecond; 30 | @property (nonatomic, assign) CFTimeInterval *recentFrameTimes; // malloc: CFTimeInterval[hardwareFramesPerSecond] 31 | 32 | @end 33 | 34 | @implementation KMCGeigerCounter 35 | 36 | #pragma mark - Helpers 37 | 38 | + (UIColor *)colorWithHex:(uint32_t)hex alpha:(CGFloat)alpha 39 | { 40 | CGFloat red = (CGFloat) ((hex & 0xff0000) >> 16) / 255.0f; 41 | CGFloat green = (CGFloat) ((hex & 0x00ff00) >> 8) / 255.0f; 42 | CGFloat blue = (CGFloat) (hex & 0x0000ff) / 255.0f; 43 | return [UIColor colorWithRed:red green:green blue:blue alpha:alpha]; 44 | } 45 | 46 | - (CFTimeInterval)lastFrameTime 47 | { 48 | return _recentFrameTimes[self.frameNumber % self.hardwareFramesPerSecond]; 49 | } 50 | 51 | - (void)recordFrameTime:(CFTimeInterval)frameTime 52 | { 53 | ++self.frameNumber; 54 | _recentFrameTimes[self.frameNumber % self.hardwareFramesPerSecond] = frameTime; 55 | } 56 | 57 | - (void)clearLastSecondOfFrameTimes 58 | { 59 | CFTimeInterval initialFrameTime = CACurrentMediaTime(); 60 | for (NSInteger i = 0; i < self.hardwareFramesPerSecond; ++i) { 61 | _recentFrameTimes[i] = initialFrameTime; 62 | } 63 | self.frameNumber = 0; 64 | } 65 | 66 | - (void)updateMeterLabel 67 | { 68 | NSInteger droppedFrameCount = self.droppedFrameCountInLastSecond; 69 | NSInteger drawnFrameCount = self.drawnFrameCountInLastSecond; 70 | 71 | NSString *droppedString; 72 | NSString *drawnString; 73 | 74 | if (droppedFrameCount <= 0) { 75 | self.meterLabel.backgroundColor = self.meterPerfectColor; 76 | 77 | droppedString = @"--"; 78 | } else { 79 | if (droppedFrameCount <= 2) { 80 | self.meterLabel.backgroundColor = self.meterGoodColor; 81 | } else { 82 | self.meterLabel.backgroundColor = self.meterBadColor; 83 | } 84 | 85 | droppedString = [NSString stringWithFormat:@"%ld", (long) droppedFrameCount]; 86 | } 87 | 88 | if (drawnFrameCount == -1) { 89 | drawnString = @"--"; 90 | } else { 91 | drawnString = [NSString stringWithFormat:@"%ld", (long) drawnFrameCount]; 92 | } 93 | 94 | self.meterLabel.text = [NSString stringWithFormat:@"%@ %@", droppedString, drawnString]; 95 | } 96 | 97 | - (CFTimeInterval)hardwareFrameDuration 98 | { 99 | return 1.0 / self.hardwareFramesPerSecond; 100 | } 101 | 102 | - (void)displayLinkWillDraw:(CADisplayLink *)displayLink 103 | { 104 | CFTimeInterval currentFrameTime = displayLink.timestamp; 105 | CFTimeInterval frameDuration = currentFrameTime - [self lastFrameTime]; 106 | 107 | // Frames should be even multiples of hardwareFrameDuration. 108 | // If a frame takes two frame durations, we dropped at least one, so click. 109 | if (1.5 < frameDuration / [self hardwareFrameDuration]) { 110 | AudioServicesPlaySystemSound(self.tickSoundID); 111 | } 112 | 113 | [self recordFrameTime:currentFrameTime]; 114 | 115 | [self updateMeterLabel]; 116 | } 117 | 118 | #pragma mark - 119 | 120 | - (void)start 121 | { 122 | NSURL *tickSoundURL = [[NSBundle bundleForClass:KMCGeigerCounter.class] URLForResource:@"KMCGeigerCounterTick" withExtension:@"aiff"]; 123 | SystemSoundID tickSoundID; 124 | AudioServicesCreateSystemSoundID((__bridge CFURLRef) tickSoundURL, &tickSoundID); 125 | self.tickSoundID = tickSoundID; 126 | 127 | self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayLinkWillDraw:)]; 128 | [self.displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes]; 129 | [self clearLastSecondOfFrameTimes]; 130 | } 131 | 132 | - (void)stop 133 | { 134 | [self.displayLink invalidate]; 135 | self.displayLink = nil; 136 | 137 | AudioServicesDisposeSystemSoundID(self.tickSoundID); 138 | self.tickSoundID = 0; 139 | } 140 | 141 | - (void)setRunning:(BOOL)running 142 | { 143 | if (_running != running) { 144 | if (running) { 145 | [self start]; 146 | } else { 147 | [self stop]; 148 | } 149 | 150 | _running = running; 151 | } 152 | } 153 | 154 | #pragma mark - 155 | 156 | - (void)applicationDidBecomeActive 157 | { 158 | self.running = self.enabled; 159 | } 160 | 161 | - (void)applicationWillResignActive 162 | { 163 | self.running = NO; 164 | } 165 | 166 | #pragma mark - 167 | 168 | - (void)enable 169 | { 170 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 171 | self.window.rootViewController = [[UIViewController alloc] init]; 172 | self.window.windowLevel = self.windowLevel; 173 | self.window.userInteractionEnabled = NO; 174 | 175 | CGFloat const kMeterWidth = 105.0; 176 | CGFloat xOrigin = 0.0; 177 | UIViewAutoresizing autoresizingMask = UIViewAutoresizingFlexibleBottomMargin; 178 | switch (self.position) { 179 | case KMCGeigerCounterPositionLeft: 180 | xOrigin = 0.0; 181 | autoresizingMask |= UIViewAutoresizingFlexibleRightMargin; 182 | break; 183 | case KMCGeigerCounterPositionMiddle: 184 | xOrigin = (CGRectGetWidth(self.window.bounds) - kMeterWidth) / 2.0; 185 | autoresizingMask |= UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleLeftMargin; 186 | break; 187 | case KMCGeigerCounterPositionRight: 188 | xOrigin = (CGRectGetWidth(self.window.bounds) - kMeterWidth); 189 | autoresizingMask |= UIViewAutoresizingFlexibleLeftMargin; 190 | break; 191 | } 192 | 193 | CGFloat meterHeight = 20; 194 | self.meterLabel = [[UILabel alloc] initWithFrame:CGRectMake(xOrigin, isXDevice ? 35.0 : 5.0, 195 | kMeterWidth, meterHeight)]; 196 | self.meterLabel.autoresizingMask = autoresizingMask; 197 | self.meterLabel.font = [UIFont boldSystemFontOfSize:12.0]; 198 | self.meterLabel.backgroundColor = [UIColor grayColor]; 199 | self.meterLabel.textColor = [UIColor whiteColor]; 200 | self.meterLabel.textAlignment = NSTextAlignmentCenter; 201 | [self.window.rootViewController.view addSubview:self.meterLabel]; 202 | 203 | self.window.hidden = NO; 204 | 205 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidBecomeActive) name:UIApplicationDidBecomeActiveNotification object:nil]; 206 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillResignActive) name:UIApplicationWillResignActiveNotification object:nil]; 207 | 208 | if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive) { 209 | self.running = YES; 210 | } 211 | } 212 | 213 | - (void)disable 214 | { 215 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 216 | 217 | self.running = NO; 218 | 219 | self.meterLabel = nil; 220 | self.window = nil; 221 | } 222 | 223 | #pragma mark - Init/dealloc 224 | 225 | - (instancetype)init 226 | { 227 | self = [super init]; 228 | if (self) { 229 | _windowLevel = UIWindowLevelStatusBar + 10.0; 230 | _position = KMCGeigerCounterPositionLeft; 231 | 232 | _meterPerfectColor = [KMCGeigerCounter colorWithHex:0x999999 alpha:1.0]; 233 | _meterGoodColor = [KMCGeigerCounter colorWithHex:0x66a300 alpha:1.0]; 234 | _meterBadColor = [KMCGeigerCounter colorWithHex:0xff7f0d alpha:1.0]; 235 | 236 | if (@available(iOS 10.3, *)) { 237 | _hardwareFramesPerSecond = [UIScreen mainScreen].maximumFramesPerSecond; 238 | } else { 239 | _hardwareFramesPerSecond = 60; 240 | } 241 | 242 | _recentFrameTimes = malloc(sizeof(*_recentFrameTimes) * _hardwareFramesPerSecond); 243 | } 244 | return self; 245 | } 246 | 247 | - (void)dealloc 248 | { 249 | [_displayLink invalidate]; 250 | 251 | if (_tickSoundID) { 252 | AudioServicesDisposeSystemSoundID(_tickSoundID); 253 | } 254 | 255 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 256 | 257 | if (_recentFrameTimes) { 258 | free(_recentFrameTimes); 259 | _recentFrameTimes = nil; 260 | } 261 | } 262 | 263 | #pragma mark - Public interface 264 | 265 | + (instancetype)sharedGeigerCounter 266 | { 267 | static KMCGeigerCounter *instance; 268 | static dispatch_once_t onceToken; 269 | dispatch_once(&onceToken, ^{ 270 | instance = [[KMCGeigerCounter alloc] init]; 271 | }); 272 | return instance; 273 | } 274 | 275 | - (void)setEnabled:(BOOL)enabled 276 | { 277 | if (_enabled != enabled) { 278 | if (enabled) { 279 | [self enable]; 280 | } else { 281 | [self disable]; 282 | } 283 | 284 | _enabled = enabled; 285 | } 286 | } 287 | 288 | - (void)setWindowLevel:(UIWindowLevel)windowLevel 289 | { 290 | _windowLevel = windowLevel; 291 | self.window.windowLevel = windowLevel; 292 | } 293 | 294 | - (NSInteger)droppedFrameCountInLastSecond 295 | { 296 | NSInteger droppedFrameCount = 0; 297 | 298 | CFTimeInterval lastFrameTime = CACurrentMediaTime() - [self hardwareFrameDuration]; 299 | for (NSInteger i = 0; i < self.hardwareFramesPerSecond; ++i) { 300 | if (1.0 <= lastFrameTime - _recentFrameTimes[i]) { 301 | ++droppedFrameCount; 302 | } 303 | } 304 | 305 | return droppedFrameCount; 306 | } 307 | 308 | - (NSInteger)drawnFrameCountInLastSecond 309 | { 310 | if (!self.running || self.frameNumber < self.hardwareFramesPerSecond) { 311 | return -1; 312 | } 313 | 314 | return self.hardwareFramesPerSecond - self.droppedFrameCountInLastSecond; 315 | } 316 | 317 | @end 318 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /CDDGroupAvatar/AvatarConfig/DCAvatarHelper.m: -------------------------------------------------------------------------------- 1 | // 2 | // DCAvatarHelper.m 3 | // DCAvatarHelper 4 | // 5 | // Created by 陈甸甸 on 2019/7/18. 6 | // Copyright © 2019 RocketsChen. All rights reserved. 7 | // 8 | 9 | #import "DCAvatarHelper.h" 10 | 11 | #import 12 | 13 | @implementation DCAvatarHelper 14 | 15 | + (CGSize)dc_calculateSizeQQAvatarGroupCount:(NSInteger)groupCount index:(NSInteger)index containerSize:(CGSize)containerSize distanceBetweenAvatar:(CGFloat)distance 16 | { 17 | CGSize wholeSize = containerSize; 18 | CGSize avatarSize = CGSizeZero; 19 | 20 | if (groupCount == DCNumberOfGroupAvatarOne) { 21 | 22 | avatarSize = wholeSize; 23 | 24 | }else if (groupCount == DCNumberOfGroupAvatarTwo) { 25 | 26 | avatarSize = CGSizeMake((wholeSize.width - distance) / 2, wholeSize.height); 27 | 28 | }else if (groupCount == DCNumberOfGroupAvatarThree && index == 0){ 29 | 30 | avatarSize = CGSizeMake((wholeSize.width - distance) / 2, wholeSize.height); 31 | 32 | }else{ 33 | avatarSize = CGSizeMake((wholeSize.width - distance) / 2, (wholeSize.height - distance) / 2); 34 | } 35 | 36 | return avatarSize; 37 | } 38 | 39 | 40 | 41 | + (CGSize)dc_calculateSizeWeChatAvatarGroupCount:(NSInteger)groupCount containerSize:(CGSize)containerSize distanceBetweenAvatar:(CGFloat)distance 42 | { 43 | CGSize wholeSize = containerSize; 44 | CGSize avatarSize = CGSizeZero; 45 | 46 | if (groupCount < DCNumberOfGroupAvatarFive) { 47 | avatarSize = CGSizeMake((wholeSize.width - (3 * distance)) / 2, (wholeSize.height - (3 * distance)) / 2); 48 | }else{ 49 | avatarSize = CGSizeMake((wholeSize.width - (4 * distance)) / 3, (wholeSize.height - (4 * distance)) / 3); 50 | } 51 | return avatarSize; 52 | } 53 | 54 | 55 | + (CGFloat)dc_calculateRadiusWeiBoAvatarGroupCount:(NSInteger)groupCount containerSize:(CGSize)containerSize distanceBetweenAvatar:(CGFloat)distance 56 | { 57 | CGFloat bigRadius = containerSize.width / 2; 58 | CGFloat radius = 0; 59 | switch (groupCount) { 60 | 61 | case DCNumberOfGroupAvatarOne: 62 | 63 | radius = bigRadius; 64 | break; 65 | 66 | case DCNumberOfGroupAvatarTwo: 67 | 68 | radius = bigRadius / 2 + (distance / 2); 69 | break; 70 | 71 | case DCNumberOfGroupAvatarThree: 72 | 73 | radius = (2 * sqrt(3) - 3) * bigRadius + (distance / 3); 74 | break; 75 | 76 | case DCNumberOfGroupAvatarFour: 77 | 78 | radius = bigRadius / 2 - (distance / 2); 79 | break; 80 | 81 | default: 82 | break; 83 | } 84 | 85 | return radius; 86 | } 87 | 88 | 89 | + (CGPoint)dc_calculateWeiBoAvatarGroupCount:(NSInteger)groupCount index:(NSInteger)index containerSize:(CGSize)containerSize distanceBetweenAvatar:(CGFloat)distance 90 | { 91 | CGPoint avatarPoint = CGPointZero; 92 | 93 | CGFloat avatarDiameter = [self dc_calculateRadiusWeiBoAvatarGroupCount:groupCount containerSize:containerSize distanceBetweenAvatar:distance]; 94 | CGFloat bigRadius = containerSize.width / 2 ; 95 | 96 | CGFloat radiusOffset; 97 | CGFloat shrinkage = (groupCount == DCNumberOfGroupAvatarFour) ? distance : - 2 * distance ; // 收缩属性 98 | 99 | if (groupCount == DCNumberOfGroupAvatarOne) { 100 | 101 | avatarPoint = CGPointMake(containerSize.width * 0.5, containerSize.height * 0.5); 102 | 103 | } else if (groupCount == DCNumberOfGroupAvatarThree) { 104 | 105 | CGFloat difference = (bigRadius - avatarDiameter); 106 | 107 | if (index == 1) { 108 | 109 | avatarDiameter -= shrinkage; 110 | avatarPoint = CGPointMake(bigRadius, avatarDiameter + distance); 111 | 112 | }else{ 113 | 114 | avatarDiameter += shrinkage; 115 | radiusOffset = index * -.5 * M_PI; 116 | CGFloat pX = avatarDiameter * cosf(radiusOffset); 117 | avatarPoint = CGPointMake(bigRadius + pX, bigRadius + (difference / 2) + distance); 118 | } 119 | 120 | }else{ 121 | 122 | avatarDiameter += shrinkage; 123 | 124 | radiusOffset = -.75 * M_PI; 125 | 126 | CGFloat pX = avatarDiameter * cosf(2 * M_PI * index / groupCount + radiusOffset); 127 | CGFloat pY = avatarDiameter * sinf(2 * M_PI * index / groupCount + radiusOffset); 128 | 129 | avatarPoint = CGPointMake(bigRadius + pX, bigRadius + pY); 130 | 131 | } 132 | return avatarPoint; 133 | } 134 | 135 | 136 | 137 | + (CGPoint)dc_calculatePointAvatarGroupCount:(NSInteger)groupCount index:(NSInteger)index containerSize:(CGSize)containerSize distanceBetweenAvatar:(CGFloat)distance avatarType:(DCGroupAvatarType)groupAvatarType 138 | { 139 | CGPoint avatarPoint = CGPointZero; 140 | NSInteger currentIndex = index; 141 | CGSize avatarSize = (groupAvatarType == DCGroupAvatarWeChatType) ? [self dc_calculateSizeWeChatAvatarGroupCount:groupCount containerSize:containerSize distanceBetweenAvatar:distance] : [self dc_calculateSizeQQAvatarGroupCount:groupCount index:index containerSize:containerSize distanceBetweenAvatar:distance]; 142 | CGFloat avaWidth = avatarSize.width; 143 | CGFloat avaHeight = avatarSize.height; 144 | CGFloat row , column; 145 | 146 | switch (groupCount) { 147 | 148 | case DCNumberOfGroupAvatarOne: 149 | 150 | if (groupAvatarType == DCGroupAvatarWeChatType) { 151 | 152 | avatarPoint = CGPointMake((containerSize.width - avaWidth) * 0.5, (containerSize.height - avaHeight) * 0.5); 153 | } 154 | break; 155 | 156 | case DCNumberOfGroupAvatarTwo: 157 | if (groupAvatarType == DCGroupAvatarWeChatType) { // 微信 158 | 159 | avatarPoint = CGPointMake(currentIndex * (avaWidth + distance) + distance, (containerSize.height - avaHeight) / 2); 160 | 161 | }else if (groupAvatarType == DCGroupAvatarQQType){ // QQ 162 | 163 | avatarPoint = CGPointMake(currentIndex * (avaWidth + distance), 0); 164 | } 165 | break; 166 | case DCNumberOfGroupAvatarThree: 167 | 168 | if (groupAvatarType == DCGroupAvatarWeChatType) { 169 | 170 | if (currentIndex == 0) { 171 | avatarPoint = CGPointMake((containerSize.width - avaWidth) / 2, distance); 172 | }else{ 173 | 174 | avatarPoint = CGPointMake((currentIndex - 1) * (avaWidth + distance) + distance, avaHeight + 2 * distance); 175 | } 176 | }else if (groupAvatarType == DCGroupAvatarQQType){ 177 | 178 | if (currentIndex == 0) { 179 | 180 | avatarPoint = CGPointMake(0, 0); 181 | 182 | }else{ 183 | if (currentIndex == 2) { 184 | ++currentIndex; 185 | } 186 | column = currentIndex / 2; 187 | avatarPoint = CGPointMake(avaWidth + distance, column * (avaHeight + distance)); 188 | } 189 | } 190 | break; 191 | case DCNumberOfGroupAvatarFour: 192 | 193 | row = currentIndex % 2; 194 | column = currentIndex / 2; 195 | 196 | if (groupAvatarType == DCGroupAvatarWeChatType) { 197 | 198 | avatarPoint = CGPointMake(row * (avaWidth + distance) + distance, column * (avaHeight + distance) + distance); 199 | 200 | }else if (groupAvatarType == DCGroupAvatarQQType){ 201 | 202 | avatarPoint = CGPointMake(row * (avaWidth + distance), column * (avaHeight + distance)); 203 | } 204 | break; 205 | case DCNumberOfGroupAvatarFive: 206 | 207 | if (groupAvatarType == DCGroupAvatarWeChatType) { 208 | 209 | CGPoint tempPoint = CGPointMake((containerSize.width - distance - (2 * avaWidth)) / 2, (containerSize.height - distance - (2 * avaHeight)) / 2); 210 | if (currentIndex <= 1) { 211 | avatarPoint = CGPointMake(currentIndex * (distance + avaWidth) + tempPoint.x , tempPoint.y); 212 | }else{ 213 | avatarPoint = CGPointMake((currentIndex - 2) * (avaWidth + distance) + distance, tempPoint.y + avaHeight + distance); 214 | } 215 | } 216 | break; 217 | case DCNumberOfGroupAvatarSix: 218 | 219 | 220 | if (groupAvatarType == DCGroupAvatarWeChatType) { 221 | 222 | CGFloat tempPointY = (containerSize.height - distance - (2 * avaHeight)) / 2; 223 | 224 | row = currentIndex % DCMaxWeChatColumn; 225 | column = currentIndex / DCMaxWeChatColumn; 226 | avatarPoint = CGPointMake(row * (avaWidth + distance) + distance, column * (avaHeight + distance) + tempPointY); 227 | } 228 | break; 229 | case DCNumberOfGroupAvatarSeven: 230 | 231 | 232 | if (groupAvatarType == DCGroupAvatarWeChatType) { 233 | 234 | if (currentIndex == 0) { 235 | avatarPoint = CGPointMake((containerSize.width - avaWidth) / 2, distance); 236 | 237 | }else{ 238 | row = (currentIndex + 2) % DCMaxWeChatColumn; 239 | column = (currentIndex + 2) / DCMaxWeChatColumn; 240 | avatarPoint = CGPointMake(row * (avaWidth + distance) + distance, column * (avaHeight + distance) + distance); 241 | } 242 | } 243 | break; 244 | case DCNumberOfGroupAvatarEight: 245 | 246 | if (groupAvatarType == DCGroupAvatarWeChatType) { 247 | 248 | if (currentIndex < 2) { 249 | 250 | CGFloat tempPointX = (containerSize.width - 2 * avaWidth - distance) / 2; 251 | avatarPoint = CGPointMake(currentIndex * (avaWidth + distance) + tempPointX, distance); 252 | 253 | }else{ 254 | 255 | row = (currentIndex + 1) % DCMaxWeChatColumn; 256 | column = (currentIndex + 1) / DCMaxWeChatColumn; 257 | avatarPoint = CGPointMake(row * (avaWidth + distance) + distance, column * (avaHeight + distance) + distance); 258 | } 259 | } 260 | break; 261 | case DCNumberOfGroupAvatarNine: 262 | 263 | if (groupAvatarType == DCGroupAvatarWeChatType) { 264 | 265 | row = currentIndex % DCMaxWeChatColumn; 266 | column = currentIndex / DCMaxWeChatColumn; 267 | 268 | avatarPoint = CGPointMake(row * (avaWidth + distance) + distance, column * (avaHeight + distance) + distance); 269 | 270 | } 271 | break; 272 | default: 273 | break; 274 | } 275 | 276 | return avatarPoint; 277 | } 278 | 279 | 280 | 281 | 282 | 283 | + (NSArray *)dc_getTypefMaxCount:(NSArray *)groupSource avatarType:(DCGroupAvatarType)groupAvatarType 284 | { 285 | if (groupAvatarType == DCGroupAvatarWeChatType) { 286 | return [groupSource subarrayWithRange:NSMakeRange(0, MIN(groupSource.count, DCMaxWeChatCount))]; 287 | }else if (groupAvatarType == DCGroupAvatarQQType){ 288 | return [groupSource subarrayWithRange:NSMakeRange(0, MIN(groupSource.count, DCMaxQQCount))]; 289 | }else if (groupAvatarType == DCGroupAvatarWeiBoType){ 290 | return [groupSource subarrayWithRange:NSMakeRange(0, MIN(groupSource.count, DCMaxWeiBoCount))]; 291 | } 292 | return [NSArray array]; 293 | } 294 | 295 | 296 | + (NSString *)dc_cacheMd5:(NSString *)key{ 297 | const char *str = key.UTF8String; 298 | if (str == NULL) { 299 | str = ""; 300 | } 301 | unsigned char outputBuffer[CC_MD5_DIGEST_LENGTH]; 302 | CC_MD5(str, (CC_LONG)strlen(str), outputBuffer); 303 | NSMutableString *outputString = [[NSMutableString alloc] initWithCapacity:CC_MD5_DIGEST_LENGTH * 2]; 304 | for(NSInteger count = 0; count < CC_MD5_DIGEST_LENGTH; count++){ 305 | [outputString appendFormat:@"%02x", outputBuffer[count]]; 306 | } 307 | return outputString; 308 | } 309 | 310 | 311 | + (NSString *)dc_hexColor:(UIColor *)color { 312 | 313 | CGFloat red, green, blue, alpha; 314 | 315 | if (![color getRed:&red green:&green blue:&blue alpha:&alpha]) { 316 | [color getWhite:&red alpha:&alpha]; 317 | green = red; 318 | blue = red; 319 | } 320 | red = roundf(red * 255.f); 321 | green = roundf(green * 255.f); 322 | blue = roundf(blue * 255.f); 323 | alpha = roundf(alpha * 255.f); 324 | 325 | uint hex = ((uint)alpha << 24) | ((uint)red << 16) | ((uint)green << 8) | ((uint)blue); 326 | return [NSString stringWithFormat:@"#%08x", hex]; 327 | } 328 | 329 | 330 | + (BOOL)dc_getCGImageRefContainsAlpha:(CGImageRef)imageRef{ 331 | if (!imageRef) return NO; 332 | CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(imageRef); 333 | BOOL hasAlpha = !(alphaInfo == kCGImageAlphaNone || 334 | alphaInfo == kCGImageAlphaNoneSkipFirst || 335 | alphaInfo == kCGImageAlphaNoneSkipLast); 336 | return hasAlpha; 337 | } 338 | 339 | @end 340 | --------------------------------------------------------------------------------