How to grow an iOS app faster (Swift 4)
iOS swift |
After working as an iOS app developer for nearly two years, I came up with several solutions to simplify and organize code that will save you a lot of time and effort. This article will cover the most commonly used requirements that are present in almost every application, such as: changing colors, using fonts, and moving between pages.
This article requires a basic knowledge of Swift basics.
Use custom fonts:
When you write: label.font = UIFont(name: "foo", size: 12)!
every time you need to use the font, you may encounter several problems as a result of repetition, for example: misspellings, a lot of time and effort to modify the code in case of changing the font. As a solution to these problems, you can take advantage of the extension feature.
Extension:
extension UIFont {
class func foo(size: CGFloat) -> UIFont {
return UIFont(name: "foo", size: size)!
}
}
Example of how to use:
label.font = UIFont.foo(size: 12)
Use of colors:
Instead of selecting a specific color using RGB values each time you need to use that color, and to avoid problems that may occur as a result of repetition, you can also take advantage of the Extensions feature and build an extension that contains all the color values you want to use.
Extension:
extension UIColor {
static let foo = UIColor(red: 234/255, green: 232/255, blue: 232/255, alpha: 1)
}
Example of how to use:
label.color = UIColor.foo
Notification Center names:
In the same way, you can create an Extension with all the names of the Notification Center to avoid spelling errors.
Extesnsion:
extension Notification.Name {
static let foo = Notification.Name("foo")
}
Example of how to use:
NotificationCenter.default.post(name: .foo, object: nil)
View Controllers Names:
When writing interface navigation commands, you will often need the name of the View Controller associated with the intended interface. To avoid spelling errors and to shorten many lines of code, you can also take advantage of the extension feature.
Extesnsion:
extension UIStoryboard {
static var main: UIStoryboard {
return UIStoryboard(name: "Main", bundle: nil)
}
var foo: FooViewController {
guard let vc = UIStoryboard.main.instantiateViewController(withIdentifier: String(describing: FooViewController.self)) as? FooViewController else {
fatalError("FooViewController couldn't be found in Storyboard file")
}
return vc
}
}
Example of how to use:
self.window?rootViewController = UIStoryboard.main.foo
Strings:
There are many text-based functions, many of which you will need to use multiple times in a single project.
I have prepared some useful commands that you can use that will save you a lot of time and effort, of course you can modify and add any command to suit your needs.
Extesnsion:
extension String {
// Open any valid URL
func openURL() {
if let url = URL(string: self), UIApplication.shared.canOpenURL(url) {
if #available(iOS 10, *) {
UIApplication.shared.open(url)
} else {
UIApplication.shared.openURL(url)
}
} else {
print("This is not a valid URL")
}
}
// Call a number
func call() {
let url = "telprompt://\(self)"
url.openURL()
}
// Encoding a URL
func encodeUrl() -> String? {
return self.addingPercentEncoding( withAllowedCharacters: NSCharacterSet.urlQueryAllowed)
}
// Decoding a URL
func decodeUrl() -> String? {
return self.removingPercentEncoding
}
// Validate matching a regular expression
func isMatching(regex: String) -> Bool {
let test = NSPredicate(format:"SELF MATCHES %@", regex)
return test.evaluate(with: self)
}
}
Example of how to use:
let urlString = "https://3alam.pro"
urlString.openURL()
Alert Controllers:
Every application often needs the feature of alerts in various forms and for different needs. The following class will help you create and display alerts using as few commands as possible.
Class:
class Alert {
// Alert with ok button
static func create(title:String, msg: String) -> UIAlertController {
let alert = UIAlertController(title: title, message: msg, preferredStyle: .alert)
let action = UIAlertAction(title: "Ok", style: .default, handler: nil)
alert.addAction(action)
return alert
}
// Alert with custom button and cancel button
static func createWithAction(title:String, msg: String, actionTitle: String, callback: @escaping ()->()) -> UIAlertController {
let alert = UIAlertController(title: title, message: msg, preferredStyle: .alert)
let action = UIAlertAction(title: actionTitle, style: .default) { (action) in
callback()
}
alert.addAction(action)
let cancel = UIAlertAction(title: "cancel", style: .cancel, handler: nil)
alert.addAction(cancel)
return alert
}
}
Example of how to use:
let alert = Alert.createWithAction(title: "title", msg: "message", actionTitle: "confirm") {
print("confirm button tapped")
}
self.present(alert, animated: true, completion: nil)
Network Layer
I built a framework for Network Layer using the famous libraries Alamofire and SwiftyJSON . You can use it as a starting point for building your own Network Layer.
The idea of the structure is to build a class after installing the required libraries. The task of this class is to handle all the types of API requests it needs. Example: GET, POST, PUT, DELETE
Class:
class Service: NSObject {
static let reachabilityManager = NetworkReachabilityManager(host: "https://baseURL.com")!
// GET Services
static func getService(url: String, callback: @escaping (JSON?) -> ()) {
if !reachabilityManager.isReachable {
callback(nil)
} else {
Alamofire.request(url).responseJSON { (response) in
switch response.result {
case .success(let value):
let json = JSON(value)
callback(json)
case .failure(let error):
print(error)
callback(nil)
}
}
}
}
static func getServiceWithAuth(url: String, callback: @escaping (JSON?) -> ()) {
if !reachabilityManager.isReachable {
callback(nil)
} else {
let header : HTTPHeaders = ["Authorization": "token"] // Customize it as needed
Alamofire.request(url, headers: header).responseJSON { (response) in
switch response.result {
case .success(let value):
let json = JSON(value)
callback(json)
case .failure(let error):
print(error)
callback(nil)
}
}
}
}
// POST Services
static func postService(url: String, parameters: [String:Any], callback: @escaping (JSON?) -> ()) {
if !reachabilityManager.isReachable {
callback(nil)
} else {
Alamofire.request(url, method: .post, parameters: parameters, encoding: JSONEncoding.default).responseJSON { (response) in
switch response.result {
case .success(let value):
let json = JSON(value)
callback(json)
case .failure(let error):
print(error)
callback(nil)
}
}
}
}
static func postServiceWithAuth(url: String, parameters: [String:Any], callback: @escaping (JSON?) -> ()) {
if !reachabilityManager.isReachable {
callback(nil)
} else {
let header : HTTPHeaders = ["Authorization": "token"] // Customize it as needed
Alamofire.request(url, method: .post, parameters: parameters, encoding: JSONEncoding.default, headers: header).responseJSON { (response) in
switch response.result {
case .success(let value):
let json = JSON(value)
callback(json)
case .failure(let error):
print(error)
callback(nil)
}
}
}
}
// PUT Services
static func putService(url: String, parameters: [String:Any], callback: @escaping (JSON?) -> ()) {
if !reachabilityManager.isReachable {
callback(nil)
} else {
Alamofire.request(url, method: .put, parameters: parameters, encoding: JSONEncoding.default).responseJSON { (response) in
switch response.result {
case .success(let value):
let json = JSON(value)
callback(json)
case .failure(let error):
print(error)
callback(nil)
}
}
}
}
static func putServiceWithAuth(url: String, parameters: [String:Any], callback: @escaping (JSON?) -> ()) {
if !reachabilityManager.isReachable {
callback(nil)
} else {
let header : HTTPHeaders = ["Authorization": "token"] // Customize it as needed
Alamofire.request(url, method: .put, parameters: parameters, encoding: JSONEncoding.default, headers: header).responseJSON { (response) in
switch response.result {
case .success(let value):
let json = JSON(value)
callback(json)
case .failure(let error):
print(error)
callback(nil)
}
}
}
}
// DELETE Services
static func deleteService(url: String, parameters: [String:Any], callback: @escaping (JSON?) -> ()) {
if !reachabilityManager.isReachable {
callback(nil)
} else {
Alamofire.request(url, method: .delete, parameters: parameters, encoding: JSONEncoding.default).responseJSON { (response) in
switch response.result {
case .success(let value):
let json = JSON(value)
callback(json)
case .failure(let error):
print(error)
callback(nil)
}
}
}
}
static func deleteServiceWithAuth(url: String, parameters: [String:Any], callback: @escaping (JSON?) -> ()) {
if !reachabilityManager.isReachable {
callback(nil)
} else {
let header : HTTPHeaders = ["Authorization": "token"] // Customize it as needed
Alamofire.request(url, method: .delete, parameters: parameters, encoding: JSONEncoding.default, headers: header).responseJSON { (response) in
switch response.result {
case .success(let value):
let json = JSON(value)
callback(json)
case .failure(let error):
print(error)
callback(nil)
}
}
}
}
}
Example of how to use:
Every time you need to use the API, you can just call one of the previous funcations and pass the required values:
Service.getService(url: "https://baseURL.com/foo") { (response) in
print(response)
}
I hope that this article will achieve its intended purpose and that you will start using the Extension and Custom Classes feature for a cleaner and cleaner code. You can use the previous codes and modify them according to your need, or even build your own 😉.
read also :
Comments
Post a Comment