Hello!!
Hope all good.
Let me introduce my Wreely - Community Platform app architecture to you guys that How I implemented it using swift 4.1 language along with view
, presenter
and protocols
way to architect this app.
NOTE: This is not a tutorial for any kind of architectural setup (While I’m trying it should be but for now it is not looking like that). It is just an overview of my current project architecture which I’m sharing to keep track of my swift project standards and reference for colleagues.
Before starting app design pattern, architecture & all let me share Tools
I have used in this project.
- Slack
For centralized project communication
- Trello
For project initial to-do list, list of project screen along with use cases for each screen, future plan etc
- GitLab Issues
For project issue tracking (Kanban style board)
- GitLab CI
For continuous integration
- GitLab
For version control
- Codacy
For code review
Now as per below list of GitLab issue list I will explain what I had done in that issue commit using issue number.
- Initial project setup
- Setup network, database, analytics and basic utility library via dependency manager
CocoaPods
- Setup network connection manager via
Alamofire
as a base library - Setup database connection manager to persist data from remote server -
Not yet implemented
- Setup class model as per network response using
Mappable
- Setup initial extensions for native controls & class
- Setup helper class for logger, theme, analytics, error, constant and session
- Setup base class and protocols for inbuilt view controllers and UI classes
Initial project setup
- Created project via latest Xcode with init git repo
- Folder structure as below -
Improving it every day
- Except for root and test folder all other folder name starts with
WS
(project initial)
Setup network, database, analytics and basic utilities library via dependency manager
For dependency manager, I have used CocoaPods
The content of Podfile as below - Improving it every day
Setup network connection manager via Alamofire as base library
It includes implementation of below:
Create API request class which handle common HTTP request parameter like below
- Url string
- Http Method
- Request parameter
- Post Data (For image or any binary data)
- Pass success/failure closure so once network connection manager get a response from the server it will inform this class
Filename Standard: Project two main initial capital word(2 Letters) + APIRequest i.e If your project name is Facebook then name should be FBAPIRequest
Other utilities this class handles:
- Request pagination (page number and per page)
- Which core data or realm model should be used based on a request type
- Create detail error dictionary return method because here only you are getting request parameter and response object
Create network connection manager class
- Initiate HTTP session manager class from here based on a request parameters getting from API request
- Pass success/failure closure so once session manager get a response from the server it will inform this class
- This class must synthesize(get/set) a singleton class of self
- Once got a response via session manager class handle it here and call a database manager (singleton class) response handler method
Other utilities this class handles:
- Network reachability implementation
- Which request should read or not like for login and sign up it should not check for a valid session for all other requests you should check for a valid token before performing it
Create HTTP session manager class (Should inherit from SessionManager- Alamofire if you are using it)
- Perform actual network request via the third party library i.e Alamofire or Apple native one to handle session request
- Perform GET, POST, PUT etc based on API Request class details
- Get the full path of URL using API Request class and constant base URL
Setup database connection manager to persist data from remote server
For now for persistent storage I have not implemented core data implementation in Wreely app but it is in the queue may be after completion of app remaining feature & optimization will do this.
Still, let me explain to you guys that how I will going to implement that soon. If your app is fairly static so it is good to implement persistence storage otherwise at the end it’s your choice but remember via below implementation you have to maintain below code which indirectly invites hidden or unwanted bugs which you will only have to maintain.
Below few steps I will perform for database manager implementation.
-
Create database manager class with name standard i.e Project two main initial letter + DatabaseManager So if your project name is facebook so name it as
FBDatabaseManager
-
FBDatabaseManager
should implement things of core data to handle the response- Database version (get it via app version)
- Manage object context (Learn about NSManageObjectContext)
- Persistent store coordinator (Learn about NSPersistentStoreCoordinator)
- Manage object model (Learn about NSManageObjectModel)
- Clean up previous database response
- Singleton class for shared db manager
- Save context method for core data
- During init create
NSManageObjectContext
object withNSMainQueueConcurrencyType
along with merge policies and self persistent store coordinator and also implement default app related data insert function task likeGender
,Relationship Status
,Months
etc during this init - Perform all save operation of core data model via
NSManageObjectContext
object should be inasynchronous execution on a dispatch queue
withDISPATCH_QUEUE_SERIAL
queue option - Now finally write handle response function along with API request object so parse it based in API request type
This parser function should be like below:
- Get a managedObjectContext object from shared DB manager
- Get parent manage-object from based on API request object
- Write one more method to customize response object to get a proper dictionary or array object for inserting into the database
- Finally, save it into core data based on array result from the above step
Setup class model as per network response using Mappable
As previously in Objective-C I always create a model using Interfaces
but in swift, I mostly use Struct
as because of it’s immutable behavior and allocation on the stack. (As we know stack is used for static memory allocation and Heap for dynamic. Variables allocated on the stack are stored directly to the memory and access to this memory is very fast).
Check below struct model as used in the project for User
model
Setup initial extensions for native controls & class
Swift has the amazing set of open source extensions library which you can use via dependency manager CocoaPods or Carthage.
Few good libraries for extensions are as below:
In Wreely based on type, I have created project necessary extensions only as per below folder structure.
Soon will open source this project then you can easily see the content of these extensions and all other files.
Setup helper class for logger, analytics, error and session
Logger
My logger class as below which depend on Log library - An extensible color logging framework for Swift:
How to use:
Call below WSLogger class method directly from anywhere along with optional error type:
WSLogger.log(errorMessage, logType: .kError)
Analytics
Customized analytics class for this project which cover OneSignal
, Mixpanel
, Answers
and Firebase
via one method.
How to use:
One should call WSTracking.sharedTracking.setupInitialTracking()
from login or signup or any start controller after initialization of all supported analytics library in appDelegate
Error handle
Error handler helper class as below which used in the project.
How to use:
You have to initialize WSError object with customize message as below:
let error: LocalizedDescriptionError = WSError.customError(message: "Custom error here")
Later call default localizedDescription
protocol method to get this custom message.
print(error.localizedDescription)
Session management
Wreely session management fully depends on user-based access_token
key of UserDefault object. If exist it will fetch user details from the server during splash screen load and if not it will skip to OTP login screen.
All other internal endpoints need this access_token
to get a valid response.
See below implementation of WSSession class
How to use:
- After successful access token response from server save it on session class via session manager singleton class
WSSessionManager.sessionManager.setAccessToken(response["access_token"] as! String)
- Once session is saved now you have to call user detail endpoint to save user object in current session via WSSessionManager
WSSessionManager.sessionManager.setCurrentUser(userObject)
- To get the active current user just call
activeSession
class func ofWSSession
where it will fetch current active session object via singleton class of WSSessionManager and then callcurrentUser
instance func
WSSession.activeSession().currentUser()
- For logout call
logout
use as below which uses same way to get WSSession object as explained above:
WSSession.activeSession().logout()
Setup base class and protocols for in-built view controllers and UI classes
As we know swift is protocol-oriented programming (POP) rather than object-oriented programming(OOP) which gives him the ability to do more with protocol declaration.
We can:
- Inherit protocols
- Create extension
- Even typecast it
In Wreely I have used protocols for each view controller via view
and presenter
as both confirming to each other protocol and calling protocol methods whenever necessary.
Let me give you simple example of WSOTPView module which contains below files.
- WSOTPProtocol.swift
- WSOTPView.swift
- WSOTPPresenter.swift
- WSOTPCell.swift
Check below WSOTPProtocol implementation where WSOTPViewProtocol
and WSOTPPresenterProtocol
initiated which will later adopt by WSOTPView and WSOTPPresenter respectively
Once above protocol initiated now let’s see WSOTPView implementation which adopted WSOTPViewProtocol methods which will call by WSOTPPresenter whenever necessary.
Same way you can see WSOTPPresenter implementation which adopted WSOTPPresenterProtocol methods which will call by WSOTPView as whenever necessary.
Along with the above view design pattern I have used storyboard for UI view and even for table view cells responsibility. Check below WSOTPCell
implementation which is implemented using a storyboard outlet.
WSOTPCell
inherited by WSTableViewCell
which has below implementation
Few below things still in progress which I’m working on it.
- Integration of Core Data (As bit explained above but not yet implemented)
- Uses of
DispatchQueue
queues in-app with properconcurrent
andserial
type based on task for the network, heavy batch operation & database related things. (This is one of the ways to optimize large code base app) - Pagination (With and without persistent database along with network
per_page
&page_no
handler) - Reachability handler
- Implement all possible helper protocols for stable and lesser code for UITableView, UICollectionView etc
Comments