Skip to main content
deleted 7 characters in body; edited title
Source Link
Jamal
  • 35.2k
  • 13
  • 134
  • 238

iOS Swift 3 app that requests data from stackexchange apithe Stack Exchange API

1.If the data is in RAM, get it from there,

2.Else, if it is on disk, get it from there,

3.Else, make the API request and save the data afterwards.

  1. If the data is in RAM, get it from there

  2. Else, if it is on disk, get it from there

  3. Else, make the API request and save the data afterwards

iOS Swift 3 app that requests data from stackexchange api

1.If the data is in RAM, get it from there,

2.Else, if it is on disk, get it from there,

3.Else, make the API request and save the data afterwards.

iOS Swift 3 app that requests data from the Stack Exchange API

  1. If the data is in RAM, get it from there

  2. Else, if it is on disk, get it from there

  3. Else, make the API request and save the data afterwards

added 6 characters in body
Source Link

I was asked to achieve the following memory management caching: 1

1.If the data is in RAM, get it from there, 2

2.Else, if it is on disk, get it from there, 3

3.Else, make the API request and save the data afterwards.

I was asked to achieve the following memory management caching: 1.If the data is in RAM, get it from there, 2.Else, if it is on disk, get it from there, 3.Else, make the API request and save the data afterwards.

I was asked to achieve the following memory management caching:

1.If the data is in RAM, get it from there,

2.Else, if it is on disk, get it from there,

3.Else, make the API request and save the data afterwards.

Tweeted twitter.com/StackCodeReview/status/985181000559886337
added 10 characters in body; edited tags
Source Link
Mast
  • 13.9k
  • 12
  • 57
  • 128

This is my first swiftSwift app, so I want to improve everything that I can about my code and know what I can do better. The app requests 10 developers from stackexchange apiStackExchange API and displays them in a table with the possibility to click on one of them and see more details about him.

I was asked to achieve the following memory management caching: 1.If the data is in ramRAM, get it from there, 2.Else, if it is on disk, get it from there, 3.Else, make the apiAPI request and save the data afterwards.

I'm not sure if what I did with NSCacheNSCache was good,I I mean if I have the data in my viewControllerviewController class I don't think I need to implement NSCacheNSCache because it goes in ram anyway right?I I wish to see what I can improve in this project.

ViewControllerViewController code bellow and link to githubGitHub repo:

githubGitHub repo here

import UIKit
import Alamofire
import Foundation


class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource{

@IBOutlet weak var tableView: UITableView!

private var userData = UserData()
private var clearMemoryTimer = Timer.scheduledTimer(timeInterval: 30.0*60.0, target: self, selector: #selector(clearMemory), userInfo: nil, repeats: true)
private let ramCache = NSCache<NSString,UserData>()


let param: Parameters = [
    "order": "desc",
    "max" : 10,
    "sort" : "reputation",
    "site" : "stackoverflow"
]

private var filePath:String{
    let manager = FileManager.default
    let url = manager.urls(for: .documentDirectory, in: .userDomainMask).first
    return url!.appendingPathComponent("SavedData").path
}


override func viewDidLoad() {
print("view loaded")
    
    super.viewDidLoad()
    self.loadData()

    tableView.delegate = self
    tableView.dataSource = self
    
    let nibName = UINib(nibName: "CustomTableViewCell", bundle: nil)
    tableView.register(nibName, forCellReuseIdentifier: "tableViewCell")
}


func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return self.userData.numberOfUsers()
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "tableViewCell", for: indexPath) as! CustomTableViewCell
   
    cell.commonInit(image: self.userData.userAtIndex(index: indexPath.item)!.ProfilePicImage!, labelText: self.userData.userAtIndex(index: indexPath.item)!.Username)
    
    return cell
}

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return 80
}

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    let detailViewController = DetailsUserViewController()
    detailViewController.commonInit(image: self.userData.userAtIndex(index: indexPath.item)!.ProfilePicImage!,
                                    name: self.userData.userAtIndex(index: indexPath.item)!.Username,
                                    location: self.userData.userAtIndex(index: indexPath.item)!.Location,
                                    bronzeBadges: self.userData.userAtIndex(index: indexPath.item)!.BronzeBadges,
                                    silverBadges: self.userData.userAtIndex(index: indexPath.item)!.SilverBadges,
                                    goldBadges: self.userData.userAtIndex(index: indexPath.item)!.GoldBadges)
    
    self.navigationController?.pushViewController(detailViewController, animated: true)
    self.tableView.deselectRow(at: indexPath, animated: true)
}

private func saveData(user: User) {
    self.userData.appendUser(newUser: user)
    NSKeyedArchiver.archiveRootObject(userData, toFile: filePath)  // we save on disk
    ramCache.setObject(self.userData, forKey: "Data" )
}

private func loadData() {
    if let cachedUsers = self.ramCache.object(forKey: "Data" ) {
        print("data was on ram")
        self.userData.SavedData = cachedUsers.SavedData
        
    }
    else if let savedUsers = NSKeyedUnarchiver.unarchiveObject(withFile: filePath) as? UserData {
        // check if its on disk
        print("data was on disk")
        self.userData.SavedData = savedUsers.SavedData
        ramCache.setObject(self.userData, forKey: "Data")
    } else {
        print("we requested the data")
        self.requestDataFromApi()
    }
}

func clearMemory()
{
    do{
        try FileManager.default.removeItem(atPath: filePath)
    }
    catch{
        print("Error in clearMemory()")
    }
}



private func requestDataFromApi() {
    // GET the data from the stackexchange api
    
    
    
    Alamofire.request("https://api.stackexchange.com/2.2/users", method: .get, parameters: param).responseJSON { (response) -> (Void) in
        
        if let json = response.result.value {
            // we got a result
            
            /* I know this is a bit ugly */
            let json1 = json as! [String:AnyObject]
            let usersInfoFromJSON = json1["items"] as! NSArray       // remember to cast it as NSDictionary
            
            
            for userInfo in usersInfoFromJSON {
                
                let userDict = userInfo as! NSDictionary
                
                // download user image from url
                
                Alamofire.request(userDict["profile_image"] as! String).responseData { (response) in
                    if response.error == nil {
                        
                        //print(response.result)
                        
                        if let data = response.data {
                            
                            // save the downloaded image
                            
                            let imageView = UIImageView()
                            imageView.image = UIImage(data: data)
                            
                            // check if user has location set, if not display a proper message
                            var userLocation:String=""
                            
                            if let checkLocation = (userDict["location"] as? String) {
                                userLocation = checkLocation
                            } else {
                                userLocation = "Location is not set."
                            }
                            
                            // get every badge count from the json to use it in User constructor
                            
                            let badgeCounts = userDict["badge_counts"] as? [String:Int]
                            
                            var goldb = 0
                            var bronzeb = 0
                            var silverb = 0
                            
                            if badgeCounts != nil {
                                bronzeb = badgeCounts!["bronze"]!
                                silverb = badgeCounts!["silver"]!
                                goldb   =   badgeCounts!["gold"]!
                            }
                            
                            
                            let newUser = User(username: userDict["display_name"] as! String,
                                               location: userLocation,
                                               bronzeBadges: bronzeb,
                                               silverBadges: silverb,
                                               goldBadges: goldb,
                                               profilePicUrl: userDict["profile_image"] as! String,
                                               profilePicImg: imageView.image)
                            
                            self.saveData(user: newUser)
                            
                            self.tableView.reloadData()
                            
                        }
                    }
                } // end alamofire second request
            } // end user iteration
        }
    } // end alamofire first request
}


 }

}

This is my first swift app, so I want to improve everything that I can about my code and know what I can do better. The app requests 10 developers from stackexchange api and displays them in a table with the possibility to click on one of them and see more details about him.

I was asked to achieve the following memory management caching: 1.If the data is in ram, get it from there, 2.Else, if it is on disk, get it from there, 3.Else, make the api request and save the data afterwards.

I'm not sure if what I did with NSCache was good,I mean if I have the data in my viewController class I don't think I need to implement NSCache because it goes in ram anyway right?I wish to see what I can improve in this project.

ViewController code bellow and link to github repo:

github repo here

import UIKit
import Alamofire
import Foundation


class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource{

@IBOutlet weak var tableView: UITableView!

private var userData = UserData()
private var clearMemoryTimer = Timer.scheduledTimer(timeInterval: 30.0*60.0, target: self, selector: #selector(clearMemory), userInfo: nil, repeats: true)
private let ramCache = NSCache<NSString,UserData>()


let param: Parameters = [
    "order": "desc",
    "max" : 10,
    "sort" : "reputation",
    "site" : "stackoverflow"
]

private var filePath:String{
    let manager = FileManager.default
    let url = manager.urls(for: .documentDirectory, in: .userDomainMask).first
    return url!.appendingPathComponent("SavedData").path
}


override func viewDidLoad() {
print("view loaded")
    
    super.viewDidLoad()
    self.loadData()

    tableView.delegate = self
    tableView.dataSource = self
    
    let nibName = UINib(nibName: "CustomTableViewCell", bundle: nil)
    tableView.register(nibName, forCellReuseIdentifier: "tableViewCell")
}


func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return self.userData.numberOfUsers()
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "tableViewCell", for: indexPath) as! CustomTableViewCell
   
    cell.commonInit(image: self.userData.userAtIndex(index: indexPath.item)!.ProfilePicImage!, labelText: self.userData.userAtIndex(index: indexPath.item)!.Username)
    
    return cell
}

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return 80
}

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    let detailViewController = DetailsUserViewController()
    detailViewController.commonInit(image: self.userData.userAtIndex(index: indexPath.item)!.ProfilePicImage!,
                                    name: self.userData.userAtIndex(index: indexPath.item)!.Username,
                                    location: self.userData.userAtIndex(index: indexPath.item)!.Location,
                                    bronzeBadges: self.userData.userAtIndex(index: indexPath.item)!.BronzeBadges,
                                    silverBadges: self.userData.userAtIndex(index: indexPath.item)!.SilverBadges,
                                    goldBadges: self.userData.userAtIndex(index: indexPath.item)!.GoldBadges)
    
    self.navigationController?.pushViewController(detailViewController, animated: true)
    self.tableView.deselectRow(at: indexPath, animated: true)
}

private func saveData(user: User) {
    self.userData.appendUser(newUser: user)
    NSKeyedArchiver.archiveRootObject(userData, toFile: filePath)  // we save on disk
    ramCache.setObject(self.userData, forKey: "Data" )
}

private func loadData() {
    if let cachedUsers = self.ramCache.object(forKey: "Data" ) {
        print("data was on ram")
        self.userData.SavedData = cachedUsers.SavedData
        
    }
    else if let savedUsers = NSKeyedUnarchiver.unarchiveObject(withFile: filePath) as? UserData {
        // check if its on disk
        print("data was on disk")
        self.userData.SavedData = savedUsers.SavedData
        ramCache.setObject(self.userData, forKey: "Data")
    } else {
        print("we requested the data")
        self.requestDataFromApi()
    }
}

func clearMemory()
{
    do{
        try FileManager.default.removeItem(atPath: filePath)
    }
    catch{
        print("Error in clearMemory()")
    }
}



private func requestDataFromApi() {
    // GET the data from the stackexchange api
    
    
    
    Alamofire.request("https://api.stackexchange.com/2.2/users", method: .get, parameters: param).responseJSON { (response) -> (Void) in
        
        if let json = response.result.value {
            // we got a result
            
            /* I know this is a bit ugly */
            let json1 = json as! [String:AnyObject]
            let usersInfoFromJSON = json1["items"] as! NSArray       // remember to cast it as NSDictionary
            
            
            for userInfo in usersInfoFromJSON {
                
                let userDict = userInfo as! NSDictionary
                
                // download user image from url
                
                Alamofire.request(userDict["profile_image"] as! String).responseData { (response) in
                    if response.error == nil {
                        
                        //print(response.result)
                        
                        if let data = response.data {
                            
                            // save the downloaded image
                            
                            let imageView = UIImageView()
                            imageView.image = UIImage(data: data)
                            
                            // check if user has location set, if not display a proper message
                            var userLocation:String=""
                            
                            if let checkLocation = (userDict["location"] as? String) {
                                userLocation = checkLocation
                            } else {
                                userLocation = "Location is not set."
                            }
                            
                            // get every badge count from the json to use it in User constructor
                            
                            let badgeCounts = userDict["badge_counts"] as? [String:Int]
                            
                            var goldb = 0
                            var bronzeb = 0
                            var silverb = 0
                            
                            if badgeCounts != nil {
                                bronzeb = badgeCounts!["bronze"]!
                                silverb = badgeCounts!["silver"]!
                                goldb   =   badgeCounts!["gold"]!
                            }
                            
                            
                            let newUser = User(username: userDict["display_name"] as! String,
                                               location: userLocation,
                                               bronzeBadges: bronzeb,
                                               silverBadges: silverb,
                                               goldBadges: goldb,
                                               profilePicUrl: userDict["profile_image"] as! String,
                                               profilePicImg: imageView.image)
                            
                            self.saveData(user: newUser)
                            
                            self.tableView.reloadData()
                            
                        }
                    }
                } // end alamofire second request
            } // end user iteration
        }
    } // end alamofire first request
}

}

This is my first Swift app, so I want to improve everything that I can about my code and know what I can do better. The app requests 10 developers from StackExchange API and displays them in a table with the possibility to click on one of them and see more details about him.

I was asked to achieve the following memory management caching: 1.If the data is in RAM, get it from there, 2.Else, if it is on disk, get it from there, 3.Else, make the API request and save the data afterwards.

I'm not sure if what I did with NSCache was good, I mean if I have the data in my viewController class I don't think I need to implement NSCache because it goes in ram anyway right? I wish to see what I can improve in this project.

ViewController code bellow and link to GitHub repo:

GitHub repo

import UIKit
import Alamofire
import Foundation


class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource{

@IBOutlet weak var tableView: UITableView!

private var userData = UserData()
private var clearMemoryTimer = Timer.scheduledTimer(timeInterval: 30.0*60.0, target: self, selector: #selector(clearMemory), userInfo: nil, repeats: true)
private let ramCache = NSCache<NSString,UserData>()


let param: Parameters = [
    "order": "desc",
    "max" : 10,
    "sort" : "reputation",
    "site" : "stackoverflow"
]

private var filePath:String{
    let manager = FileManager.default
    let url = manager.urls(for: .documentDirectory, in: .userDomainMask).first
    return url!.appendingPathComponent("SavedData").path
}


override func viewDidLoad() {
print("view loaded")
    
    super.viewDidLoad()
    self.loadData()

    tableView.delegate = self
    tableView.dataSource = self
    
    let nibName = UINib(nibName: "CustomTableViewCell", bundle: nil)
    tableView.register(nibName, forCellReuseIdentifier: "tableViewCell")
}


func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return self.userData.numberOfUsers()
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "tableViewCell", for: indexPath) as! CustomTableViewCell
   
    cell.commonInit(image: self.userData.userAtIndex(index: indexPath.item)!.ProfilePicImage!, labelText: self.userData.userAtIndex(index: indexPath.item)!.Username)
    
    return cell
}

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return 80
}

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    let detailViewController = DetailsUserViewController()
    detailViewController.commonInit(image: self.userData.userAtIndex(index: indexPath.item)!.ProfilePicImage!,
                                    name: self.userData.userAtIndex(index: indexPath.item)!.Username,
                                    location: self.userData.userAtIndex(index: indexPath.item)!.Location,
                                    bronzeBadges: self.userData.userAtIndex(index: indexPath.item)!.BronzeBadges,
                                    silverBadges: self.userData.userAtIndex(index: indexPath.item)!.SilverBadges,
                                    goldBadges: self.userData.userAtIndex(index: indexPath.item)!.GoldBadges)
    
    self.navigationController?.pushViewController(detailViewController, animated: true)
    self.tableView.deselectRow(at: indexPath, animated: true)
}

private func saveData(user: User) {
    self.userData.appendUser(newUser: user)
    NSKeyedArchiver.archiveRootObject(userData, toFile: filePath)  // we save on disk
    ramCache.setObject(self.userData, forKey: "Data" )
}

private func loadData() {
    if let cachedUsers = self.ramCache.object(forKey: "Data" ) {
        print("data was on ram")
        self.userData.SavedData = cachedUsers.SavedData
        
    }
    else if let savedUsers = NSKeyedUnarchiver.unarchiveObject(withFile: filePath) as? UserData {
        // check if its on disk
        print("data was on disk")
        self.userData.SavedData = savedUsers.SavedData
        ramCache.setObject(self.userData, forKey: "Data")
    } else {
        print("we requested the data")
        self.requestDataFromApi()
    }
}

func clearMemory()
{
    do{
        try FileManager.default.removeItem(atPath: filePath)
    }
    catch{
        print("Error in clearMemory()")
    }
}



private func requestDataFromApi() {
    // GET the data from the stackexchange api
    
    
    
    Alamofire.request("https://api.stackexchange.com/2.2/users", method: .get, parameters: param).responseJSON { (response) -> (Void) in
        
        if let json = response.result.value {
            // we got a result
            
            /* I know this is a bit ugly */
            let json1 = json as! [String:AnyObject]
            let usersInfoFromJSON = json1["items"] as! NSArray       // remember to cast it as NSDictionary
            
            
            for userInfo in usersInfoFromJSON {
                
                let userDict = userInfo as! NSDictionary
                
                // download user image from url
                
                Alamofire.request(userDict["profile_image"] as! String).responseData { (response) in
                    if response.error == nil {
                        
                        //print(response.result)
                        
                        if let data = response.data {
                            
                            // save the downloaded image
                            
                            let imageView = UIImageView()
                            imageView.image = UIImage(data: data)
                            
                            // check if user has location set, if not display a proper message
                            var userLocation:String=""
                            
                            if let checkLocation = (userDict["location"] as? String) {
                                userLocation = checkLocation
                            } else {
                                userLocation = "Location is not set."
                            }
                            
                            // get every badge count from the json to use it in User constructor
                            
                            let badgeCounts = userDict["badge_counts"] as? [String:Int]
                            
                            var goldb = 0
                            var bronzeb = 0
                            var silverb = 0
                            
                            if badgeCounts != nil {
                                bronzeb = badgeCounts!["bronze"]!
                                silverb = badgeCounts!["silver"]!
                                goldb   =   badgeCounts!["gold"]!
                            }
                            
                            
                            let newUser = User(username: userDict["display_name"] as! String,
                                               location: userLocation,
                                               bronzeBadges: bronzeb,
                                               silverBadges: silverb,
                                               goldBadges: goldb,
                                               profilePicUrl: userDict["profile_image"] as! String,
                                               profilePicImg: imageView.image)
                            
                            self.saveData(user: newUser)
                            
                            self.tableView.reloadData()
                            
                        }
                    }
                } // end alamofire second request
            } // end user iteration
        }
    } // end alamofire first request
}


 }
Source Link
Loading