• One day saw the technology group passed a zhihu on how to interview iOS engineers? Please design a simple image memory cache (remove strategy must be mentioned). ZBNetworking (ZBNetworking) The advantages of ZBNetworking mentioned in the previous article are: 1. Low coupling and easy to expand. Maybe some friends don’t take it seriously. ZBNetworking ZBCacheManager class to create a picture cache, but I think the question is how to design a simple picture cache. And it’s actually pretty easy to add memory to it with NSCache and just add a few ifs to the memory. But ZBNetworking was designed with disk storage in mind. I’d rather not change.

  • There are many excellent third-party frameworks SDWebImage,YYWebImage and so on in the application we develop and maintain for image request. But somewhere in the corner you’ll often see the following code, a system’s own image request method. To make a simple image cache, let’s use a simple one. If we add a cache to such code, then is not very 👍

        NSURL *url=[NSURL URLWithString:imageUrl];
        NSData *data=[NSData dataWithContentsOfURL:url];
        UIImage *image=[UIImage imageWithData:data];
Copy the code

So let’s write a method

- (void)requestImageUrl:(NSString *)imageUrl completion:(downloadCompletion)completion{
    if(! imageUrl)return;
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
       
        NSURL *url=[NSURL URLWithString:imageUrl];
        
        NSData *data=[NSData dataWithContentsOfURL:url];
        
        UIImage *image=[UIImage imageWithData:data];
        
        dispatch_async(dispatch_get_main_queue(), ^{
            completion(image);
        });
    });
}

Copy the code

An image request in the child thread, followed by a block callback that returns a UIimage completed by the request. The following uses ZBCacheManager for storage

  [self requestImageUrl:imageUrl completion:^(UIImage *image){ 
       [[ZBCacheManager sharedInstance]storeContent:image forKey:imageUrl path:path];
   }];
Copy the code

The code is very simple and when we’re done with the request and we store the returned UIimage to the specified path (we create the path ahead of time),

- (void)downloadImageUrl:(NSString *)imageUrl path:(NSString *)path completion:(downloadCompletion)completion{
    
    if ([[ZBCacheManager sharedInstance]diskCacheExistsWithKey:imageUrl path:path]) {
        
        [[ZBCacheManager sharedInstance]getCacheDataForKey:imageUrl path:path value:^(NSData *data,NSString *filePath) {
            
            UIImage *image=[UIImage imageWithData:data];
            
            completion(image) ;
        }];
        
    }else{
        [self requestImageUrl:imageUrl completion:^(UIImage *image){
            
            [[ZBCacheManager sharedInstance]storeContent:image forKey:imageUrl path:path]; completion(image); }]; }}Copy the code

ZBNetworking is the same as ZBNetworking. If there is a cache, return it to the cache. If there is no cache, request it and store it. Here are the methods for different types

- (void)downloadImageUrl:(NSString *)imageUrl{
    [self downloadImageUrl:imageUrl completion:nil];
}

- (void)downloadImageUrl:(NSString *)imageUrl completion:(downloadCompletion)completion{
    [self downloadImageUrl:imageUrl path:[self imageFilePath] completion:completion];
}

- (void)downloadImageUrl:(NSString *)imageUrl path:(NSString *)path{
    [self downloadImageUrl:imageUrl path:path completion:nil];
}

- (void)downloadImageUrl:(NSString *)imageUrl path:(NSString *)path completion:(downloadCompletion)completion{
    
    if ([[ZBCacheManager sharedInstance]diskCacheExistsWithKey:imageUrl path:path]) {
        
        [[ZBCacheManager sharedInstance]getCacheDataForKey:imageUrl path:path value:^(NSData *data,NSString *filePath) {
            
            UIImage *image=[UIImage imageWithData:data];
            
            completion(image) ;
        }];
        
    }else{
        [self requestImageUrl:imageUrl completion:^(UIImage *image){
            
            [[ZBCacheManager sharedInstance]storeContent:image forKey:imageUrl path:path]; completion(image); }]; }} / / the default cache store path path/Library/Caches/ZBKit/AppImage - (nsstrings *) imageFilePath {nsstrings * AppImagePath = [[[ZBCacheManager  sharedInstance]ZBKitPath]stringByAppendingPathComponent:ImageDefaultPath];return AppImagePath;
}
Copy the code

Maybe it’s a personal habit, always like to customize the path. So in addition to saving to the default path, you can also save to the path you want.

Below is the operation that shows the cache size/number and deletes the cache

// Size - (NSUInteger)imageFileSize{return[[ZBCacheManager sharedInstance]getFileSizeWithpath:[self imageFilePath]]; } // Quantity - (NSUInteger)imageFileCount{return[[ZBCacheManager sharedInstance]getFileCountWithpath:[self imageFilePath]]; } / / clear picture - (void) clearImageFile {[self clearImageFileCompletion: nil]; } / / clear image cache Have block callback - (void) clearImageFileCompletion: (ZBCacheCompletedBlock) completion {[[ZBCacheManager sharedInstance]clearDiskWithpath:[self imageFilePath] completion:completion]; } // Clear an image - (void)clearImageForkey:(NSString *)key{[self clearImageForkey:key completion:nil]; } // clear an image cache with a block callback - (void)clearImageForkey:(NSString *)key completion:(ZBCacheCompletedBlock)completion{ [[ZBCacheManager sharedInstance]clearCacheForkey:key path:[self imageFilePath] completion:completion]; }Copy the code

When you use it, it’s easy to understand

self.imageView=[[UIImageView alloc]initWithFrame:CGRectMake(0, 64, SCREEN_WIDTH, 240)]; [self.view addSubview:self.imageView]; / / download images [[ZBWebImageManager sharedInstance] downloadImageUrl: imageUrl completion: ^ (UIImage * image) { self.imageView.image=image; }];Copy the code
  • Make UIImageView category. Go to the code
- (void)zb_setImageWithURL:(NSString *)urlString{
    [self zb_setImageWithURL:urlString completion:nil];
}

- (void)zb_setImageWithURL:(NSString *)urlString placeholderImage:(UIImage *)placeholder{
    [self zb_setImageWithURL:urlString placeholderImage:placeholder path:nil];
}

- (void)zb_setImageWithURL:(NSString *)urlString placeholderImage:(UIImage *)placeholder path:(NSString *)path{
    [self zb_setImageWithURL:urlString placeholderImage:placeholder path:path completion:nil];
}

- (void)zb_setImageWithURL:(NSString *)urlString completion:(downloadCompletion)completion{
    [self zb_setImageWithURL:urlString placeholderImage:nil completion:completion];
}

- (void)zb_setImageWithURL:(NSString *)urlString placeholderImage:(UIImage *)placeholder completion:(downloadCompletion)completion{
    [self zb_setImageWithURL:urlString placeholderImage:placeholder path:[[ZBWebImageManager sharedInstance]imageFilePath] completion:completion];
}

- (void)zb_setImageWithURL:(NSString *)urlString placeholderImage:(UIImage *)placeholder path:(NSString *)path completion:(downloadCompletion)completion{
    if(placeholder){
        self.image=placeholder;
    }
    __weak __typeof(self)wself = self;
    [[ZBWebImageManager sharedInstance]downloadImageUrl:urlString path:path completion:^(UIImage *image){
        if (image) {
            wself.image=image;
            [wself setNeedsLayout];
        }else{
            wself.image=placeholder;
            [wself setNeedsLayout];
        }
        if(completion) { completion(image); }}]; }Copy the code

The above core method is very simple to determine a placeholder map with a placeholder, get the picture to replace the placeholder map. use

 [self.imageView zb_setImageWithURL:imageUrl placeholderImage:[UIImage imageNamed:@"zhanweitu"]].Copy the code

At this point a simple image cache is done but can’t take the place of other third parties because the image has a lot of other work to do. We will slowly accumulate, but for the beginning of the interview question, or enough. In the actual project. As mentioned earlier, we can use this framework when we come across code like this.

        NSURL *url=[NSURL URLWithString:imageUrl];
        NSData *data=[NSData dataWithContentsOfURL:url];
        UIImage *image=[UIImage imageWithData:data];
Copy the code

From this article, you can feel that ZBNetworking has a good extension of ZBCacheManager, all the storage judgment has been designed, only when you should call it.

Click on github to download it

End: the level is limited, the code is also very bad, has been studying hard, we forgive. If you like this wheel, please give a star, this is the biggest encouragement and support to the author, thank you!! If you have a better idea or plan, please leave a comment!