{"id":25082218,"url":"https://github.com/niksativa/smartimages","last_synced_at":"2025-04-15T08:16:16.539Z","repository":{"id":39404791,"uuid":"450015413","full_name":"NikSativa/SmartImages","owner":"NikSativa","description":"Simple and lightweight library for loading images in a fast way","archived":false,"fork":false,"pushed_at":"2025-01-30T10:39:04.000Z","size":301,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-15T08:16:06.617Z","etag":null,"topics":["animation","cache","decoding","ios","placegolder","swift","uiimage","uiimageview"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/NikSativa.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-01-20T08:32:55.000Z","updated_at":"2025-01-30T10:38:55.000Z","dependencies_parsed_at":"2023-01-31T09:30:39.911Z","dependency_job_id":"3392aa83-7f6e-48f3-b4b6-cf8737b953ed","html_url":"https://github.com/NikSativa/SmartImages","commit_stats":null,"previous_names":[],"tags_count":27,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NikSativa%2FSmartImages","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NikSativa%2FSmartImages/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NikSativa%2FSmartImages/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NikSativa%2FSmartImages/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/NikSativa","download_url":"https://codeload.github.com/NikSativa/SmartImages/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249031814,"owners_count":21201357,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["animation","cache","decoding","ios","placegolder","swift","uiimage","uiimageview"],"created_at":"2025-02-07T05:29:08.242Z","updated_at":"2025-04-15T08:16:16.519Z","avatar_url":"https://github.com/NikSativa.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SmartImages\n[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2FNikSativa%2FSmartImages%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/NikSativa/SmartImages)\n[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2FNikSativa%2FSmartImages%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/NikSativa/SmartImages)\n[![CI](https://github.com/NikSativa/SmartImages/actions/workflows/swift_macos.yml/badge.svg)](https://github.com/NikSativa/SmartImages/actions/workflows/swift_macos.yml)\n\nSimple and lightweight library for loading images in a fast way, because it prioritizes queuing and loading images in the order they are requested and/or if ImageView is waiting for an image to be loaded, it will be prioritized over the others. \nIt uses the native Image object to load images and provides a way to cache them in memory and you can also set a custom cache size.\n\n### ImageDownloader\nManager responsible for downloading images from the internet.\n\n### ImageCache\nManager responsible for caching images in memory. \nBy default: \n- memory capacity is **40MB** and minimum capacity is **10MB**\n- disk capacity is **400MB** and minimum capacity is **10MB**\n\n### ImageDownloadQueue\nManager responsible for queuing images to be downloaded and prioritizing the images that are being requested.\nThe priority changes at runtime, so it is calculated before adding to the download queue. The highest priority occurs when the image URL is attached to a UI view (SwiftUI is also supported) and has a queued timestamp that is much closer to the current time.\n\nExample:\n- You have a queue with a limit of 2 tasks at a time. \n- You add 5 tasks with low priority:\n\n```swift\nfor i in 0..\u003c5 {\n    imageDownloader.prefetch(url: URL(string: \"apple.com/image_\\(i)\")!)\n}\n```\n\n- `ImageDownloader` is starting download first 2 images immediately.\n- You add 2 tasks which are attached to UI-view\n\n```swift\nlet imageView = UIImageView()\nimageView.setImage(withURL: URL(string: \"apple.com/image\\_\\\\(99)\")!) // new URL\nimageView.setImage(withURL: URL(string: \"apple.com/image\\_\\\\(3)\")!)  // \u003c-- the same URL in queue\n```\n\n- `ImageDownloader` did download 1 image and free 1 space in queue. \n- The state is:\n    - \"image\\_1 - downloaded\n    - \"image\\_2\" - in progress\n    - \"image\\_3\"\n    - \"image\\_4\"\n    - \"image\\_5\"\n    - \"image\\_3\" with View\n    - \"image\\_99\" with View \n\n- Prioritization algorithm will do:\n    - \"image\\_3\" with View and added after \"99\" - that means timestamp is more close to \"now\" *(\"now\" - \"99\".timestamp \u003e \"now\" - \"3\".timestamp)*\n    - \"image\\_99\" with View\n    - ~~\"image\\_1\"~~ - downloaded, no longer needed\n    - \"image\\_2\" - in progress\n    - ~~\"image\\_3\"~~ the same URL as already added \"with View\"\n    - \"image\\_4\"\n    - \"image\\_5\"\n\n- Next task will take **\"image\\_3\" with View** because it is attached to View and that means the User is Waiting this image on his screen.\n\n### ImageDownloaderNetwork\nProtocol that must be implemented by the app and represents the network layer.\n\n## How to use\n\nExample anywhere in the application:\n```swift\nplaneImageView.setImage(withURL: url, placeholder: .image(.planePlaceholder))\nplaneImageView.setImage(withURL: url, placeholder: .clear)\nplaneImageView.setImage(withURL: url)\n```\n\n`UIImageView` extension for easy use:\n```swift\n// extend UIImageView for loading images\npublic extension UIImageView {\n    func setImage(withURL url: URL,\n                  animated animation: ImageAnimation? = nil,\n                  placeholder: ImagePlaceholder = .none,\n                  completion: ImageClosure? = nil) {\n        let info = ImageInfo(url: url)\n        ImageDownloader.shared.download(of: info,\n                                        for: self,\n                                        animated: animation,\n                                        placeholder: placeholder,\n                                        completion: completion ?? { _ in })\n    }\n\n    func cancelImageRequest() {\n        ImageDownloader.shared.cancel(for: self)\n    }\n}\n\n// MARK: - ImageDownloader + ImageDownloading\n\nextension ImageDownloader: ImageDownloading {\n    public var imageCache: ImageCaching? {\n        return Self.shared.imageCache\n    }\n\n    public func prefetch(of info: ImageInfo,\n                         completion: @escaping ImageClosure) {\n        Self.shared.prefetch(of: info, completion: completion)\n    }\n\n    public func prefetching(of info: SmartImages.ImageInfo, completion: @escaping SmartImages.ImageClosure) -\u003e AnyCancellable {\n        return Self.shared.prefetching(of: info, completion: completion)\n    }\n\n    public func download(of info: ImageInfo,\n                         completion: @escaping ImageClosure) -\u003e AnyCancellable {\n        Self.shared.download(of: info,\n                             completion: completion)\n    }\n\n    public func download(of info: ImageInfo,\n                         for imageView: ImageView,\n                         animated animation: ImageAnimation?,\n                         placeholder: ImagePlaceholder = .none,\n                         completion: @escaping ImageClosure) {\n        Self.shared.download(of: info,\n                             for: imageView,\n                             animated: animation,\n                             placeholder: placeholder,\n                             completion: completion)\n    }\n\n    public func cancel(for imageView: ImageView) {\n        Self.shared.cancel(for: imageView)\n    }\n}\n```\n\n### How to use with SmartNetwork\n\n```swift\nimport Combine\nimport Foundation\nimport SmartImages\nimport SmartNetwork\nimport UIKit\n\npublic typealias ImageAnimation = SmartImages.ImageAnimation\npublic typealias ImageClosure = SmartImages.ImageClosure\npublic typealias ImageInfo = SmartImages.ImageInfo\npublic typealias ImagePlaceholder = SmartImages.ImagePlaceholder\n\npublic struct ImageDownloader {\n    private static let manager: RequestManagering = RequestManager.create() // \u003c---- this is the place of your custom plugins, StopTheLine etc.\n\n    public static let shared: ImageDownloading = {\n        return SmartImages.ImageDownloader(network: ImageDownloaderNetworkAdaptor(manager: manager),\n                                           cache: .init(folderName: \"DownloadedImages\"),\n                                           concurrentLimit: 8)\n    }()\n\n    private init() {}\n}\n\nextension RequestingTask: @retroactive ImageDownloaderTask {}\n\nprivate struct ImageDownloaderNetworkAdaptor: ImageDownloaderNetwork {\n    let manager: RequestManagering\n\n    func request(with url: URL,\n                 cachePolicy: URLRequest.CachePolicy?,\n                 timeoutInterval: TimeInterval?,\n                 completion: @escaping ResultCompletion,\n                 finishedOrCancelled finished: FinishedCompletion?) -\u003e ImageDownloaderTask {\n        return manager.data.request(address: .init(url),\n                                    with: .init(requestPolicy: cachePolicy ?? .useProtocolCachePolicy,\n                                                timeoutInterval: timeoutInterval ?? RequestSettings.timeoutInterval),\n                                    inQueue: .absent,\n                                    completion: completion)\n    }\n}\n```\n\n### How to use with URLSession\n\n```swift\nimport Foundation\nimport SmartImages\nimport UIKit\n\npublic enum ImageDownloader {\n    private static let imageDownloader: ImageDownloading = {\n        return SmartImages.ImageDownloader.create(network: ImageDownloaderNetworkAdaptor(),\n                                                  cache: .init(folderName: \"DownloadedImages\"),\n                                                  concurrentImagesLimit: 8)\n    }()\n\n    public init() {}\n}\n\nprivate struct ImageDownloaderTaskAdaptor: ImageDownloaderTask {\n    let task: URLSessionTask\n\n    func start() {\n        task.resume()\n    }\n\n    func cancel() {\n        task.cancel()\n    }\n}\n\nprivate struct ImageDownloaderNetworkAdaptor: ImageDownloaderNetwork {\n    private let session: URLSession = .shared\n\n    func request(with url: URL,\n                 cachePolicy: URLRequest.CachePolicy,\n                 timeoutInterval: TimeInterval,\n                 completion: @escaping (Result\u003cData, Error\u003e) -\u003e Void) -\u003e ImageDownloaderTask {\n        let dataTask = session.dataTask(with: url) { data, _, error in\n            if let error {\n                completion(.failure(error))\n            } else if let data {\n                completion(.success(data))\n            } else {\n                completion(.failure(NSError(domain: \"ImageDownloader\", code: 0, userInfo: [\"url\": url])))\n            }\n        }\n\n        return ImageDownloaderTaskAdaptor(task: dataTask)\n    }\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fniksativa%2Fsmartimages","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fniksativa%2Fsmartimages","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fniksativa%2Fsmartimages/lists"}