Giter Site home page Giter Site logo

pinterest / pinremoteimage Goto Github PK

View Code? Open in Web Editor NEW
4.0K 102.0 508.0 22.76 MB

A thread safe, performant, feature rich image fetcher

License: Apache License 2.0

Objective-C 22.73% Ruby 0.14% Shell 20.38% Makefile 24.48% Swift 0.75% C 31.52%
ios objective-c image webp progressive-jpgs gifs

pinremoteimage's Introduction

PINRemoteImage

Fast, non-deadlocking parallel image downloader and cache for iOS

CocoaPods compatible Carthage compatible Build status

PINRemoteImageManager is an image downloading, processing and caching manager. It uses the concept of download and processing tasks to ensure that even if multiple calls to download or process an image are made, it only occurs one time (unless an item is no longer in the cache). PINRemoteImageManager is backed by GCD and safe to access from multiple threads simultaneously. It ensures that images are decoded off the main thread so that animation performance isn't affected. None of its exposed methods allow for synchronous access. However, it is optimized to call completions on the calling thread if an item is in its memory cache.

PINRemoteImage supports downloading many types of files. It, of course, supports both PNGs and JPGs. It also supports decoding WebP images if Google's library is available. It even supports GIFs and Animated WebP via PINAnimatedImageView.

PINRemoteImage also has two methods to improve the experience of downloading images on slow network connections. The first is support for progressive JPGs. This isn't any old support for progressive JPGs though: PINRemoteImage adds an attractive blur to progressive scans before returning them.

Progressive JPG with Blur

PINRemoteImageCategoryManager defines a protocol which UIView subclasses can implement and provide easy access to PINRemoteImageManager's methods. There are built-in categories on UIImageView, PINAnimatedImageView and UIButton, and it's very easy to implement a new category. See [UIImageView+PINRemoteImage](/Pod/Classes/Image Categories/UIImageView+PINRemoteImage.h) of the existing categories for reference.

Download an image and set it on an image view:

Objective-C

UIImageView *imageView = [[UIImageView alloc] init];
[imageView pin_setImageFromURL:[NSURL URLWithString:@"http://pinterest.com/kitten.jpg"]];

Swift

let imageView = UIImageView()
imageView.pin_setImage(from: URL(string: "https://pinterest.com/kitten.jpg")!)

Download a progressive jpeg and get attractive blurred updates:

Objective-C

UIImageView *imageView = [[UIImageView alloc] init];
[imageView setPin_updateWithProgress:YES];
[imageView pin_setImageFromURL:[NSURL URLWithString:@"http://pinterest.com/progressiveKitten.jpg"]];

Swift

let imageView = UIImageView()
imageView.pin_updateWithProgress = true
imageView.pin_setImage(from: URL(string: "https://pinterest.com/progressiveKitten.jpg")!)

Download a WebP file

Objective-C

UIImageView *imageView = [[UIImageView alloc] init];
[imageView pin_setImageFromURL:[NSURL URLWithString:@"http://pinterest.com/googleKitten.webp"]];

Swift

let imageView = UIImageView()
imageView.pin_setImage(from: URL(string: "https://pinterest.com/googleKitten.webp")!)

Download a GIF and display with PINAnimatedImageView

Objective-C

PINAnimatedImageView *animatedImageView = [[PINAnimatedImageView alloc] init];
[animatedImageView pin_setImageFromURL:[NSURL URLWithString:@"http://pinterest.com/flyingKitten.gif"]];

Swift

let animatedImageView = PINAnimatedImageView()
animatedImageView.pin_setImage(from: URL(string: "http://pinterest.com/flyingKitten.gif")!)

Download and process an image

Objective-C

UIImageView *imageView = [[UIImageView alloc] init];
[self.imageView pin_setImageFromURL:[NSURL URLWithString:@"https://i.pinimg.com/736x/5b/c6/c5/5bc6c5387ff6f104fd642f2b375efba3.jpg"] processorKey:@"rounded" processor:^UIImage *(PINRemoteImageManagerResult *result, NSUInteger *cost)
 {
     CGSize targetSize = CGSizeMake(200, 300);
     CGRect imageRect = CGRectMake(0, 0, targetSize.width, targetSize.height);
     UIGraphicsBeginImageContext(imageRect.size);
     UIBezierPath *bezierPath = [UIBezierPath bezierPathWithRoundedRect:imageRect cornerRadius:7.0];
     [bezierPath addClip];

     CGFloat sizeMultiplier = MAX(targetSize.width / result.image.size.width, targetSize.height / result.image.size.height);

     CGRect drawRect = CGRectMake(0, 0, result.image.size.width * sizeMultiplier, result.image.size.height * sizeMultiplier);
     if (CGRectGetMaxX(drawRect) > CGRectGetMaxX(imageRect)) {
         drawRect.origin.x -= (CGRectGetMaxX(drawRect) - CGRectGetMaxX(imageRect)) / 2.0;
     }
     if (CGRectGetMaxY(drawRect) > CGRectGetMaxY(imageRect)) {
         drawRect.origin.y -= (CGRectGetMaxY(drawRect) - CGRectGetMaxY(imageRect)) / 2.0;
     }

     [result.image drawInRect:drawRect];

     UIImage *processedImage = UIGraphicsGetImageFromCurrentImageContext();
     UIGraphicsEndImageContext();
     return processedImage;
 }];

Swift

let imageView = FLAnimatedImageView()
imageView.pin_setImage(from: URL(string: "https://i.pinimg.com/736x/5b/c6/c5/5bc6c5387ff6f104fd642f2b375efba3.jpg")!, processorKey: "rounded")  { (result, unsafePointer) -> UIImage? in

    guard let image = result.image else { return nil }

    let radius : CGFloat = 7.0
    let targetSize = CGSize(width: 200, height: 300)
    let imageRect = CGRect(x: 0, y: 0, width: targetSize.width, height: targetSize.height)

    UIGraphicsBeginImageContext(imageRect.size)

    let bezierPath = UIBezierPath(roundedRect: imageRect, cornerRadius: radius)
    bezierPath.addClip()

    let widthMultiplier : CGFloat = targetSize.width / image.size.width
    let heightMultiplier : CGFloat = targetSize.height / image.size.height
    let sizeMultiplier = max(widthMultiplier, heightMultiplier)

    var drawRect = CGRect(x: 0, y: 0, width: image.size.width * sizeMultiplier, height: image.size.height * sizeMultiplier)
    if (drawRect.maxX > imageRect.maxX) {
        drawRect.origin.x -= (drawRect.maxX - imageRect.maxX) / 2
    }
    if (drawRect.maxY > imageRect.maxY) {
        drawRect.origin.y -= (drawRect.maxY - imageRect.maxY) / 2
    }

    image.draw(in: drawRect)

    UIColor.red.setStroke()
    bezierPath.lineWidth = 5.0
    bezierPath.stroke()

    let ctx = UIGraphicsGetCurrentContext()
    ctx?.setBlendMode(CGBlendMode.overlay)
    ctx?.setAlpha(0.5)

    let logo = UIImage(named: "white-pinterest-logo")
    ctx?.scaleBy(x: 1.0, y: -1.0)
    ctx?.translateBy(x: 0.0, y: -drawRect.size.height)

    if let coreGraphicsImage = logo?.cgImage {
        ctx?.draw(coreGraphicsImage, in: CGRect(x: 90, y: 10, width: logo!.size.width, height: logo!.size.height))
    }

    let processedImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    return processedImage

}

Handle Authentication

Objective-C

[[PINRemoteImageManager sharedImageManager] setAuthenticationChallenge:^(NSURLSessionTask *task, NSURLAuthenticationChallenge *challenge, PINRemoteImageManagerAuthenticationChallengeCompletionHandler aCompletion) {
aCompletion(NSURLSessionAuthChallengePerformDefaultHandling, nil)];

Swift

PINRemoteImageManager.shared().setAuthenticationChallenge { (task, challenge, completion) in
  completion?(.performDefaultHandling, nil)
}

Support for high resolution images

Currently there are two ways PINRemoteImage is supporting high resolution images:

  1. If the URL contains an _2x. or an _3x. postfix it will be automatically handled by PINRemoteImage and the resulting image will be returned at the right scale.
  2. If it's not possible to provide an URL with an _2x. or _3x. postfix, you can also handle it with a completion handler:
NSURL *url = ...;
__weak UIImageView *weakImageView = self.imageView;
[self.imageView pin_setImageFromURL:url completion:^(PINRemoteImageManagerResult * _Nonnull result) {
  CGFloat scale = UIScreen.mainScreen.scale;
  if (scale > 1.0) {
    UIImage *image = result.image;
    weakImageView.image = [UIImage imageWithCGImage:image.CGImage scale:scale orientation:image.imageOrientation];
    }
}];

Set some limits

// cache is an instance of PINCache as long as you haven't overridden defaultImageCache
PINCache *cache = (PINCache *)[[PINRemoteImageManager sharedImageManager] cache];
// Max memory cost is based on number of pixels, we estimate the size of one hundred 600x600 images as our max memory image cache.
[[cache memoryCache] setCostLimit:600 * [[UIScreen mainScreen] scale] * 600 * [[UIScreen mainScreen] scale] * 100];

// ~50 MB
[[cache diskCache] setByteLimit:50 * 1024 * 1024];
// 30 days
[[cache diskCache] setAgeLimit:60 * 60 * 24 * 30];

Installation

CocoaPods

Add PINRemoteImage to your Podfile and run pod install.

If you'd like to use WebP images, add PINRemoteImage/WebP to your Podfile and run pod install.

Carthage

Add github "pinterest/PINRemoteImage" to your Cartfile . See Carthage's readme for more information on integrating Carthage-built frameworks into your project.

Manually

Download the latest tag and drag the Pod/Classes folder into your Xcode project. You must also manually link against PINCache.

Install the docs by double clicking the .docset file under docs/, or view them online at cocoadocs.org

Git Submodule

You can set up PINRemoteImage as a submodule of your repo instead of cloning and copying all the files into your repo. Add the submodule using the commands below and then follow the manual instructions above.

git submodule add https://github.com/pinterest/PINRemoteImage.git
git submodule update --init

Requirements

PINRemoteImage requires iOS 7.0 or greater.

Contact

Garrett Moon @garrettmoon Pinterest

License

Copyright 2015 Pinterest, Inc.

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

pinremoteimage's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pinremoteimage's Issues

Crash on -[PINProgressiveImage data]

Hey,

We've seen reports of crashes caused by PINProgressiveImage in the wild, although we are not able to reproduce them locally. I thought I might as well throw it up here just in case. It seems to happen when the request fails, and PINProgressiveImage tries to make a copy of its mutableData. Perhaps the data in there is malformed, due to the error (a network error?)? I've only seen this reported on iOS 8. Here's the crash report:

Incident Identifier: 0ee7954f-96a4-4084-b1bc-1cd7e8eafdc3
CrashReporter Key:   TODO
Hardware Model:      iPad5,3
Process:         whats-new [4854]
Path:            /private/var/mobile/Containers/Bundle/Application/2D9CA817-0342-48BA-89E0-D26AB4A58538/whats-new.app/whats-new
Version:         5378
Code Type:       ARM-64 (Native)
Parent Process:  launchd[1]

Date/Time:       2015-11-02 20:58:51 +0000
OS Version:      iOS 8.1 (12B410)
Report Version:  104

Exception Type:  SIGABRT
Exception Codes: #0 at        0x1952e3270
Crashed Thread:  21

Application Specific Information:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** NSAllocateMemoryPages(337384) failed'

Last Exception Backtrace:
CoreFoundation                 0x000000018406de48 __exceptionPreprocess + 132
libobjc.A.dylib                0x0000000194b5c0e0 objc_exception_throw + 56
CoreFoundation                 0x000000018406dd84 +[NSException raise:format:] + 124
Foundation                     0x0000000184ec7184 NSAllocateMemoryPages + 100
Foundation                     0x0000000184e9980c _NSDataCreateVMDispatchData + 32
Foundation                     0x0000000184e60ebc -[_NSPlaceholderData initWithBytes:length:copy:deallocator:] + 268
whats-new                      0x0000000100276718 -[PINProgressiveImage data] (PINProgressiveImage.m:271)
whats-new                      0x000000010027d6cc __69-[PINRemoteImageManager downloadDataWithURL:key:priority:completion:]_block_invoke (PINRemoteImageManager.m:831)
whats-new                      0x0000000100274f6c __86+[PINDataTaskOperation dataTaskOperationWithSessionManager:request:completionHandler:]_block_invoke (PINDataTaskOperation.m:57)
whats-new                      0x0000000100281ebc -[PINURLSessionManager URLSession:task:didCompleteWithError:] (PINURLSessionManager.m:78)
CFNetwork                      0x0000000183ad1be0 __51-[NSURLSession delegate_task:didCompleteWithError:]_block_invoke227 + 60
Foundation                     0x0000000184f23504 __NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__ + 12
Foundation                     0x0000000184e74c90 -[NSBlockOperation main] + 92
Foundation                     0x0000000184e64618 -[__NSOperationInternal _start:] + 632
Foundation                     0x0000000184f26268 __NSOQSchedule_f + 224
libdispatch.dylib              0x00000001951a1368 _dispatch_client_callout + 12
libdispatch.dylib              0x00000001951ab4bc _dispatch_queue_drain + 1212
libdispatch.dylib              0x00000001951a4470 _dispatch_queue_invoke + 128
libdispatch.dylib              0x00000001951ad220 _dispatch_root_queue_drain + 660
libdispatch.dylib              0x00000001951ae758 _dispatch_worker_thread3 + 104
libsystem_pthread.dylib        0x000000019537d2e0 _pthread_wqthread + 812
libsystem_pthread.dylib        0x000000019537cfa4 start_wqthread + 0

Loads of boring stuff and then:

Thread 21 Crashed:
0   libsystem_kernel.dylib         0x00000001952e3270 __pthread_kill + 8
1   libsystem_c.dylib              0x000000019525ab14 abort + 108
2   whats-new                      0x000000010030ce88 _ZN7plcrash5async24dwarf_cfa_state_iteratorIyxE4nextEPjPNS1_28plcrash_dwarf_cfa_reg_rule_tEPy (ISO8601Serialization.m:150)
3   CoreFoundation                 0x000000018406e204 __handleUncaughtException + 688
4   libobjc.A.dylib                0x0000000194b5c3b0 _ZL15_objc_terminatev + 112
5   libc++abi.dylib                0x0000000194349bb0 _ZSt11__terminatePFvvE + 12
6   libc++abi.dylib                0x0000000194349c20 _ZSt9terminatev + 60
7   libobjc.A.dylib                0x0000000194b5c314 objc_terminate + 8
8   libdispatch.dylib              0x00000001951a137c        0x1951a0000 + 32
9   libdispatch.dylib              0x00000001951ab4bc _dispatch_queue_drain + 1212
10  libdispatch.dylib              0x00000001951a4470 _dispatch_queue_invoke + 128
11  libdispatch.dylib              0x00000001951ad220 _dispatch_root_queue_drain + 660
12  libdispatch.dylib              0x00000001951ae758 _dispatch_worker_thread3 + 104
13  libsystem_pthread.dylib        0x000000019537d2e0 _pthread_wqthread + 812
14  libsystem_pthread.dylib        0x000000019537cfa4 start_wqthread + 0

Any help appreciated. Thanks.

Feature request: pre-build framework (or static library)

Hi,

Your library is awesome! Yesterday I've replaced our own simple caching solution with PINRemoteImage and our app http://marqueemoviesapp.com got a really noticeable speed boost. But I can't say that was easy thing to do and IMHO most of the developers does not want to fiddle with sources and spend their time building external libraries.

Could you consider providing PINRemoteImage as a framework or static library?

Thanks,
Alex

Set up to build on Travis CI

Since you've got some unit tests, it would be good to get them running on Travis to make sure they keep passing through merges.

Crash on - [PINProgressiveImage postProcessImage:withProgress:] CompilerFSCacheSerialQueue

Hi,
I receive a crash report from Crashlytics.
Here is the crash report raw data

Thread : Crashed: CompilerFSCacheSerialQueue

0  libsystem_platform.dylib       0x18490e2c0 _platform_memmove + 208
1  AGXGLDriver                    0x195e751bc (null)
2  AGXGLDriver                    0x195e751bc (null)
3  AGXCompilerConnection          0x194302dc4 (null)
4  libdispatch.dylib              0x1847015f0 _dispatch_client_callout + 16
5  libdispatch.dylib              0x18470c89c _dispatch_barrier_sync_f_invoke + 100
6  AGXCompilerConnection          0x194302c40 CompilerFSCache::GetElement(unsigned char*, void (void const*, unsigned long) block_pointer)
7  AGXCompilerConnection          0x194302364 (null)
8  libdispatch.dylib              0x1847015f0 _dispatch_client_callout + 16
9  libdispatch.dylib              0x18470c89c _dispatch_barrier_sync_f_invoke + 100
10 AGXCompilerConnection          0x1943022f4 XPCCompilerConnection::BuildRequest(NSObject<OS_dispatch_data>*, NSObject<OS_dispatch_data>*, void (void const*, unsigned long) block_pointer)
11 AGXGLDriver                    0x195e76410 AGXHalShaderFactoryT<AGXUserFragmentShaderKey, AGXHalFragmentShader>::create(AGXUserFragmentShaderKey const*)
12 AGXGLDriver                    0x195eb011c AGXFragmentShader::getCompiledVariant(AGXContextRec*, _AGCFragmentContextStateGL const*, _AGCSamplerPCFStates const*, _AGCDrawBufferState const*, _AGCTexUnitBiasStates const*, unsigned int&)
13 AGXGLDriver                    0x195eb0730 glrUpdateCtxSysFragmentProgram
14 AGXGLDriver                    0x195e38ba8 gpusLoadCurrentPipelinePrograms
15 AGXGLDriver                    0x195e65660 gldUpdateDispatch
16 GLEngine                       0x196e47860 gleDoDrawDispatchCoreES2
17 GLEngine                       0x196e21478 glDrawArrays_IMM_ES2Exec
18 CoreImage                      0x187d58dbc CI::GLContext::quad(float const*, float const*) + 308
19 CoreImage                      0x187d543ec CI::GeneralPromise::render_node_gles(CI::GLContext*, CI::PromiseNode const*, CGRect, void const*) + 1060
20 CoreImage                      0x187d59614 CI::GLContext::recursive_render(CI::Node*, bool) + 576
21 CoreImage                      0x187d595cc CI::GLContext::recursive_render(CI::Node*, bool) + 504
22 CoreImage                      0x187d595cc CI::GLContext::recursive_render(CI::Node*, bool) + 504
23 CoreImage                      0x187d595cc CI::GLContext::recursive_render(CI::Node*, bool) + 504
24 CoreImage                      0x187d595cc CI::GLContext::recursive_render(CI::Node*, bool) + 504
25 CoreImage                      0x187d595cc CI::GLContext::recursive_render(CI::Node*, bool) + 504
26 CoreImage                      0x187d595cc CI::GLContext::recursive_render(CI::Node*, bool) + 504
27 CoreImage                      0x187d59490 CI::GLContext::recursive_render(CI::Node*, bool) + 188
28 CoreImage                      0x187d5a6f0 CI::GLContext::render(CI::Node*) + 180
29 CoreImage                      0x187d6c748 CI::image_get_cgimage(CI::Context*, CI::Image*, CGRect, CGColorSpace*, CI::PixelFormat) + 1784
30 CoreImage                      0x187d335e0 -[CIContext createCGImage:fromRect:format:colorSpace:] + 616
31 Kono                           0x1005cd990 -[PINProgressiveImage postProcessImage:withProgress:] (PINProgressiveImage.m:364)
32 Kono                           0x1005cd1f0 -[PINProgressiveImage currentImage] (PINProgressiveImage.m:259)
33 Kono                           0x1005d5d34 __48-[PINRemoteImageManager didReceiveData:forTask:]_block_invoke (PINRemoteImageManager.m:1061)
34 Foundation                     0x185654334 __NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__ + 16
35 Foundation                     0x1855a7100 -[NSBlockOperation main] + 96
36 Foundation                     0x185597348 -[__NSOperationInternal _start:] + 604
37 Foundation                     0x185656728 __NSOQSchedule_f + 224
38 libdispatch.dylib              0x1847015f0 _dispatch_client_callout + 16
39 libdispatch.dylib              0x18470d634 _dispatch_queue_drain + 864
40 libdispatch.dylib              0x1847050f4 _dispatch_queue_invoke + 464
41 libdispatch.dylib              0x18470f504 _dispatch_root_queue_drain + 728
42 libdispatch.dylib              0x18470f224 _dispatch_worker_thread3 + 112
43 libsystem_pthread.dylib        0x184915470 _pthread_wqthread + 1092
44 libsystem_pthread.dylib        0x184915020 start_wqthread + 4

Could you give me some advice? Thanks!

Placeholder Image not set when URL is nil.

When using a PinRemoteImageCategory (UIImageView) if you set a placeholderImage and provide an invalid URL. The invalid url causes the UIImageView to set the image to nil removing the placeholder image.

I would expect the behaviour to instead set the placeholder Image regardless of if the url is a valid or not.

I can submit a PR with a fix. If this is something you guys would liked fixed.

How to prefetch properly - README Enhancement

I'm using PINRemoteImage as my main image downloader and it's really awesome to use it. In my applications I use it as the main library for handling image downloads and prefetching them to store it locally on the disk.

But I head to run through many obstacles to create a download task that is not cached in the memory cache but in the disk cache.

I would like to add more information about How to prefetch properly in the README file if it's ok with you guys. IMHO it's the best RemoteImage solution that we have in iOS OSS.

What is your opinion about this?

Readme missing instructions on setting up PINCache

This library relies on PINCache, but there are no instructions in the Readme that it needs to be added to your project or how to do so properly. Presumably it is set up for you if you are using Cocoapods, but further documentation should be added to the git submodules section.

Image not found but error is (null)?

When I attempt to load an image at an invalid URL and the completion block is called I would expect the error to contain information about why the image didn't load. Instead both the error and image contain (null). Shouldn't a 404 result in a valid error?

console output when printing result:

<PINRemoteImageManagerResult: 0x7ff2996d5e40>image: (null)
animatedImage: (null)
requestDuration: 0.366901
error: (null)
resultType: 3
UUID: <__NSConcreteUUID 0x7ff29ba06db0> 8264EB5B-4ADD-466E-9033-2A11BFDA2524

Memory Leak in UIIMage(PInDecodedImage)

I maybe found a memory leak in the current implementation of decoding the images. It's clearly visible when you try to decode big images (2000x1000 px). The CG raster data in VM memory size is really high for each of my pictures (10,2 MB). And if I relaunch the app with local cached images the cg raster data for the image is only 1.34 MB each.

I can reproduce it myself when I try to scale my images with the processor. After switching from UIGraphicsBeginImageContextWithOptions to CIImage my memory footprint is now very low and my code is releasing it much better.

CGGraphicsBeginImageContext Example

 let image = managerResult.image
 let scaleValue = UIScreen.mainScreen().bounds.size.height / managerResult.image.size.height
 let size = CGSizeApplyAffineTransform(image!.size, CGAffineTransformMakeScale(scaleValue, scaleValue))
 let hasAlpha = false
 let scale : CGFloat = 0.0

UIGraphicsBeginImageContextWithOptions(size, !hasAlpha, scale)
image!.drawInRect(CGRect(origin: CGPointZero, size: size))

 let scaledImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()

return scaledImage;

This is leaking :(

CIImage Example

 let image = CIImage(CGImage: managerResult.image.CGImage)

 let filter = CIFilter(name: "CILanczosScaleTransform")!
 filter.setValue(image, forKey: "inputImage")
 filter.setValue(scaleValue, forKey: "inputScale")
 filter.setValue(1.0, forKey: "inputAspectRatio")
 let outputImage = filter.valueForKey("outputImage") as! CIImage

 let context = CIContext(options: [kCIContextUseSoftwareRenderer : false])
 let scaledImage = UIImage(CGImage: context.createCGImage(outputImage, fromRect: outputImage.extent()))

 return scaledImage

This is fine 😎

Instrument Leaks

screenshot 2015-10-19 16 46 33
screenshot 2015-10-19 16 53 13

Understanding addImages method

I'm new to iOS and likely going to use this library, trying to understand addImages method implementation, could see that add kitten object is added using main thread? why not directly add in it async block like mentioned below?

addImages {
....
kitten.imageURL = kittenURLs[kittenIdx];
kitten.imageSize = CGSizeMake(width / scale, height / scale);

// dispatch_sync(dispatch_get_main_queue(), ^{
// [tmpKittens addObject:kitten];
// });
[tmpKittens addObject:kitten];
}

Prefetching with many images is memory intensive and is crashing the App

I would like to prefetch as many pictures as possible for my application tried the PINRemoteImageManager.sharedImageManager().prefetchImagesWithURLs() function.

But at the Moment my App is crashing from watchdog because of heavy memory usage. I got 133 Images to prefetch and some of theme are high quality pictures (2001x1334).

I switched from SDWebImage to PINRemoteImage to resize the pictures, but I'cant do it in prefetchImagesWithURL. Is there a way to create as many images as possible offline without memory exhaustion?

Feature request: progressive jpeg on iOS 7

I dig into the source and try to disable iOS 8 checking, but my app crashes when displaying the jpeg.
I try to fix this but failed.
Is there any ways to support progressive jpeg on iOS 7?

Don't load image from cache

My server unfortunately returns the same image URL even if the picture is updated. Therefore I somehow need to skip the cache when loading an image. Could you please help me how this can be done?

I tried to clear the cache before loading the image:

 PINRemoteImageManager.sharedImageManager().defaultImageCache().removeAllObjects()
 profileImage.pin_cancelImageDownload()
            profileImage.pin_setImageFromURL(profileImageURL, placeholderImage: placeHolder) {
                (result:PINRemoteImageManagerResult!) in
            }

Nevertheless the image is returned from the cache.

Readme and code are out of sync

I updated the readme in #3, but because there has not been a new release, the readme currently recommends using methods that are not available in the 1.0 release, which anyone using CocoaPods will be using.

Decoded images ignore image orientation

Using UIImageView -pin_setImageFromURL: and related methods lose orientation metadata and display incorrectly.

This seems to be because that are decoded using pin_decodedImageWithCGImageRef: don't take the images orientation into account when drawing the CGImageRef into the context.

Repro steps:

imageView.pin_setImageFromURL(NSURL(string: "https://www.dropbox.com/s/nakmlzyqkqd8ie8/04cd607b-d5ba-4f4a-9344-77c8ef94c291--2015-08-12-08-41-27.jpg?dl=1"))

That image was taken with an iPhone 6, portrait orientation. It appears rotated when set on the imageview via pin_setImageFromURL. Viewing it in a browser, preview, etc show it correctly.

use of @import when modules are disabled

Not sure if it's because I'm developing in swift using a bridging header, or because my project is running on top of Unity but the @import lines at the top of some of your source code cause the error "use of @import when modules are disabled". I've gone through my project settings as well as the cocoapods settings and enabled modules but I eventually had to go through and hack out the @import with the old style #import, which we will have to do again if cocoa pods updates the pod!

I think it's probably the Unity aspect of my project as we have to use Objective-C++.

Other than that great job on the library, far quicker and more robust than the solution we were using previously.

Crash on -[PINURLSessionManager URLSession:dataTask:didReceiveData:]

Hey,

We've seen some crashes reported on our monitoring. These crashes happen on iOS 8 and 9. We haven't been able to reproduce them. Here is a stack trace:

Incident Identifier: 1e728a20-4ec7-4434-b44e-72050dd9e36b
CrashReporter Key:   TODO
Hardware Model:      iPhone5,2
Process:         whats-new [1169]
Path:            /var/mobile/Containers/Bundle/Application/DB9AFE0C-58A1-476F-8A84-BD7DD291FC57/whats-new.app/whats-new
Version:         5637
Code Type:       ARM (Native)
Parent Process:  ???[1]

Date/Time:       2015-11-06 06:33:56 +0000
OS Version:      iOS 9.1 (13B143)
Report Version:  104

Exception Type:  SIGSEGV
Exception Codes: SEGV_ACCERR at       0x30
Crashed Thread:  13

Thread 13:

Thread 13 Crashed:
0   libdispatch.dylib              0x37e54f22 dispatch_async + 66
1   whats-new                      0x001c9ea8 -[PINURLSessionManager URLSession:dataTask:didReceiveData:] (PINURLSessionManager.m:90)
2   CFNetwork                      0x2597227e __67-[NSURLSession delegate_dataTask:didReceiveData:completionHandler:]_block_invoke221 + 34
3   Foundation                     0x26e2c56a __NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__ + 6
4   Foundation                     0x26d8dfdc -[NSBlockOperation main] + 144
5   Foundation                     0x26d803cc -[__NSOperationInternal _start:] + 772
6   Foundation                     0x26e2e82a __NSOQSchedule_f + 190
7   libdispatch.dylib              0x37e5dfec _dispatch_queue_drain + 1760
8   libdispatch.dylib              0x37e56f84 _dispatch_queue_invoke + 280
9   libdispatch.dylib              0x37e5f37a _dispatch_root_queue_drain + 398
10  libdispatch.dylib              0x37e5f1e8 _dispatch_worker_thread3 + 92
11  libsystem_pthread.dylib        0x37fe8e0a _pthread_wqthread + 1022
12  libsystem_pthread.dylib        0x37fe89fa start_wqthread + 7

Error when trying to use webp

I have a Swift project that includes PINRemoteImage and webp. When I try to build my project I get this error:

Undefined symbols for architecture arm64:
  "_WebPGetFeaturesInternal", referenced from:
      _WebPGetFeatures in UIImage+WebP.o
  "_WebPDecodeRGBA", referenced from:
      +[UIImage(WebP) imageWithWebPData:] in UIImage+WebP.o
  "_WebPDecodeRGB", referenced from:
      +[UIImage(WebP) imageWithWebPData:] in UIImage+WebP.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

I'm not sure where to go hunting for what exactly is wrong.. I've cleaned my project a bunch of times, deleted Derived Data, etc. No luck so far :(

How to use with webp

I have add all of the PINRemoteImage files to my project ,but use pin_setImageFromURL(NSURL(string: "xxxx.jpg")!) can not show the image ,my webp image postfix is ".jpg",but it is wep image

Carthage support

It would be nice to have carthage support. Not sure about the exact requirements, but I believe it needs to have a framework target.

Crashed: PINURLSessionManager Operation Queue :: NSOperation (QOS: LEGACY)

We have a similar issue to #91 I thought I'd create a new ticket as it isnt on the exact same line. I'm running the latest code with commit 65d9c58

The issue happens on ios 8/9 only. I can link you to the crashlytics issue if more info is required.

Thread : Crashed: PINURLSessionManager Operation Queue :: NSOperation 0x149041870 (QOS: LEGACY)
0  libdispatch.dylib              6850538312 dispatch_async + 76
1  libdispatch.dylib              6850538304 dispatch_async + 68
2  PaigeeWorld                    4297916584 -[PINURLSessionManager URLSession:task:didReceiveChallenge:completionHandler:] (PINURLSessionManager.m:79)
3  Foundation                     6509364084 __NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__ + 16
4  Foundation                     6508655008 -[NSBlockOperation main] + 96
5  Foundation                     6508590056 -[__NSOperationInternal _start:] + 604
6  Foundation                     6509373288 __NSOQSchedule_f + 224
7  libdispatch.dylib              6850533032 _dispatch_client_callout + 16
8  libdispatch.dylib              6850582252 _dispatch_queue_drain + 864
9  libdispatch.dylib              6850548140 _dispatch_queue_invoke + 464
10 libdispatch.dylib              6850590140 _dispatch_root_queue_drain + 728
11 libdispatch.dylib              6850589404 _dispatch_worker_thread3 + 112
12 libsystem_pthread.dylib        6852760688 _pthread_wqthread + 1092

I've had no luck trying to reproduce it. If you have any thoughts on how I can give it a shot.

Receiving resultType of PINRemoteImageResultTypeDownload when offline and no image is downloaded

I expect that when I get a result in my completion block with a non-nil error, and a nil image, the resultType should be PINRemoteImageResultTypeNone - no image was downloaded, after all.

However, with my iPad in Airplane mode, I get PINRemoteImageResultTypeDownload.

This happens because the result type is assumed to be a successful download if a cache miss occurs, regardless of the error state or images existence.

Is this expected behaviour?

PINURLSessionManager Crash on iOS 9

EXC_BAD_ACCESS KERN_INVALID_ADDRESS on
PINURLSessionManager.m line 76
-[PINURLSessionManager URLSession:task:didReceiveChallenge:completionHandler:]

here is the stack trace

Thread : com.apple.main-thread
0  libsystem_kernel.dylib         6871861824 mach_msg_trap + 8
1  libsystem_kernel.dylib         6871861436 mach_msg + 72
2  CoreFoundation                 6514966792 __CFRunLoopServiceMachPort + 196
3  CoreFoundation                 6514957836 __CFRunLoopRun + 1032
4  CoreFoundation                 6514101408 CFRunLoopRunSpecific + 384
5  GraphicsServices               6700990600 GSEventRunModal + 180
6  UIKit                          6605426684 UIApplicationMain + 204
7  App                            4296537760 main (main.m:16)
8  libdyld.dylib                  6870804664 start + 4

Include of non-modular header inside framework module

We are implementing an iOS-framework so to reuse it in other projects. We use PINRemoteImage in one class of our framework as well as a couple of times in the project it self. However as soon as we use the class from the framework 3 error messages e.g. "Include of non-modular header inside framework module 'PINRemoteImage.PINRemoteImageManagerResult'".

As a workaround we removed the define macro in "PINRemoteImageMacros.h" at the moment

cheers,
Chris

pinremoteimagemanagerresult_error

Using PINRemoteImageManager's initWithSessionConfiguration

I am unclear on how you are supposed to use the initWithSessionConfiguration init on PINRemoteImageManager, as there is no way to get your init'd manager into the result of the sharedImageManager method, which is used by several methods in PINRemoteImageCategoryManager. Possibly I am just not understanding its intended usage, but it seems like you need to either have a way to change/set the return value of sharedImageManager, or refactor PINRemoteImageCategoryManager to not rely on a singleton.

Support for custom HTTP request headers

If an application is required to set additional HTTP headers on image requests, I don't see a way to either supply an NSURLRequest for each image request (with the appropriate headers already set) or to add the headers globally to all requests.

As one solution, PINRemoteImageManager uses [NSURLSessionConfiguration defaultConfiguration] in its initialization. If PINRemoteImageManager offered a way to customize that configuration, that could be configured to add the additional headers to all image requests made through that (shared) instance of PINRemoteImageManager.

Raise 'processor' block also in case getting image cache

It would be nice if processor block would also get called on pulling image from cache using methods
pin_setImageFromURL:processorKey:processor:, etc.

Image preprocessing block is great thing and would be cool if that can be applied for cached images.
Thanks in advance!

Ability to track download progress

Is there a way to track the download progress of a remote image?

For example, I would like to show a progress bar atop a UIImageView that shows the image is downloading from the web.

Issue #59 referred to it, but I think it was answered in reference to progressive renders as opposed to download percentages.

It's a great project but difficult to use

As you say how to use:
Installation
Manually
Download the latest tag and drag the PINRemoteImage folder into your Xcode project.
Install the docs by double clicking the .docset file under docs/, or view them online at cocoadocs.org

First,i tried clone in desktop directly,but find the Contents is so complex that i do not know how to 'drag the PINRemoteImage folder into your Xcode project' .

Then,i use 'pod search PINRemoteImage‘ code,but it shows:
[!] Unable to find a pod with name matching `PINRemoteImage'

I love this project but i really can not find how to put it in my Xcode project. I guess you should learn the SDWebImage's usage.Thank you!

My English is so pool,sorry for that!

Images mixed up while using with UICollectionView

When Collectionview reuses the view then images get mixed up.
Let suppose there is cell A, and code made a request for IMG_URL_1 that is 43KB It will take time to load CollectionView while scrolling reuses cell A again and this time code made a request for IMG_URL_6 for this cell, and this image is only of 6KB, so it will load faster while IMG_URL_1 still in loading process. First view gets updated with IMG_URL_6 image because it loaded early, but after few mili seconds IMG_URL_1 also get loaded so cell will get updated again with IMG_URL_1 this time. But it should display IMG_URL_6 image instead of IMG_URL_1 image.

Change image cache class

I would like to use multiple image caches with different parameters (e.g. ageLimit). What is the preferred way to accomplish this?

Subclassing PINRemoteImageManager is not that easy, because it's shared instance is used for all view categories.

Fast scrolling with a lot of images causes excessive memory usage

Hi,

I have an iPad app where I show rows of 4 (relatively large: width: 920px; height: 1380px;) images on an iPad inside a collection view. This leads to, when scrolling moderately rapid, excessive memory usage and eventually a crash (on physical devices). An example instruments call tree:

pasted_image_at_2015_09_28_16_57_720

An example of memory usage over time:

pasted_image_at_2015_09_28_16_57_720-1

Here is a device log from the crash:

Incident Identifier: 9C9452D1-8376-4E06-8F2F-8E6F26080653
CrashReporter Key:   34a30a2fec33ac19197705866e1020fc84df87bf
Hardware Model:      iPad2,5
OS Version:          iPhone OS 7.0.4 (11B554a)
Kernel Version:      Darwin Kernel Version 14.0.0: Fri Sep 27 23:00:49 PDT 2013; root:xnu-2423.3.12~1/RELEASE_ARM_S5L8942X
Date:                2015-09-30 12:45:46 +0100
Time since snapshot: 125 ms

Free pages:                              1182
Active pages:                            3665
Inactive pages:                          1845
Speculative pages:                       266
Throttled pages:                         102067
Purgeable pages:                         0
Wired pages:                             19868
File-backed pages:                       5433
Anonymous pages:                         343
Compressions:                            0
Decompressions:                          0
Compressor Size:                         0
Uncompressed Pages in Compressor:        0
Largest process:   PINRemoteTest

Processes
     Name                    <UUID>                       rpages       recent_max   fds      [reason]          (state)

   wirelessproxd <46066fc432663d45ab7e055082fe0bd6>          139              139  200   [vm-pageshortage]  (daemon) (idle)
      MobileMail <b3574f4bded1315cb2e50e5de205be48>         1137             1137  200   [vm-pageshortage]  (resume) (continuous)
            tccd <1fea8c5a71943151b5cd304c7eb0fd8c>          160              160  100   [vm-pageshortage]  (daemon)
   PINRemoteTest <8aac78eadffc37b0ac68272860f87788>        74944            74944  200   [vm-pageshortage]  (frontmost) (resume)
            ptpd <db9048c36f6c3c18a7330fc96d93a0cf>          647              647   50                      (daemon)
identityservices <18cc20db2e4739a782cc8e38e03eff52>          364              364  100                      (daemon)
           wifid <a5cf99e5a0f032a69bc2f65050b44291>          379              379   25                      (daemon)
         syslogd <6539f4cf4dcf34daadf1d99991926680>          155              166   50                      (daemon)
       locationd <c31643022d833911b8b7461fd3964bd5>          955              955  100                      (daemon)
          powerd <0a253ac2a99236809422214be1700bc0>          118              118  100                      (daemon)
         imagent <bef102e1faef39209926fb25f428a71e>          240              240  100                      (daemon)
   iaptransportd <42faa147f61a314bb735e239f445efaf>          205              205   50                      (daemon)
    mediaserverd <71101024312538ccae5799b88681e38d>          667              667  100                      (daemon)
   mDNSResponder <8922e9954d893eb9a1ab27ca4723bbab>          210              280  100                      (daemon)
            apsd <0dd1fd7c2edc3cf9899a4830541c1bac>          437              437  100                      (daemon)
     dataaccessd <5da732b6ce6935f2928461a022101aba>          941              941  100                      (daemon)
        sharingd <a95c2cea41b43cc69b0bbe9a03730d45>          448              448   50                      (daemon)
           timed <abc20e52e7ce3cb9832590652d21e7d1>          199              199   50                      (daemon)
          voiced <2823988f691e3715a6e23959590f3c00>          215              215  200                      (daemon)
      calaccessd <77a5672f2f653f64acf7367126a8d173>          219              219  200                      (daemon)
     SpringBoard <3c0e305139b331c6b37d2e9516f5804f>        10476            10476   50                     
      backboardd <d61df126c4673b25bbfe5d9024be1d48>         7615             7615   50                      (daemon)
      aggregated <a5dda46586ba3a3cbb298bd8aa545e50>          454              454   50                      (daemon)
       lockdownd <6f28a28a0025348aa5361078e41914e3>          193              193  100                      (daemon)
    fairplayd.A2 <6cae0c124e1830598a43f6b4d790917f>          132              132  100                      (daemon)
         configd <c57db43e53a73f8a9360f4d0d9001704>          446              446  100                      (daemon)
       fseventsd <5c909a70b62f33c8856e3158834ba071>          242              242  100                      (daemon)
        BTServer <3933a8148924316b9f19dd3d10a23f00>          254              254  100                      (daemon)
       distnoted <38616bd8864034e7bc741f8bd7313349>          117              117  100                      (daemon)
  UserEventAgent <a3c7e56924ec3690a994a75a0ea79ee8>          502              502   50                      (daemon)
        networkd <84dfdb49c24132fa8dd10520deb16645>          423              423  100                      (daemon)
     eapolclient <534b8549294d384c9bec206a272a29cd>          141              141  100                      (daemon)
notification_pro <852af3fe832e3cc3a3f31d05511a5482>          114              114  100                      (daemon)
             ubd <ca1400009326346db54f834cc8b740d2>          491              491  100                      (daemon)
          cplogd <148e9e2ff86130ecb63423c183f68da5>          130              130  200                      (daemon)
     touchsetupd <02780826b4263a7498bda167721b5f8c>          153              153  200                      (daemon)
     debugserver <4f8d671c17be36d2bb9d3b30da9dd947>          164              167  200                      (daemon)
      DTMobileIS <cd97740bdfd833b69d543b3044065d20>          186              186  200                      (daemon)
CommCenterClassi <b836b786e0cb3785a18a94e9b13c9991>          314              314   50                      (daemon)
         notifyd <35afacabfed73771889e72a017479709>          183              183  100                      (daemon)

**End**

I have also created a test project where I can reproduce the issue:

https://github.com/kerrmarin/PINRemoteTest

Is there any way to prevent this crash while maintaining performance? Initially, we thought about setting PINRemoteImageManagerDownloadOptionsSkipDecode as one of the options for the manager, but that limits the scroll performance.

Thanks

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.