|  | 
|  | 1 | +// | 
|  | 2 | +//  AppData.swift | 
|  | 3 | +//  TechStacks | 
|  | 4 | +// | 
|  | 5 | +//  Created by Demis Bellot on 2/3/15. | 
|  | 6 | +//  Copyright (c) 2015 ServiceStack LLC. All rights reserved. | 
|  | 7 | +// | 
|  | 8 | + | 
|  | 9 | +import UIKit | 
|  | 10 | +import Foundation | 
|  | 11 | + | 
|  | 12 | + | 
|  | 13 | +public class AppData : NSObject | 
|  | 14 | +{ | 
|  | 15 | +    var client = JsonServiceClient(baseUrl: "http://techstacks.io") | 
|  | 16 | +     | 
|  | 17 | +    struct Property { | 
|  | 18 | +        static let TopTechnologies = "topTechnologies" | 
|  | 19 | +        static let AllTiers = "allTiers" | 
|  | 20 | +        static let AllTechnologies = "allTechnologies" | 
|  | 21 | +        static let AllTechnologyStacks = "allTechnologyStacks" | 
|  | 22 | +    } | 
|  | 23 | +     | 
|  | 24 | +    public dynamic var allTiers:[Option] = [] | 
|  | 25 | +     | 
|  | 26 | +    public dynamic var overview:AppOverviewResponse = AppOverviewResponse() | 
|  | 27 | +    public dynamic var topTechnologies:[TechnologyInfo] = [] | 
|  | 28 | +     | 
|  | 29 | +    public dynamic var allTechnologies:[Technology] = [] | 
|  | 30 | +    public dynamic var allTechnologyStacks:[TechnologyStack] = [] | 
|  | 31 | +     | 
|  | 32 | +    public dynamic var search:String? | 
|  | 33 | +    public dynamic var filteredTechStacks:[TechnologyStack] = [] | 
|  | 34 | +    public dynamic var filteredTechnologies:[Technology] = [] | 
|  | 35 | +     | 
|  | 36 | +    public var technologyStackCache:[String:GetTechnologyStackResponse] = [:] | 
|  | 37 | +    public var technologyCache:[String:GetTechnologyResponse] = [:] | 
|  | 38 | +     | 
|  | 39 | +    override init(){ | 
|  | 40 | +        super.init() | 
|  | 41 | +        self.loadDefaultImageCaches() | 
|  | 42 | +    } | 
|  | 43 | +     | 
|  | 44 | +    func loadOverview() -> Promise<AppOverviewResponse> { | 
|  | 45 | +        return client.getAsync(AppOverview()) | 
|  | 46 | +            .then(body:{(r:AppOverviewResponse) -> AppOverviewResponse in | 
|  | 47 | +                self.overview = r | 
|  | 48 | +                self.allTiers = r.allTiers | 
|  | 49 | +                self.topTechnologies = r.topTechnologies | 
|  | 50 | +                return r | 
|  | 51 | +            }) | 
|  | 52 | +    } | 
|  | 53 | +     | 
|  | 54 | +    func loadAllTechnologies() -> Promise<GetAllTechnologiesResponse> { | 
|  | 55 | +        return client.getAsync(GetAllTechnologies()) | 
|  | 56 | +            .then(body:{(r:GetAllTechnologiesResponse) -> GetAllTechnologiesResponse in | 
|  | 57 | +                self.allTechnologies = r.results | 
|  | 58 | +                return r | 
|  | 59 | +            }) | 
|  | 60 | +    } | 
|  | 61 | +     | 
|  | 62 | +    func loadAllTechStacks() -> Promise<GetAllTechnologyStacksResponse> { | 
|  | 63 | +        return client.getAsync(GetAllTechnologyStacks()) | 
|  | 64 | +            .then(body:{(r:GetAllTechnologyStacksResponse) -> GetAllTechnologyStacksResponse in | 
|  | 65 | +                self.allTechnologyStacks = r.results | 
|  | 66 | +                return r | 
|  | 67 | +            }) | 
|  | 68 | +    } | 
|  | 69 | +     | 
|  | 70 | +    func loadTechnologyStack(slug:String) -> Promise<GetTechnologyStackResponse> { | 
|  | 71 | +        if let response = technologyStackCache[slug] { | 
|  | 72 | +            return Promise<GetTechnologyStackResponse> { (complete,reject) in complete(response) } | 
|  | 73 | +        } | 
|  | 74 | +         | 
|  | 75 | +        var request = GetTechnologyStack() | 
|  | 76 | +        request.slug = slug | 
|  | 77 | +        return client.getAsync(request) | 
|  | 78 | +            .then(body:{ (r:GetTechnologyStackResponse) -> GetTechnologyStackResponse in | 
|  | 79 | +                self.technologyStackCache[r.result!.slug!] = r | 
|  | 80 | +                return r | 
|  | 81 | +            }) | 
|  | 82 | +    } | 
|  | 83 | +     | 
|  | 84 | +    func searchTechStacks(query:String) -> Promise<QueryResponse<TechnologyStack>> { | 
|  | 85 | +        self.search = query | 
|  | 86 | +         | 
|  | 87 | +        let request = FindTechStacks<TechnologyStack>() | 
|  | 88 | +        return client.getAsync(request, query:["NameContains":query, "DescriptionContains":query]) | 
|  | 89 | +            .then(body:{(r:QueryResponse<TechnologyStack>) -> QueryResponse<TechnologyStack> in | 
|  | 90 | +                self.filteredTechStacks = r.results | 
|  | 91 | +                return r | 
|  | 92 | +            }) | 
|  | 93 | +    } | 
|  | 94 | +     | 
|  | 95 | +    func loadTechnology(slug:String) -> Promise<GetTechnologyResponse> { | 
|  | 96 | +        if let response = technologyCache[slug] { | 
|  | 97 | +            return Promise<GetTechnologyResponse> { (complete,reject) in complete(response) } | 
|  | 98 | +        } | 
|  | 99 | +         | 
|  | 100 | +        var request = GetTechnology() | 
|  | 101 | +        request.slug = slug | 
|  | 102 | +        return client.getAsync(request) | 
|  | 103 | +            .then(body:{ (r:GetTechnologyResponse) -> GetTechnologyResponse in | 
|  | 104 | +                self.technologyCache[r.technology!.slug!] = r | 
|  | 105 | +                return r | 
|  | 106 | +            }) | 
|  | 107 | +    } | 
|  | 108 | +     | 
|  | 109 | +    func searchTechnologies(query:String) -> Promise<QueryResponse<Technology>> { | 
|  | 110 | +        self.search = query | 
|  | 111 | +         | 
|  | 112 | +        let request = FindTechnologies<Technology>() | 
|  | 113 | +        return client.getAsync(request, query:["NameContains":query, "DescriptionContains":query]) | 
|  | 114 | +            .then(body:{(r:QueryResponse<Technology>) -> QueryResponse<Technology> in | 
|  | 115 | +                self.filteredTechnologies = r.results | 
|  | 116 | +                return r | 
|  | 117 | +            }) | 
|  | 118 | +    } | 
|  | 119 | + | 
|  | 120 | +    var imageCache:[String:UIImage] = [:] | 
|  | 121 | +    func loadDefaultImageCaches() { | 
|  | 122 | +        imageCache["stacks"] = UIImage(named: "stacks") | 
|  | 123 | + | 
|  | 124 | +        UIGraphicsBeginImageContextWithOptions(CGSizeMake(858, 689), false, 0.0) | 
|  | 125 | +        imageCache["blankScreenshot"] = UIGraphicsGetImageFromCurrentImageContext() | 
|  | 126 | +        UIGraphicsEndImageContext() | 
|  | 127 | +    } | 
|  | 128 | +     | 
|  | 129 | +    public func loadAllImagesAsync(urls:[String]) -> Promise<[String:UIImage?]> { | 
|  | 130 | +        var images = [String:UIImage?]() | 
|  | 131 | +        return Promise<[String:UIImage?]> { (complete, reject) in | 
|  | 132 | +            for url in urls { | 
|  | 133 | +                self.loadImageAsync(url) | 
|  | 134 | +                    .then(body: { (img:UIImage?) -> Void in | 
|  | 135 | +                        images[url] = img | 
|  | 136 | +                        if images.count == urls.count { | 
|  | 137 | +                            return complete(images) | 
|  | 138 | +                        } | 
|  | 139 | +                    }) | 
|  | 140 | +            } | 
|  | 141 | +        } | 
|  | 142 | +    } | 
|  | 143 | +     | 
|  | 144 | +    public func loadImageAsync(url:String) -> Promise<UIImage?> { | 
|  | 145 | +        if let image = imageCache[url] { | 
|  | 146 | +            return Promise<UIImage?> { (complete, reject) in complete(image) } | 
|  | 147 | +        } | 
|  | 148 | +         | 
|  | 149 | +        return client.getDataAsync(url) | 
|  | 150 | +            .then(body: { (data:NSData) -> UIImage? in | 
|  | 151 | +                if let image = UIImage(data:data) { | 
|  | 152 | +                    self.imageCache[url] = image | 
|  | 153 | +                    return image | 
|  | 154 | +                } | 
|  | 155 | +                return nil | 
|  | 156 | +            }) | 
|  | 157 | +    } | 
|  | 158 | +     | 
|  | 159 | +    /* KVO Observable helpers */ | 
|  | 160 | +    var observedProperties = [NSObject:[String]]() | 
|  | 161 | +    var ctx:AnyObject = 1 | 
|  | 162 | +     | 
|  | 163 | +    public func observe(observer: NSObject, properties:[String]) { | 
|  | 164 | +        for property in properties { | 
|  | 165 | +            self.observe(observer, property: property) | 
|  | 166 | +        } | 
|  | 167 | +    } | 
|  | 168 | +     | 
|  | 169 | +    public func observe(observer: NSObject, property:String) { | 
|  | 170 | +        self.addObserver(observer, forKeyPath: property, options: .New | .Old, context: &ctx) | 
|  | 171 | +         | 
|  | 172 | +        var properties = observedProperties[observer] ?? [String]() | 
|  | 173 | +        properties.append(property) | 
|  | 174 | +        observedProperties[observer] = properties | 
|  | 175 | +    } | 
|  | 176 | +     | 
|  | 177 | +    public func unobserve(observer: NSObject) { | 
|  | 178 | +        if let properties = observedProperties[observer] { | 
|  | 179 | +            for property in properties { | 
|  | 180 | +                self.removeObserver(observer, forKeyPath: property, context: &ctx) | 
|  | 181 | +            } | 
|  | 182 | +        } | 
|  | 183 | +    } | 
|  | 184 | +     | 
|  | 185 | +    //Clear caches if we receive memory warning | 
|  | 186 | +    func resetCache() { | 
|  | 187 | +        imageCache = [:] | 
|  | 188 | +        technologyStackCache = [:] | 
|  | 189 | +        technologyCache = [:] | 
|  | 190 | +        loadDefaultImageCaches() | 
|  | 191 | +    } | 
|  | 192 | +     | 
|  | 193 | +} | 
0 commit comments