Tuesday, June 10, 2014

[iOS] Image Cache Libraries Comparison

The implementation is to pack together images of the same dimensions to a single file(image table), all images in image table are decompressed, and original image never be cached. 
When an image request is coming, it’s going to check the image table and simply return it immediately if it can be found, or else to download asynchronously from remote server, by the way, the decompressed image is added to the image table after it is done.
Advantage:
  1. All images of the same dimension are stored in a single file(image table).
  2. Every image is stored with decompressing, original image never be stored.
  3. Image format can be specified before storing, so no need to format every time when using.
  4. All above prove it’s very fast to read the image and display them. 
Weakness:
  1. All images are decompressed, it takes more space to store.
  2. The image table size is limited, the big images take more size and overall reduce the number of cached image.
  3. One image with multiple formats stores in multiple copies.
  4. Need initial configuration
The implementation is common, the original image is automatically cached when downloading from remote, and decompress and resize it when it’s about to using it. 
When image request is coming, it’s going to check the cache and simply return it immediately if it can be found, or else to download asynchronously from remote server.

It’s similar to SDWebImage.

It provides two types of cache mechanism, memory cache and disk cache, it applies to cache any object. If using it, you have to check if need to download image from remote by yourself.

Monday, June 9, 2014

[iOS] Fast Image Cache

  • Stores images of similar sizes and styles together
  • Persists image data to disk
  • Returns images to the user significantly faster than traditional methods
  • Automatically manages cache expiry based on recency of usage
  • Utilizes a model-based approach for storing and retrieving images
  • Allows images to be processed on a per-model basis before being stored into the cache
Specials:
  1. It packs together images of the same dimensions to a single file.
  2. Uncompress image data to the file, so Fast Image Cache works best with smaller images.
  3. Image table size is limited, how many images can it stores that depends on the images size, it will replace the old ones when it's to add more when it's full.
  4. Image table files are stored in the user's caches directory in a subdirectory called ImageTables
  5. Does not persist the original source images
Notes:
  1. Note that it is an entity and an image format name that uniquely identifies the desired image in the image cache. As a format name uniquely identifies an image table, the entity alone uniquely identifies the desired image data in an image table.
  2. The image cache never returns a UIImage directly. The requested image is included in the completion block. The return value will indicate whether or not the image already exists in the image cache.
  3. -retrieveImageForEntity:withFormatName:completionBlock: is a synchronous method. If the requested image already exists in the image cache, the completion block will be called immediately. There is an asynchronous counterpart to this method called -asynchronouslyRetrieveImageForEntity:withFormatName:completionBlock:.
  4. If a requested image does not already exist in the image cache, then the image cache invokes the necessary actions to request the source image for its delegate. Afterwards, perhaps some time later, the completion block will be called.
  5. If an image request is already in progress, it can be cancelled.


Saturday, June 7, 2014

[iOS] Learning note: Swift new features - constant, variable, control and function

Use let to make a constant and var to make a variable

* Use if and let together to work with values that might be missing. These values are represented as optionals. An optional value either contains a value or contains nil to indicate that the value is missing. Write a question mark (?) after the type of a value to mark the value as optional
  • var optionalString: String? = "Hello"
  • optionalString == nil
  • var optionalName: String? = "John Appleseed"
  • var greeting = "Hello!"
  • if let name = optionalName {
  • greeting = "Hello, \(name)"
  • }

* Switch don't need "break" any more
  • let vegetable = "red pepper"
  • switch vegetable {
  • case "celery":
  • let vegetableComment = "Add some raisins and make ants on a log."
  • case "cucumber", "watercress":
  • let vegetableComment = "That would make a good tea sandwich."
  • case let x where x.hasSuffix("pepper"):
  • let vegetableComment = "Is it a spicy \(x)?"
  • default:
  • let vegetableComment = "Everything tastes good in soup."
  • }

You use for-in to iterate over items in a dictionary by providing a pair of names to use for each key-value pair
  • let interestingNumbers = [
  • "Prime": [2, 3, 5, 7, 11, 13],
  • "Fibonacci": [1, 1, 2, 3, 5, 8],
  • "Square": [1, 4, 9, 16, 25],
  • ]
  • var largest = 0
  • for (kind, numbers) in interestingNumbers {
  • for number in numbers {
  • if number > largest {
  • largest = number
  • }
  • }
  • }

Use a tuple to return multiple values from a function
  • func getGasPrices() -> (Double, Double, Double) {
  • return (3.59, 3.69, 3.79)
  • }

*. Functions can be nested
  • func returnFifteen() -> Int {
  • var y = 10
  • func add() {
  • y += 5
  • }
  • add()
  • return y
  • }

*. Function can return another function as its value
  • func makeIncrementer() -> (Int -> Int) {
  • func addOne(number: Int) -> Int {
  • return 1 + number
  • }
  • return addOne
  • }
  • var increment = makeIncrementer()

*. Function can take another function as one of its arguments
  • func hasAnyMatches(list: Int[], condition: Int -> Bool) -> Bool {
  • for item in list {
  • if condition(item) {
  • return true
  • }
  • }
  • return false
  • }
  • func lessThanTen(number: Int) -> Bool {
  • return number < 10
  • }
  • var numbers = [20, 19, 7, 12]
  • hasAnyMatches(numbers, lessThanTen)

*. Functions are actually a special case of closures. You can write a closure without a name by surrounding code with braces ({}). Use in to separate the arguments and return type from the body
  • numbers.map({
  • (number: Int) -> Int in
  • let result = 3 * number
  • return result
  • })
  • or
  • numbers.map({ number in 3 * number })

*. You can refer to parameters by number instead of by name
  • sort([1, 5, 3, 12, 2]) { $0 > $1 }