Xcode is IDE for development of the iOS, macOS, tvOS and watchOS applications. Every year apple comes up with so many changes in this IDE. Xcode 9.3 released on March 29, 2018.
Here, I am listing out all the issues with the workaround.
Technology Makes A Wonderful World
Xcode is IDE for development of the iOS, macOS, tvOS and watchOS applications. Every year apple comes up with so many changes in this IDE. Xcode 9.3 released on March 29, 2018.
Here, I am listing out all the issues with the workaround.
Hello after long time I am writing this blog regarding use of Alamofire with Codable model object for the ease of MVC architecture.
Let’s rewind with some of the post which is used to cover this point:
Here I am taking an example of a web service which contains JSON related to the contact.
1 2 3 4 5 6 7 8 9 10 11 12 |
{ "id": "c200", "name": "Ravi Tamada", "email": "ravi@gmail.com", "address": "xx-xx-xxxx,x - street, x - country", "gender" : "male", "phone": { "mobile": "+91 0000000000", "home": "00 000000", "office": "00 000000" } } |
So, we can create two Codable files from this JSON as per hierarchy. These would be like as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
struct Contact: Codable { var id : String var name : String var email : String var address : String var gender : String var phone : Phone } struct Phone: Codable { var mobile : String var home : String var office : String } |
As you can see we have created 2 objects Contact and Phone. Here Phone is in sub hierarchy.
As we have previously revised blogs, there is a blog mentioned about to create a wrapper of the Alamofire and SwiftyJSON. We have to replace the SwiftyJSON code to return normal dictionary objects, and after that we will convert that dictionary to the Codable object.
So here I have updated the AFWrapper class file to do that thing:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import UIKit import Alamofire class AFWrapper: NSObject { class func requestGETURL(_ strURL: String, success:@escaping ([String : Any]) -> Void, failure:@escaping (Error) -> Void) { Alamofire.request(strURL).responseJSON { (responseObject) -> Void in print(responseObject) if responseObject.result.isSuccess { success(responseObject.result.value! as! [String : Any]) } if responseObject.result.isFailure { let error : Error = responseObject.result.error! failure(error) } } } } |
We will call a web service which contain that kind of JSON response. And after calling the web-service we will decode the object to create the Codable object.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
import UIKit class ViewController: UIViewController { var arrContacts = [Contact]() @IBOutlet var txtContacts: UITextView! override func viewDidLoad() { super.viewDidLoad() AFWrapper.requestGETURL("https://api.androidhive.info/contacts/", success: { (responseObject) in print(responseObject) for aContact in responseObject["contacts"] as! [Any] { do { let jsonData = try JSONSerialization.data(withJSONObject: aContact, options: .prettyPrinted) let reqJSONStr = String(data: jsonData, encoding: .utf8) let data = reqJSONStr?.data(using: .utf8) let jsonDecoder = JSONDecoder() let aContact = try jsonDecoder.decode(Contact.self, from: data!) self.arrContacts.append(aContact) self.txtContacts.text = self.txtContacts.text + aContact.name + " " + aContact.phone.mobile + "\n" print(self.arrContacts) } catch { } } }) { (error) in print(error.localizedDescription) } } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } } |
In above sample I have added one text view in the view controller and I am fetching the data from the contacts API. After that using JSONSerialization and JSONDecoder we will get our decoded Contact object with Phone object.
Swift 4 comes with so many updates. We are going to have a great time exploring them all and finding out so much more by using it on further projects. We have learned about Codable and use of it. You too should go check it out and share your experiences with us in the comments section.
Hope you liked the article.
Happy Coding 🙂
Codable is added with Xcode 9, iOS 11 and Swift 4. Codable is used to make your data types encodable and decodable for compatibility with external representations such as JSON.
Codable use to support both encoding and decoding, declare conformance to Codable, which combines the Encodable and Decodable protocols. This process is known as making your types codable.
Let’s Take an Example with Structure of Movie, here we have defined the structure as Codable. So, We can encode and decode it easily.
This article is updated with Swift 4 – Xcode 9 – iOS 11
Why to use a library everytime?
Let’s create our own Slide Menu (Drawer) in Swift 4.
1. Create New Project in Xcode 9 with Swift Language
2. Design the Menu in UIViewController
Declaration of Variables and Protocols (Delegate) :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
protocol SlideMenuDelegate { func slideMenuItemSelectedAtIndex(_ index : Int32) } class MenuViewController: UIViewController, UITableViewDataSource, UITableViewDelegate { /** * Array to display menu options */ @IBOutlet var tblMenuOptions : UITableView! /** * Transparent button to hide menu */ @IBOutlet var btnCloseMenuOverlay : UIButton! /** * Array containing menu options */ var arrayMenuOptions = [Dictionary<String,String>]() /** * Menu button which was tapped to display the menu */ var btnMenu : UIButton! /** * Delegate of the MenuVC */ var delegate : SlideMenuDelegate? } |
Following method is for updating the Items in the Menu :
1 2 3 4 5 |
func updateArrayMenuOptions(){ arrayMenuOptions.append(["title":"Home", "icon":"HomeIcon"]) arrayMenuOptions.append(["title":"Play", "icon":"PlayIcon"]) tblMenuOptions.reloadData() } |
Following method is for click event and animation :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
@IBAction func onCloseMenuClick(_ button:UIButton!){ btnMenu.tag = 0 if (self.delegate != nil) { var index = Int32(button.tag) if(button == self.btnCloseMenuOverlay){ index = -1 } delegate?.slideMenuItemSelectedAtIndex(index) } UIView.animate(withDuration: 0.3, animations: { () -> Void in self.view.frame = CGRect(x: -UIScreen.main.bounds.size.width, y: 0, width: UIScreen.main.bounds.size.width,height: UIScreen.main.bounds.size.height) self.view.layoutIfNeeded() self.view.backgroundColor = UIColor.clear }, completion: { (finished) -> Void in self.view.removeFromSuperview() self.removeFromParentViewController() }) } |
3. Now we will create a Base UIViewController to use anywhere in the project which control the delegate of menu.
First we will create this 3 lines Drawer Icon via Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
func addSlideMenuButton(){ let btnShowMenu = UIButton(type: UIButtonType.system) btnShowMenu.setImage(self.defaultMenuImage(), for: UIControlState()) btnShowMenu.frame = CGRect(x: 0, y: 0, width: 30, height: 30) btnShowMenu.addTarget(self, action: #selector(BaseViewController.onSlideMenuButtonPressed(_:)), for: UIControlEvents.touchUpInside) let customBarItem = UIBarButtonItem(customView: btnShowMenu) self.navigationItem.leftBarButtonItem = customBarItem; } func defaultMenuImage() -> UIImage { var defaultMenuImage = UIImage() UIGraphicsBeginImageContextWithOptions(CGSize(width: 30, height: 22), false, 0.0) UIColor.black.setFill() UIBezierPath(rect: CGRect(x: 0, y: 3, width: 30, height: 1)).fill() UIBezierPath(rect: CGRect(x: 0, y: 10, width: 30, height: 1)).fill() UIBezierPath(rect: CGRect(x: 0, y: 17, width: 30, height: 1)).fill() UIColor.white.setFill() UIBezierPath(rect: CGRect(x: 0, y: 4, width: 30, height: 1)).fill() UIBezierPath(rect: CGRect(x: 0, y: 11, width: 30, height: 1)).fill() UIBezierPath(rect: CGRect(x: 0, y: 18, width: 30, height: 1)).fill() defaultMenuImage = UIGraphicsGetImageFromCurrentImageContext()! UIGraphicsEndImageContext() return defaultMenuImage } |
Delegate (Protocol) method call :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
func slideMenuItemSelectedAtIndex(_ index: Int32) { let topViewController : UIViewController = self.navigationController!.topViewController! print("View Controller is : \(topViewController) \n", terminator: "") switch(index){ case 0: print("Home\n", terminator: "") self.openViewControllerBasedOnIdentifier("Home") break case 1: print("Play\n", terminator: "") self.openViewControllerBasedOnIdentifier("PlayVC") break default: print("default\n", terminator: "") } } |
To open a view controller by identifier :
Set the Restoration Identifier and Storyboard Identifier. If current view is open then we will not open it once again for that we have to check via Restoration Identifier.
1 2 3 4 5 6 7 8 9 |
func openViewControllerBasedOnIdentifier(_ strIdentifier:String){ let destViewController : UIViewController = self.storyboard!.instantiateViewController(withIdentifier: strIdentifier) let topViewController : UIViewController = self.navigationController!.topViewController! if (topViewController.restorationIdentifier! == destViewController.restorationIdentifier!){ print("Same VC") } else { self.navigationController!.pushViewController(destViewController, animated: true) } } |
4. Now We will assign this drawer to any of the UIViewController
We have to use only one method to add drawer (slide menu) self.addSlideMenuButton()
1 2 3 4 5 6 7 |
import UIKit class HomeVC: BaseViewController { override func viewDidLoad() { super.viewDidLoad() addSlideMenuButton() } } |
Source Code is available at the Github AKSwiftSlideMenu
You can download for versions of Swift 2, Swift 3 or Swift 4. From Releases Tab at GitHub AKSwiftSlideMenu.
Check other blog posts about Swift
Happy Coding 🙂