Skip to content

Instantly share code, notes, and snippets.

@seanlilmateus
Last active December 15, 2015 17:29
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save seanlilmateus/5296635 to your computer and use it in GitHub Desktop.
Save seanlilmateus/5296635 to your computer and use it in GitHub Desktop.
Countries example using Concurrency
class AppDelegate
def application(application, didFinishLaunchingWithOptions:launchOptions)
@window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds).tap do |win|
win.rootViewController = UINavigationController.alloc.initWithRootViewController(CountriesController.new)
win.backgroundColor = UIColor.whiteColor
win.makeKeyAndVisible
end
true
end
end
class ArrayController
def initialize(array)
objects_collation NSArray.arrayWithArray(array.dup)
end
def sections
@collection
end
def objectAtIndexPath(indexPath)
@collection[indexPath.section][indexPath.row]
end
alias_method :[], :objectAtIndexPath
def sectionIndexTitleForSectionName(section_name)
@collection[section_name.upcase]
end
def sectionAtIndex(id)
@collection[id] || []
end
def sectionIndexTitles
UILocalizedIndexedCollation.currentCollation.sectionTitles
end
def objects_collation(input)
selector = :name
index = sectionTitlesCount = UILocalizedIndexedCollation.currentCollation.sectionTitles.count
collation = UILocalizedIndexedCollation.currentCollation
mutable_sections = Array.new(sectionTitlesCount) { [] }
input.each do |object|
section_number = UILocalizedIndexedCollation.currentCollation.sectionForObject(object, collationStringSelector:selector)
mutable_sections[section_number] << object if object.is_a?(Country)
end
Dispatch::Queue.concurrent.apply(sectionTitlesCount) do |idx|
objects_for_section = mutable_sections[idx]
object = UILocalizedIndexedCollation.currentCollation.sortedArrayFromArray(objects_for_section, collationStringSelector:selector)
mutable_sections.replaceObjectAtIndex(idx, withObject:object)
end
@collection = mutable_sections
end
end
class CountriesController < UITableViewController
def init
super.tap do
country_codes = NSLocale.ISOCountryCodes
locale = NSLocale.currentLocale
countries = country_codes.map do |iso_code|
country_name = locale.displayNameForKey(NSLocaleCountryCode, value:iso_code)
hash = { name: country_name, iso_code: iso_code }
Country.new hash
end
@countries = ArrayController.new(countries)
end
end
IDENTIFIER = "Countries Cell identifier"
def viewDidLoad
super
@image_queue = Dispatch::Queue.concurrent('de.mateus.image')
@image_op_queue = NSOperationQueue.new
@image_op_queue.name = ('de.mateus.image')
self.tableView.registerClass(UITableViewCell, forCellReuseIdentifier:IDENTIFIER)
self.tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLineEtched
end
def numberOfSectionsInTableView(tbv)
@countries.sections.count
end
def tableView(tbv, numberOfRowsInSection:section)
@countries.sectionAtIndex(section).count
end
def sectionIndexTitlesForTableView(tbv)
@countries.sectionIndexTitles
end
def tableView(tbv, didSelectRowAtIndexPath:indexPath)
tbv.deselectRowAtIndexPath(indexPath, animated:true)
end
def tableView(tbv, titleForHeaderInSection:section)
@countries.sectionIndexTitles[section]
end
# A..Z#
def tableView(tbv, sectionForSectionIndexTitle:title, atIndex:index)
UILocalizedIndexedCollation.currentCollation.sectionForSectionIndexTitleAtIndex(index)
end
# to test the differents versions, you'll have to change the name of the tableView:cellForRowAtIndexPath: methods
def tableView(tbv, cellForRowAtIndexPath:indexPath)
tbv.dequeueReusableCellWithIdentifier(IDENTIFIER, forIndexPath:indexPath).tap do |cell|
country = @countries[indexPath]
cell.text = country.name
country.flag_image = UIImage.imageNamed(country.iso_code)
country.flag_image ||= UIImage.imageNamed('_united-nations')
cell.imageView.image = country.flag_image
end
end
# slow scrolling due of apply CIFilter in the Main Screen
def _1_tableView(tbv, cellForRowAtIndexPath:indexPath)
tbv.dequeueReusableCellWithIdentifier(IDENTIFIER, forIndexPath:indexPath).tap do |cell|
country = @countries[indexPath]
cell.text = country.name
country.flag_image ||= begin
image = UIImage.imageNamed(country.iso_code) || UIImage.imageNamed('_united-nations')
_, sepia_image = applySepiaFilter(image, indexPath)
sepia_image
end
cell.imageView.image = country.flag_image
end
end
# The GCD version may be a little buggy, sometimes you'll need to scroll to update the images
def _2_tableView(tbv, cellForRowAtIndexPath:indexPath)
tbv.dequeueReusableCellWithIdentifier(IDENTIFIER, forIndexPath:indexPath).tap do |cell|
country = @countries[indexPath]
country.indexPath = indexPath
cell.text = country.name
unless country.flag_image
@image_queue.async do
image = UIImage.imageNamed(country.iso_code) || UIImage.imageNamed('_united-nations')
index, sepia_image = applySepiaFilter(image, indexPath)
Dispatch::Queue.main.async do
@countries[index].flag_image = sepia_image
tbv.reloadRowsAtIndexPaths([index], withRowAnimation:UITableViewRowAnimationNone)
end
end
end
cell.imageView.image = country.flag_image
end
end
# NSOperationQueue Solution
def _3_tableView(tbv, cellForRowAtIndexPath:indexPath)
tbv.dequeueReusableCellWithIdentifier(IDENTIFIER, forIndexPath:indexPath).tap do |cell|
country = @countries[indexPath]
cell.text = country.name
unless country.flag_image
@image_op_queue.addOperationWithBlock(-> do
image = UIImage.imageNamed(country.iso_code) || UIImage.imageNamed('_united-nations')
index, sepia_image = applySepiaFilter(image, indexPath)
@countries[index].flag_image = sepia_image
operation = NSBlockOperation.blockOperationWithBlock(-> {
tbv.reloadRowsAtIndexPaths([indexPath], withRowAnimation:UITableViewRowAnimationNone)
})
NSOperationQueue.mainQueue.addOperations([operation], waitUntilFinished:false)
end)
end
cell.imageView.image = country.flag_image
end
end
# Applies a Sepia CIFilter to given image, on the indexPath
# We need the indexPath to track the image and row
def applySepiaFilter(input_image, indexPath)
cii_image = CIImage.alloc.initWithImage(input_image)
filter = CIFilter.filterWithName("CISepiaTone")
filter.setDefaults
filter.setValue(cii_image, forKey:"inputImage")
filter.setValue(0.8, forKey:"inputIntensity")
output_image = filter.valueForKey('outputImage')
context = CIContext.contextWithOptions(nil)
image_ref = context.createCGImage(output_image, fromRect:output_image.extent)
[indexPath, UIImage.imageWithCGImage(image_ref)]
end
end
class Country
attr_accessor :name, :iso_code, :flag_image
def initialize(dictionary={})
setValuesForKeysWithDictionary(dictionary) if dictionary.is_a?(Hash)
end
def setValue(value, forUndefinedKey:key); end
end
@seanlilmateus
Copy link
Author

the flags can be downloaded from here: https://www.gosquared.com/resources/flag-icons
you'll need the flags-iso/shiny/64 inside the zip file,
array_controller.rb is a helper I created for the UILocalizedIndexedCollation

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment