Giter Site home page Giter Site logo

arabamcom's Introduction

Arabam.com Case 📰

I model the data I got from a advert site and transferred it to the application with async / await URLSessions. I created a detail page for the advert and showed the pictures by downloading them with Kingfisher. I made the auto layout of the application Storyboard with .xib . In addition, i made the page transitions with Hero. I hope you like.

Technologies

  • MVVM Architecture ✅
  • Storyboard and .xib ✅
  • Async/Await ✅
  • Generic URLSessions Layer ✅
  • CoreData ✅
  • CollectionView ✅
  • TableView ✅
  • Kingfisher ✅
  • Unit Test ✅

Demo

Simulator Screenshot - iPhone 14

Async / Await

protocol AdvertServiceable {
    func getAdvert(sort: Int, sortDirection: Int, take: Int) async -> Result<AdvertModel, RequestError>
    func getAdvertDetail(id: String) async -> Result<AdvertDetail, RequestError>
}

struct AdvertService: HTTPClient, AdvertServiceable {
    public static var shared = AdvertService()
    
    func getAdvert(sort: Int, sortDirection: Int, take: Int) async -> Result<AdvertModel, RequestError> {
        let endpoint = AdvertEndpoint.advertListing(sort: sort, sortDirection: sortDirection, take: take)
        return await sendRequest(endpoint: endpoint, responseModel: AdvertModel.self)
    }

    func getAdvertDetail(id: String) async -> Result<AdvertDetail, RequestError>{
        return await sendRequest(endpoint: AdvertEndpoint.advertDetail(id: id), responseModel: AdvertDetail.self)
    }
}

MainViewController-ViewModel

Uygulamanın ilk ekranında, viewModel ve viewController arasında protokol&delegate methodu ile veri taşıma işlemi gerçekleştirdim.

protocol AdvertViewModelDelegate: AnyObject {
    func didFetchData(advert: AdvertModel)
    func didFailWithError(error: Error)
}
--------------------------------------------------------
    internal func fetchData(take: Int) {
          Task(priority: .background) { [weak self] in
              guard let self = self else { return }
              do {
                  let result = await self.service.getAdvert(sort: 1, sortDirection: 0, take: take)
                  DispatchQueue.main.async { [weak self] in
                      guard let self = self else { return }
                      switch result {
                      case .success(let response):
                          self.advert = response 
                          self.delegate?.didFetchData(advert: advert) 
                      case .failure(let error):
                          self.delegate?.didFailWithError(error: error) 
                      }
                  }
              }

Burada kullanmış olduğum delegate&protokol yapısı sayesinde, viewController'a sadece .success ve .failture değerlerimi dönebiliyorum.

DetailViewController-ViewModel

Detay ekranında ise farklı bir yöntem olarak closure yapısını kullandım.

     var fetchAdvertDetail: ((AdvertDetail) -> Void)?
    
     func getData(id: String){
         fetchDetailData(id: id, successHandler: fetchAdvertDetail)
     }
     private func fetchDetailData(id: String, successHandler: ((AdvertDetail) -> Void)?) {
        Task(priority: .background) { [weak self] in
            guard let self = self else { return }
            do {
                let result = await AdvertService.shared.getAdvertDetail(id: id)
                DispatchQueue.main.async { [weak self] in
                    guard let self = self else { return }
                    switch result {
                    case .success(let response):
                        successHandler?(response)
                    case .failure(let error):
                        print(error)
                    }
                }
            }
        }
    }

Unit Test

import XCTest
@testable import ArabamCom

class MainViewModelTests: XCTestCase {
    
    var viewModel: AdvertViewModel!
    var service: MockLeagueService!
    
    override func setUp() {
        super.setUp()
        service = MockLeagueService()
        viewModel = AdvertViewModel(service: service)
    }
    func testFetchDataSuccess() async throws {
        let mockData = [
        Advert(id: 1, title: "Mock Advert 1", location: Location(cityName: "Istanbul", townName: "Kadikoy"), category: Category(id: 1, name: "Category 1"), modelName: "Model 1", price: 1000, priceFormatted: "1,000 TL", date: "2022-04-22T10:20:30Z", dateFormatted: "22 Nisan 2022", photo: "https://via.placeholder.com/150", properties: [Property(name: "Property 1", value: "Value 1"), Property(name: "Property 2", value: "Value 2")]),
        Advert(id: 2, title: "Mock Advert 2", location: Location(cityName: "Istanbul", townName: "Besiktas"), category: Category(id: 2, name: "Category 2"), modelName: "Model 2", price: 2000, priceFormatted: "2,000 TL", date: "2022-04-21T09:10:20Z", dateFormatted: "21 Nisan 2022", photo: "https://via.placeholder.com/150", properties: [Property(name: "Property 3", value: "Value 3"), Property(name: "Property 4", value: "Value 4")]),
        Advert(id: 3, title: "Mock Advert 3", location: Location(cityName: "Ankara", townName: "Cankaya"), category: Category(id: 3, name: "Category 3"), modelName: "Model 3", price: 3000, priceFormatted: "3,000 TL", date: "2022-04-20T08:09:10Z", dateFormatted: "20 Nisan 2022", photo: "https://via.placeholder.com/150", properties: [Property(name: "Property 5", value: "Value 5"), Property(name: "Property 6", value: "Value 6")])
               ]
  
        XCTAssertEqual(mockData.count, 3)
        XCTAssertEqual(mockData[0].title, "Mock Advert 1")
        XCTAssertEqual(mockData[1].modelName, "Model 2")
        XCTAssertEqual(mockData[2].category.name, "Category 3")

    }
}
class MockLeagueService: AdvertServiceable {
    
    var mockResult: Result<AdvertModel, RequestError>?
    var mockResultDetail: Result<AdvertDetail, RequestError>?
    
    func getAdvert(sort: Int, sortDirection: Int, take: Int) async -> Result<ArabamCom.AdvertModel, ArabamCom.RequestError> {
        return mockResult ?? .failure(RequestError.unknown)
    }
    
    func getAdvertDetail(id: String) async -> Result<ArabamCom.AdvertDetail, ArabamCom.RequestError> {
        return mockResultDetail ?? .failure(RequestError.unknown)
    }
}

aslında sadece burası. Yazılan diğer kodlar, taklit etme adına oluşturmuş olduğumuz yalancı bir AdvertViewModel'den ibarettir.

        XCTAssertEqual(mockData.count, 3)
        XCTAssertEqual(mockData[0].title, "Mock Advert 1")
        XCTAssertEqual(mockData[1].modelName, "Model 2")
        XCTAssertEqual(mockData[2].category.name, "Category 3")

(Bu repo güncellenecek ve favori ilanlar sekmesi eklenecektir.)

arabamcom's People

Contributors

talhavarol-dev avatar

Watchers

 avatar  avatar

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.