Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
45 views

Refactoring 12

The document discusses refactoring an iOS app to use more modern Apple APIs and development practices. Specifically, it proposes: 1. Updating URL session calls to use the Result type to handle errors instead of completion handlers. 2. Removing deprecated code like encodedOffset and scanHexInt32 that were deprecated in iOS 13. 3. Adding better test cases around errors like "No course found" using behavior-driven development.

Uploaded by

Kumar utsav
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
45 views

Refactoring 12

The document discusses refactoring an iOS app to use more modern Apple APIs and development practices. Specifically, it proposes: 1. Updating URL session calls to use the Result type to handle errors instead of completion handlers. 2. Removing deprecated code like encodedOffset and scanHexInt32 that were deprecated in iOS 13. 3. Adding better test cases around errors like "No course found" using behavior-driven development.

Uploaded by

Kumar utsav
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 32

Refactoring

1. We need good test case for No course found error , like BDD as well
2. If we are improving the url session with completion handler using Result we need to address is
Downloading flag
3. We need to use ios 12 for all the tenants as we have bumped up the min. support version
4. Build setttings for ios 12, clat tenant, setting compilation mode to incremental instead of whole
5. init(encodedOffset:)' is deprecated: encodedOffset has been deprecated as most common usage is
incorrect. Use String.Index(utf16Offset:in:) to achieve the same behavior.
6. scanHexInt32' was deprecated in iOS 13.0
7. The app icon set "AppIcon" has an unassigned child
8. Pods updating to ios 12 deployment target
9. Linting can applied using swift lint
10. Unused core-data models can be removed from the file folder
Update Header
func updateHeader() {
struct Counter { static var counter = 0 }
if let header = Bundle.main.loadNibNamed("CourseListTableViewHeader", owner: nil, op-
tions: nil)?.first as? CourseListTableViewHeader,
courseList.count > 0 {
Counter.counter += 1
let slug = Utils.getLastCourseSlug()?.cleanedSlug
if let course = fetchedResultsControler.fetchedObjects?.filter({ $0.contentPackage?.
slug == slug }).first {
header.course = course
} else {
header.course = nil
header.courseNameLabel.text = "NONE"
}
header.delegate = self
header.frame.size = CGSize(width: 0, height: 250)
tableView.tableHeaderView = header
}else if courseList.count == 0 && !hasDownloaded {
Counter.counter += 1
}
else if hasDownloaded {
Counter.counter += 1
tableView.tableHeaderView = self.noCoursesAvailableHeaderView
if(Counter.counter >= 10) {
self.noCoursesFoundLabel.isHidden = false
self.noCoursesFoundLabel.text = Constants.No_Course_Found
self.noCoursesFoundLabel.numberOfLines = 0
self.noCoursesAvailableLabel.isHidden = false
}
}
What can we do to
make it better?

1. BDD case of testing


2. Limiting the number of calls
3. Proper understanding of why it is getting used.
url session with com-
pletion handler using
Result

func download(completion: @escaping (Error?) -> Void = { error in print("Download com-


plete, error: \(error?.localizedDescription ?? "--")") }) {
if isDownloading { return }
isDownloading = true
guard var manifestURL = URL(string: "\(Constants.API_Host)/api/v1/mobile/
content_packages/\(id)/course-manifest") else {
completion(nil)
return
}
manifestURL.addJWT(andSlug: nil)
var request = URLRequest(url: manifestURL)
request.setValue("0b5705d7ba1a13ce4635920038112a73", forHTTPHeaderField: "X-
AUTHORIZATION-TOKEN")
let backgroundID = UIApplication.shared.beginBackgroundTask(withName: "Download \
(slug)") {
self.isCanceled = true
}
let context = CoreDataManager.sharedInstance.context
URLSession.shared.dataTask(with: request) { potential, response, error in
if let data = potential {
do {
let decoder = JSONDecoder()
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
decoder.dateDecodingStrategy = .formatted(formatter)
let payload = try decoder.decode(Payload.self, from: data)
let dispatchGroup = DispatchGroup()
let _ = CourseMeta.parse(id: Int32(self.id) , date: self.formattedCurrentDate(),
version: String(payload.version ?? 0), context: context)
self.downloadResources(from: payload.audios, group: dispatchGroup)
self.downloadResources(from: payload.videos, group: dispatchGroup)
self.downloadResources(from: payload.images, group: dispatchGroup)
self.downloadResources(from: payload.supplementary, group: dispatchGroup)
self.downloadResources(from: payload.thumbnails, group: dispatchGroup)
self.downloadResources(from: payload.storyline, group: dispatchGroup)
self.downloadResources(from: payload.tracks, group: dispatchGroup)
if let cssURL = payload.custom_css_url, let cacheURL = cssURL.cacheURL {
dispatchGroup.enter()
self.totalCount += 1
URLSession.shared.dataTask(with: cssURL) { data, response, error in
if let cssData = data {
FlatFileCacheManager.cacheResource(cssURL, data: cssData, mimeType:
response?.mimeType)
}
self.incrementCompletedCount()
dispatchGroup.leave()
}.resume()
}

if let brandingCssUrl = URL(string:"\(Constants.API_Host)/api/v1/branding/\


(Constants.tenantSlug)/branding.css"), let cacheUrl = brandingCssUrl.cacheURL {
dispatchGroup.enter()
self.totalCount += 1
URLSession.shared.dataTask(with: brandingCssUrl) { data, response, error in
if let cssData = data {
FlatFileCacheManager.cacheResource(brandingCssUrl, data: cssData,
mimeType: response?.mimeType)
}
self.incrementCompletedCount()
dispatchGroup.leave()
}.resume()
}
dispatchGroup.notify(queue: .main) {
Self.remove(downloader: self)
UIApplication.shared.endBackgroundTask(backgroundID)
completion(nil)
}
} catch {
print("Error while decoding manifest for \(self.slug): \(error) \n\n \(String(data: data,
encoding: .utf8) ?? "- no data received -")")
}
} else {
completion(error)
UIApplication.shared.endBackgroundTask(backgroundID)
}
}.resume()
}
Changing it using ap-
ple api Result

enum ErrorDecodingManifestFile : Error {


        case errorDecodingManifestWithNoData(forSlug: String, forData: Data)
        case errorFormingURL
  }
    
    func downloadWith(in collection: [Int]) -> Result<String?, ErrorDecodingManifestFile> {
        if isDownloading { return .success("") }
        
        isDownloading = true
        guard var manifestURL = URL(string: "\(Constants.API_Host)/api/vi/mobile/
content_packages/\(id)/course-manifest") else {
            return .failure(.errorFormingURL)
    }
        
        manifestURL.addJWT(andSlug: nil)
        var request = URLRequest(url: manifestURL)
        request.setValue("0b5705d7ba1a13ce4635920038112a73", forHTTPHeaderField: "X-
AUTHORIZATION-TOKEN")
        let backgroundID = UIApplication.shared.beginBackgroundTask(withName: "Download \
(slug)") {
            self.isCanceled = true
    }
        let context = NSManagedObjectContext(concurrencyType: .privateQueueConcurrency-
Type)
        context.parent = CoreDataManager.sharedInstance.context
        
        URLSession.shared.dataTask(with: request) { potential, response, error in
            if let data = potential {
                do {
                    let decoder = JSONDecoder()
                    let formatter = DateFormatter()
                    formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
                    decoder.dateDecodingStrategy = .formatted(formatter)
                    let payload = try decoder.decode(Payload.self, from: data)
                    let courseDetails = CourseDetails(id: String(self.id), date: self.formattedCurrent-
Date(), version: String(payload.version ?? 0))
                    let courseID = Utils.getCourseID()
                    let managedCourse = Course.parse(id: courseID, date: courseDetails.date, version:
courseDetails.version, context: context)
                    UserDefaults.standard.set(try? PropertyListEncoder().encode(courseDetails),
forKey: Constants.Course_Details)
                    let dispatchGroup = DispatchGroup()
                    self.downloadResources(from: payload.audios, group: dispatchGroup)
                    self.downloadResources(from: payload.videos, group: dispatchGroup)
                    self.downloadResources(from: payload.images, group: dispatchGroup)
                    self.downloadResources(from: payload.supplementary, group: dispatchGroup)
                    self.downloadResources(from: payload.thumbnails, group: dispatchGroup)
                    self.downloadResources(from: payload.storyline, group: dispatchGroup)
                    self.downloadResources(from: payload.tracks, group: dispatchGroup)
                    
                    if let cssURL = payload.custom_css_url, let cacheURL = css.cacheURL {
                        dispatchGroup.enter()
                        self.totalCount += 1
                        URLSession.shared.dataTask(with: cssURL) { data, response, error in
                            if let cssData = data {
                                FlatFileCacheManager.cacheResource(cssURL, data: cssData, mimeType:
response?.mimeType)
            }
                            self.incrementCompletedCount()
                            dispatchGroup.leave()
                        }.resume()
                            
                    
        }
                    if let brandingCssUrl = URL(string: "\(Constants.API_Host)/api/v1/branding/\
(Constants.tenantSlug)/branding.css"), let cacheUrl = brandingCssUrl.cacheURL {
                        dispatchGroup.enter()
                        self.totalCount += 1
                        URLSession.shared.dataTask(with: brandingCssUrl) { data, response, error in
                            if let cssData = data {
                                FlatFileCacheManager.cacheResource(brandingCssUrl, data: cssData,
mimeType: response?.mimeType)
            }
                            self.incrementCompletedCount()
                            dispatchGroup.leave()
                        }.resume()
    }
                    dispatchGroup.notify(queue: .main) {
                        Self.remove(downloader: self)
                        UIApplication.shared.endBackgroundTask(backgroundID)
                        return .success(“downloaded")
                    } catch {
return .failure(ErrorDecodingManifestFile.
errorDecodingManifestWithNoData(forSlug: slug, for data: data)
} else {
UIApplication.shared.endBackgroundTask(backgroundID)
return .failure(error)
}
}.resume()
                
  }
Type to enter text We need to
use ios 12 for all the tenants
as we have bumped up the
min. support version

We can do this from Xcode and most of the tenant have got the higher version or 12.0

1. Build setttings for ios


12, clat tenant, setting
compilation mode to in-
cremental instead of
whole

We can use Xcode to help us. Per-


form Changes click with IDE.
11.

1. The app icon set "AppIcon" has


an unassigned child . So just re-
move it from the folder
2. Pods updating to ios 12 deploy-
ment target can be done from the
pods
3. Linting can applied using swift
lint . Yes possible
4. Unused core-data models can be
removed from the file folder .
Yes possible.

init(encodedOffset:)' is deprecated: encodedOffset has been deprecated as most common usage is in-
correct. Use String.Index(utf16Offset:in:) to achieve the same behavior.
12. scanHexInt32' was deprecated in iOS 13.0

IDE can help to fix it.


Using swift-lint and running the
script is a good option for swift lint.
}

You might also like