Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to organize files in Xcode for iOS development using Swift?

Tags:

xcode

ios

swift

How should I organize my files (controllers, models, helpers, etc.) in folders using Xcode and what's the best way of accessing them?

enter image description here

like image 358
Gagandeep Gambhir Avatar asked Jan 04 '23 21:01

Gagandeep Gambhir


1 Answers

Follow the MVC Structure Like this below images

enter image description here

Aft er opening file structure, project should be like below

enter image description here

Home structure, containing all VC's that are in HomeStoryboard(here, main storyboard)

enter image description here

NOTE: Same structure must be followed in physical directory.

Reference: https://developer.apple.com/library/content/documentation/General/Conceptual/DevPedia-CocoaCore/MVC.html

Edit

File organisation is a fundamental method to keep you files in folder like there are books on shelf,I mean same subject book on same row type.

Accessing file doesn't matter on your file hierarchy. If file is added in your project directory, then x-code automatically recognise your files and suggest you accordingly.

for every file you have to make init method to make that file into memory, or you can override init method.

Take ref : https://medium.com/ios-objective-creation/lesson-2-creating-custom-classes-in-objective-c-17f760ce9732


Edit (27 Mar 2019)

Now I am doing with this new pattern and this helped me alot.

Now you do not need MVC folder, I mean add Model , View , Controller in parent directory and remove MVC dir. Check below

enter image description here

Here is the brief explanation of every topic.

  1. Extension : It adds new functionality to instances. I keep all extensions here and every file name is the type of the extension I am using. Check below

enter image description here

  1. Resources : It contains resources that gonna used in project , like mp3 samples. gifs etc.

enter image description here

  1. Utility : I use utility of common functions that will be used through the app like string encoding-decoding , get UDID, web-services and will categories them accordingly.

Here below, Device.swift file have device related functions like Is_Ipad , is_iPhone6_7_8 etc.

enter image description here

  1. CallAPI : As My project have 100+ APIs so its very complex to keep all these calls in one file. So I keep separate section for this and categorize APIs according to their module. With this I added one extra layer for API calls so that it can be managed easily and its reusability also increased.

CallAPI+Home is the extension of APIs for the Home module. Every module have separate extensions. Its working is described in last.

enter image description here

  1. Helper : It contains all code that are used as a helping hand, like enums, structs, constants etc.

enter image description here

  1. Model : It contains view-model (customise model for views) and API-model (API data model) and NSManagedObjectModel (not added right now).

enter image description here

  1. Views : It contains all the TableViewCell and CollectionViewCell and other customise classes of UILabel, UIView etc and popups (xibs and files).

enter image description here

  1. Controller : All controllers like UIViewController, UITableViewController, UITabBarController etc. Controllers are categorised modules-wise.

enter image description here

enter image description here

  1. Storyboard : Every storyboard categorize into module-wise. Might be some modules have multiple storyboard.

enter image description here


If your App is small then you can skip this part and directly use API's from Utility.

How does APICall works?

Flow Diagram

enter image description here

1. First controller calls CallAPI, every API have its own func to get data and bind into it model.
2. CallAPI calls Webservices and decides type of API (post, get).
3. WebServices have alomofire call service. It gets data from service and return back to Call API.
4. If API result success, then CallAPI binds model data else it shows error alert.
5. Now Model data is returned to the Call API.
6. Now callAPi returns Model data to controller.

Some sample code

  • In controller,

    func validateUserAPI(){
        guard self.isValidateTF() else {
            return
        }
    
        let param = [ "sPassword": Common.encodeBase64(withOutPass: tfPassword.text!)!,
                      "sUserName": Common.encodeBase64(withOutPass: tfUsername.text!)!
            ] as [String : Any]
    
        // Validate User
        CallAPI.submitValidateUser(params: param) { [weak self] (submitResult) in
            guard let aSelf = self else {return}
            let aResultValidate = submitResult.validateUserResult[0]
            if aResultValidate.status == 0 {
                Alert.showAlertError(title: "Error", body: aResultValidate.message)
            }
            else {
                // save data to user defaults
    
            }
        }
    }
    
  • In CallAPI, I have created success handling only, if failure handler is required then create it too.

    extension CallAPI {
        class func submitValidateUser( params: [String : Any], completionHandler: @escaping ((LoginValidateUser) -> Void)) {
            HUD.startIndeterminate("Loading...")
            WebService.postAlamofire(API.ValidateUser, params: params) { (errMsg, result) in
                HUD.stopIndeterminate()
                if result.isSuccess {
                    // If data success, bind data into model and return back to controller
                    let resultModel = LoginValidateUser(fromDictionary: result.value! as! [String : Any])
                    completionHandler(resultModel)
                }
                else {
                    Alert.showAlertError(title: "Error", body: errMsg!)
                }
            }
        }
    }
    
  • In web-services,

    class WebService {
    
        class func getAlamofire(_ url : String, completionHandler: @escaping (( String?, Result<Any>) -> Void) ){
    
            Alamofire.request(url, method: .get, parameters: nil, encoding: JSONEncoding.default, headers: nil).responseJSON { (jsonResult) in
    
                completionHandler((jsonResult.error?.localizedDescription),jsonResult.result)
    
            }
        }
    
        class func postAlamofire(_ url : String, params: [String:Any], completionHandler: @escaping (( String?, Result<Any>) -> Void) ){
            print("************************************")
            print("************************************")
            print("URL ----> \(url)")
            print("INPUT ----> \(params)")
    
            Alamofire.request(url, method: .post, parameters: params, encoding: JSONEncoding.default, headers: nil).responseJSON { (jsonResult) in
                print("OUTPUT ---->")
                print(jsonResult.result.value)
                completionHandler((jsonResult.error?.localizedDescription),jsonResult.result)
            }
        }
    }
    
  • In helper I created struct, here one struct is for API lists.

    struct API {
        static let ValidateUser             = "\(kBaseURL)ValidateUser"
    }
    
like image 196
dahiya_boy Avatar answered Feb 14 '23 20:02

dahiya_boy