Thursday, October 29, 2026
HomeiOS DevelopmentiOS Swift project, can it's higher?

iOS Swift project, can it’s higher?

[ad_1]

I tend of over complicating issues, and I am scared this might be a type of instances. The code works, however is it good / scalable?

Right here is the duty: create a information aggregation app that gathers information from
a number of information sources. Every information supply needs to be thought-about a third
social gathering API that we will not change or modify.

Necessities:

  • The app ought to fetch distant information from three endpoints (information is in JSON format). Every endpoint returns a distinct format of JSON information,
    however all of them have a picture URL, title, and subtitle/textual content.
  • In any case the info is loaded, the app ought to show it in an inventory the place every merchandise has a title, subtitle, and picture.
  • The information needs to be cached. Cache stale occasions are: endpoint A – 15 sec, B – 30 sec, C – 60 sec.
  • The app ought to have a refresh possibility (e.g. pull to refresh). Refreshing ought to nonetheless respect cache stale occasions.

What will we care about:

  • Clear structure. You’ll be able to select any structure you want, e.g. MVVM.
  • Ensure that the app is extendable. What if we plan so as to add 10 extra information sources?
  • Error and edge case dealing with. What if one of many information sources didn’t load? All of them?
  • You should use any third social gathering libs you want and discover them cheap.

class Presenter {
    let sourceA = "https://res.cloudinary.com/woodspoonstaging/uncooked/add/v1645473019/assignments/mobile_homework_datasource_a_tguirv.json"
    let sourceB = "https://res.cloudinary.com/woodspoonstaging/uncooked/add/v1645473019/assignments/mobile_homework_datasource_b_x0farp.json"
    let sourceC = "https://res.cloudinary.com/woodspoonstaging/uncooked/add/v1645517666/assignments/mobile_homework_datasource_c_fqsu4l.json"
        
    let dispatchGroup = DispatchGroup()
    
    var newsItems = [NewsItem]()
    
    let notifyView = PublishSubject<Void>()
    
    public func getItems() {
        newsItems.removeAll()
        receiveSource(ofType: SourceA.self)
        receiveSource(ofType: SourceB.self)
        receiveSource(ofType: SourceC.self)
        
        dispatchGroup.notify(queue: .foremost) { [weak self] in
            guard let self = self else { return }
            self.notifyView.onNext(())
        }
    }
    
    personal func receiveSource<T:Codable>(ofType kind: T.Sort) {
        dispatchGroup.enter()
        
        swap kind {
        case is SourceA.Sort:
            let sourceParams = SourceParams(url: sourceA,
                                            key: "SourceA",
                                            expiry: 15)
            receiveSource(sourceType: kind, params: sourceParams) { [weak self] lead to
                guard let self = self else { return }
                
                swap consequence {
                case .success(let supply):
                    var array = [NewsItem]()
                    array = self.parseSourceA(supply as! SourceA)
                    self.newsItems.append(contentsOf: array)
                    self.dispatchGroup.depart()
                    
                case .failure(_):
                    self.dispatchGroup.depart()
                }
            }
        case is SourceB.Sort:
            let sourceParams = SourceParams(url: sourceB,
                                            key: "SourceB",
                                            expiry: 30)
            
            receiveSource(sourceType: kind, params: sourceParams) { [weak self] lead to
                guard let self = self else { return }
                
                swap consequence {
                case .success(let supply):
                    var array = [NewsItem]()
                    array = self.parseSourceB(supply as! SourceB)
                    self.newsItems.append(contentsOf: array)
                    self.dispatchGroup.depart()
                    
                case .failure(_):
                    self.dispatchGroup.depart()
                }
            }

        case is SourceC.Sort:
            let sourceParams = SourceParams(url: sourceC,
                                            key: "SourceC",
                                            expiry: 60)
            
            receiveSource(sourceType: kind, params: sourceParams) { [weak self] lead to
                guard let self = self else { return }
                
                swap consequence {
                case .success(let supply):
                    var array = [NewsItem]()
                    array = self.parseSourceC(supply as! SourceC)
                    self.newsItems.append(contentsOf: array)
                    self.dispatchGroup.depart()
                    
                case .failure(_):
                    self.dispatchGroup.depart()
                }
            }
        default:
            break
        }
    }
    
    personal func receiveSource<T:Codable>(sourceType: T.Sort, params: SourceParams, completion: @escaping (_ consequence: Swift.Consequence<T, Error>) -> Void) {

        // Get Parameters
        let key = params.key
        let expiry = params.expiry
        let sourceURL = params.url
        
        let diskConfig = DiskConfig(title: key, expiry: .seconds(expiry))
        let memoryConfig = MemoryConfig(expiry: .seconds(expiry))
        do {
            let storage = strive Storage(diskConfig: diskConfig,
                                       memoryConfig: memoryConfig,
                                       transformer: TransformerFactory.forCodable(ofType: sourceType))

            // Verify storage if merchandise exists & not expired
            // If true, return objects

            if strive storage.existsObject(forKey: key) && !storage.isExpiredObject(forKey: key) {
                let supply = strive storage.object(forKey: key)
                completion(.success(supply))
                
            } else { // if false, request, then return objects
                Alamofire.request(sourceURL).responseString { response in

                    do {
                        let jsonDecoder = JSONDecoder()
                        if let information = response.information {

                            let merchandise = strive jsonDecoder.decode(sourceType, from: information)
                            strive storage.setObject(merchandise, forKey: key)
                            completion(.success(merchandise))
                            return
                        }

                    } catch {
                        completion(.failure(error))
                    }
                }
            }
        } catch {
            completion(.failure(error))
        }
    }
    
    personal func parseSourceA(_ supply: SourceA) -> [NewsItem] {
        if let tales = supply.tales {
            let array = tales.map { NewsItem(title: $0.title,
                                               subtitle: $0.subtitle,
                                               picture: $0.imageUrl) }
            return array
        } else {
            return []
        }
    }
    
    personal func parseSourceB(_ supply: SourceB) -> [NewsItem] {
        
        if let objects = supply.metadata?.innerdata {
            let array = objects.map { NewsItem(title: $0.articlewrapper?.header,
                                             subtitle: $0.articlewrapper?.articlewrapperDescription,
                                             picture: $0.image) }
            return array
        } else {
            return []
        }
    }
    
    personal func parseSourceC(_ supply: SourceC) -> [NewsItem] {
        
        let array = supply.map { NewsItem(title: $0.topLine,
                                          subtitle: ($0.subLine1 ?? "") + ($0.subline2 ?? ""),
                                          picture: $0.picture) }
        return array

    }
}

[ad_2]

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments