             storage.removeAllObjects()
             keys.removeAll()
         }
-
-        class CacheDelegate<T>: NSObject, NSCacheDelegate {
-            let onObjectRemoved = Delegate<T, Void>()
-            func cache(_ cache: NSCache<AnyObject, AnyObject>, willEvictObject obj: Any) {
-                if let obj = obj as? T {
-                    onObjectRemoved.call(obj)
-                }
-            }
-        }
     }
 }
 

            for key in keys {
                let nsKey = key as NSString
                guard let object = storage.object(forKey: nsKey) else {
                    keys.remove(key)
                    continue
                }

    /// items from memory.
    public class Backend<T: CacheCostCalculable> {
        let storage = NSCache<NSString, StorageObject<T>>()

        // Keys trackes the objects once inside the storage. For object removing triggered by user, the corresponding
        // key would be also removed. However, for the object removing triggered by cache rule/policy of system, the
        // key will be remained there until next `removeExpired` happens.
        //
        // Breaking the strict tracking could save additional locking behaviors.
        // See https://github.com/onevcat/Kingfisher/issues/1233
        var keys = Set<String>()

        private var cleanTimer: Timer? = nil
        private let lock = NSLock()

        /// The config used in this storage. It is a value you can set and
        /// use to config the storage in air.
