I have stored the json image url in a array but while calling the url it shows error
Model class
import Foundation
class ProductDetails {
var productAuthor: String!
var productPrice: Int!
var artImages: [ArtImage]!
}
class ArtImage {
var imagepath: String!
var imgvideotype: Int!
}
TableView Controller Storage variable
var globalArr = [ProductDetails]()
Parsing function
func parseJSONData(data: NSData) -> [ProductDetails] {
var product_Detail = [ProductDetails]()
do {
let jsonResult = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers) as? NSDictionary
let jsonProductDetails = jsonResult?["data"] as! [AnyObject]
//print("the json response is",jsonProductDetails)
for jsonproductDetail in jsonProductDetails{
let productDetail = ProductDetails()
// let jsonProductImageDetails = jsonProductDetails["images"] as! [AnyObject]
productDetail.productAuthor = jsonproductDetail["first_name"]as! String
productDetail.productPrice = jsonproductDetail["prodprice"]as! Int
// Getting inside the json
let jsonProductImageDetails = jsonproductDetail["images"] as! [AnyObject]
var artImagesModelArray = [ArtImage]()
for image in jsonProductImageDetails {
let artImage = ArtImage();
artImage.imagepath = image["imagepath"] as! String
artImage.imgvideotype = image["imgvideotype"] as! Int
artImagesModelArray.append(artImage)
}
productDetail.artImages = artImagesModelArray;
product_Detail.append(productDetail)
}
}
catch {
print (error)
}
return product_Detail
}
Tableview DataSource
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellIdentifier = "Cell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! UserHomeScreenTableViewCell
// Configure the cell...
cell.artsAuthorName.text = globalArr[indexPath.row].productAuthor
cell.priceLabel.text = "\(globalArr[indexPath.row].productPrice)"
let productDetailsObject = globalArr[indexPath.row].artImages
print("#################",productDetailsObject)
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
if let url = (NSURL(string: self.globalArr[indexPath.row])) {
//The error comes here....in self.global array
if let data = NSData(contentsOfURL: url) {
if let image = UIImage(data: data) {
dispatch_async(dispatch_get_main_queue()) { () -> Void in
cell.artImageView.image = image
}
}
}
}
})
return cell
}
Here i have stored the parse json and display some details in tableview cell upto here everything works fine .
but call async way to load images from array its shows error
any suggestion ..plz..
Thank you
You need to change the way how you're taking the image url from the ProductDetails.
I guess you need to use something like this:
if let url = NSURL(string: self.globalArr[indexPath.row].artImages[imageIndex].imagepath) { // your code }
Because when you perform
if let url = (NSURL(string: self.globalArr[indexPath.row]))
you get an object of ProductDetails, but not an image url.
Related
I have been trying to load facebook taggable_friends, I was able to get them but can't load them in UItableView. I tried fetching request in the method "cell for Row at" but it changes the order or refresh every 2-3 seconds. I tried declaring arrays and store the names and profile pictures but I get a crash.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "friendCell", for: indexPath) as! friendstvc
// The first try
/*FBSDKGraphRequest(graphPath: "me/taggable_friends?limit=5000", parameters: nil).start { (connection, result, error) in
if error != nil
{
print(error?.localizedDescription ?? "")
cell.friendName.text = ""
return
}
let dic = result as! Dictionary<String, Any>
let data = dic["data"] as! NSArray
if let name = dic["name"]
{
print(name as! String)
}
let valuedict = data[indexPath.row] as! Dictionary<String, Any>
let id = valuedict["id"] as! String
let name = valuedict["name"] as! String
cell.friendName.text = name
cell.profpic.profileID = id
}*/
// The second try
cell.friendName.text = friendnames[indexPath.row] // crashes here
cell.profpic.image = friendpictures[indexPath.row]
return cell
}
The below method is called in the viewDidLoad for the second try
// for the second try
func loadtaggableFriends()
{
// Called in the viewDidLoad
FBSDKGraphRequest(graphPath: "me/taggable_friends?limit=5000", parameters: nil).start { (connection, result, error) in
if error != nil{
print(error?.localizedDescription ?? "")
return
}
let dic = result as! Dictionary<String, Any>
let data = dic["data"] as! NSArray
if let name = dic["name"]
{
print(name as! String)
}
print(data.count)
for i in 0...data.count - 1
{
let valuedict = data[i] as! Dictionary <String, Any>
let name = valuedict["name"] as! String
var dataurl: Data?
if let picture = valuedict["picture"] as? NSDictionary, let data = picture["data"] as? NSDictionary, let url = data["url"] as? String
{
let loadurl = URL(string: url)
dataurl = try? Data(contentsOf: loadurl!)
}
friendnames.append(name)
friendpictures.append(UIImage(data: dataurl!)!)
}
}
}
// declaring the arrays
var friendnames = [String]()
var friendpictures = [UIImage]()
Problem is that you are using two array instead of two array use one array of dictionaries like : [[String:AnyObject]] .And way of using dictionary and inserting data into array is :
let dict = [String:AnyObject]() //create dictionary
dict["friendpicture"] = "" //
dict["friendnames"] = "" //enter your data
arrOfDictionaries.append(dict) //insert data into array
Access data inside cellForRowAt method like this :
let dict = arrOfDictionaries[indexPath.item]
friendpicture = dict["friendpicture"]
friendnames = dict["friendnames"]
Question 1 :
I am using YouTube API to display a playlist of videos in a UITableView but it's not working. It's working fine when I make it for a single video, one video appears in the UITableView.
How can I display a playlist of any YouTube channel? I am using this code in my UITableView.
My UITableView code :
import UIKit
import AVFoundation
class YTViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, AVAudioPlayerDelegate {
#IBOutlet weak var txtSearch: UITextField!
#IBOutlet weak var searchResultTableView: UITableView!
// Set up a network session
let session = URLSession.shared
// ReST GET static String parts
let BASE_URL: String = "https://www.googleapis.com/youtube/v3/"
let SEARCH_VIDEO: String = "channels?part=snippet&q="
let VIDEO_TYPE: String = "&id=UCJIc9yX_3iHE2CfmUqoeJKQ&key="
let API_KEY: String = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
#IBAction func btnSearchClicked(_ sender: UIButton) {
}
func getVideoList() {
let methodArguments: [String: AnyObject] = [
"query": txtSearch.text! as AnyObject
]
// Format the search string (video title) for http request
let videoTitle: String = escapedParameters(methodArguments)
// Make the query url
// sample: https://www.googleapis.com/youtube/v3/search?part=snippet&q=werewolf&type=video&key=AIzaSyDDqTGpVR7jxeozoOEjH6SLaRdw0YY-HPQ
let searchVideoByTitle = BASE_URL + SEARCH_VIDEO + videoTitle + VIDEO_TYPE + API_KEY
print("#####################\(searchVideoByTitle)")
if let url = URL(string: searchVideoByTitle) {
let request = URLRequest(url: url)
// Initialise the task for getting the data
initialiseTaskForGettingData(request, element: "items")
}
}
// Array to store all the desired values dictionaries
var videosArray: Array<Dictionary<String, AnyObject>> = [[String: AnyObject]]()
func initialiseTaskForGettingData(_ request: URLRequest, element: String) {
// Initialize task for getting data
// Refer to http://www.appcoda.com/youtube-api-ios-tutorial/
let task = session.dataTask(with: request, completionHandler: {(data, HTTPStatusCode, error) in
// Handler in the case of an error
if error != nil {
print(error as Any)
return
}
else {
// Parse that data received from the service
let resultDict: [String: AnyObject]!
do {
// Convert the JSON data to a dictionary
resultDict = try JSONSerialization.jsonObject(with: data! as Data, options: .allowFragments) as! [String: AnyObject]
print("***************************\(resultDict)")
// Get the first item from the returned items
if let itemsArray = (resultDict as AnyObject).value(forKey: element) as? NSArray {
// Remove all existing video data
self.videosArray.removeAll()
for index in 0..<itemsArray.count {
// Append the desiredVaules dictionary to the videos array
self.videosArray.append(self.unwrapYoutubeJson(arrayToBeUnwrapped: itemsArray, index: index))
}
// Asynchronously reload the data and display on the tableview
DispatchQueue.main.async {
// Reload the tableview
self.searchResultTableView.reloadData()
}
}
} catch let jsonError {
print(jsonError)
}
}
})
// Execute the task
task.resume()
}
func unwrapYoutubeJson(arrayToBeUnwrapped: NSArray, index: Int) -> [String: AnyObject]{
let firstItemDict = arrayToBeUnwrapped[index] as! [String: AnyObject]
// Get the snippet dictionary that contains the desired data
let snippetDict = firstItemDict["snippet"] as! [String: AnyObject]
// Dictionary to store desired video contents for display on tableview
// desired values - "Title", "Description", "Thumbnail"
var desiredValuesDict = [String: AnyObject]()
desiredValuesDict["title"] = snippetDict["title"]
desiredValuesDict["description"] = snippetDict["description"]
// Further unwrap to get the Thumbnail default URL
let thumbnailDict: [String: AnyObject]
thumbnailDict = snippetDict["thumbnails"] as! [String: AnyObject]
let defaultThumbnailDict = thumbnailDict["default"] as! [String: AnyObject]
desiredValuesDict["thumbnail"] = defaultThumbnailDict["url"]
//Get the id dictionary that contains videoId
let idDict = firstItemDict["id"] as? [String: AnyObject]
desiredValuesDict["videoId"] = idDict?["videoId"]
return desiredValuesDict
}
// Helper function: Given a dictionary of parameters, convert to a string for a url
func escapedParameters(_ parameters: [String : AnyObject]) -> String {
var urlVars = [String]()
for (key, value) in parameters {
// Make sure that it is a string value
let stringValue = "\(value)"
// Escape it
let escapedValue = stringValue.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)
//Append it
urlVars += [key + "=" + "\(escapedValue!)"]
}
return (!urlVars.isEmpty ? "" : "") + urlVars.joined(separator: "&")
}
// MARK: UITableView method implementation
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! SearchResultTableViewCell
let videoSelected = videosArray[indexPath.row]
cell.updateIU(video: videoSelected)
cell.accessoryType = UITableViewCellAccessoryType.disclosureIndicator
let id = videosArray[indexPath.row]["videoId"] as? String
print("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\(id)")
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return videosArray.count
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destination = segue.destination as? playerViewController {
if let selectedRowIndexPath = searchResultTableView.indexPathForSelectedRow?.row {
destination.mytitle = videosArray[selectedRowIndexPath]["title"] as! String
destination.mydescript = videosArray[selectedRowIndexPath]["description"] as! String
destination.myvideoId = videosArray[selectedRowIndexPath] ["videoId"] as? String
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
getVideoList()
searchResultTableView.dataSource = self
searchResultTableView.delegate = self
}
}
Question 2 :
When I am trying to play a video using YTPlayerHelper it's not working:
fatal error: unexpectedly found nil while unwrapping an Optional value and the video ID appears as nil.
How can I play the video using the YTPlayerHelper? This is how I am playing the video:
import UIKit
import youtube_ios_player_helper
class playerViewController: UIViewController {
#IBOutlet weak var MyPlayer: YTPlayerView!
#IBOutlet weak var txtTitle: UITextView!
#IBOutlet weak var txtDescript: UITextView!
var mytitle: String!
var mydescript: String!
var myvideoId : String!
override func viewDidLoad() {
super.viewDidLoad()
print("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\(myvideoId)")
MyPlayer.load(withVideoId: myvideoId!)
txtTitle.text = mytitle
txtDescript.text = mydescript
}
}
Here is my Alamofire implementation; you have to adjust the names to match yours:
func callAlamo(url : String) {
Alamofire.request(url).responseJSON(completionHandler: {
response in
self.parseData(JSONData: response.data!)
})
}
func parseData(JSONData : Data) {
do {
var readableJSON = try JSONSerialization.jsonObject(with: JSONData, options: .mutableContainers) as! JSONStandard
pageToken = readableJSON["nextPageToken"] as! String
if previousPageButton.isEnabled {
previousPageToken = readableJSON["prevPageToken"] as? String
}
if previousPageToken == nil {
previousPageButton.isEnabled = false
}
if let items = readableJSON["items"] as? [JSONStandard] {
for i in 0..<items.count {
let item = items[i]
var name = String()
var previewURL1 = String()
if let id = item["id"] as? JSONStandard {
let url = id["videoId"] as! String
previewURL1 = url
}
let previewURL = previewURL1
if let snippet = item["snippet"] as? JSONStandard {
let title = snippet["title"] as! String
name = title
if let thumbnails = snippet["thumbnails"] as? JSONStandard {
if let images = thumbnails["high"] as? JSONStandard {
let mainImageURL = URL(string: images["url"] as! String)
imageURL = images["url"] as! String
let mainImageData = NSData(contentsOf: mainImageURL!)
let mainImage = UIImage(data: mainImageData! as Data)
posts.append(post.init(mainImage: mainImage, name: name, previewURL: previewURL, imageURL: imageURL))
self.tableView.reloadData()
nextPageButton.isEnabled = true
}
}
}
}
}
} catch {
print(error)
}
}
Then make a request by using callAlamo(url: yourURL), replacing yourURL with the actual URL.
For the second question, you have a great tutorial here: http://www.appcoda.com/youtube-api-ios-tutorial/
In the tutorial is another way to update UITableView with YouTube videos, but personally I prefer the Alamofire one, as it is much faster and easier to write. I recommend to view just the playing videos part.
So I have 2 NSMutableArrays, one called testArray and the other called jsonArray. jsonArray gets its objects from a mysql server using json and php. Then those same objects in jsonArray are inserted in testArray. I did print(jsonArray, testArray) and what showed in the logs were this.
I also have a NSObject class called Test, if that helps..
For the jsonArray
{
testName = GreenCorn;
testStatus1 = 12;
testStatus2 = 13;
testURL = "";
id = 1;
}
For the testArray
"<CustomCellSwift.Test: 0x17414df70>"
Now I'm new to iOS Swift but I don't know if I inserted the jsonArray into testArray correctly. Here is the code I used. Also, I'm using a custom tableview and its supposed to show testArray.count, its empty cells but its showing the several rows that I have in jsonArray.
var followedArray: NSMutableArray = []
var testArray: NSMutableArray = []
var jsonArray: NSMutableArray = []
var filteredArray: NSArray = []
var isFiltered: Bool = false
// Number of Rows in Section
internal func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if !isFiltered {
if section == 0 {
return followedArray.count
}
else if section == 1 {
return testArray.count
}
}
return filteredArray.count
}
internal func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let CellIdentifier = "Cell"
var cell = tableView.dequeueReusableCell(withIdentifier: CellIdentifier) as! CustomCell
if cell != cell {
cell = CustomCell(style: UITableViewCellStyle.default, reuseIdentifier: CellIdentifier)
}
// Coloring TableView
myTableView.backgroundColor = UIColor.white
// Configuring the cell
var testObject: Test
print("before ifFiltered")
if !isFiltered {
if indexPath.section == 0 {
print("isFiltered if")
testObject = followedArray[indexPath.row] as! Test
cell.populateCell(testObject, isFollowed: true, indexPath: indexPath, parentView: self)
}
else if indexPath.section == 1 {
print("isFiltered if 2")
testObject = testArray[indexPath.row] as! Test
cell.populateCell(testObject, isFollowed: false, indexPath: indexPath, parentView: self)
}
}
else {
print("isFiltered else")
testObject = filteredArray[indexPath.row] as! Test
cell.populateCell(testObject, isFollowed: false, indexPath: indexPath, parentView: self)
}
return cell
}
// Retrieving Data from Server
func retrieveData() {
let getDataURL = "http://exampleip.org/json.php"
let url: NSURL = NSURL(string: getDataURL)!
do {
let data: Data = try Data(contentsOf: url as URL)
jsonArray = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as! NSMutableArray
// Setting up testArray
let testArray: NSMutableArray = []
// Looping through jsonArray
for i in 0..<jsonArray.count {
// Create Test Object
let tID: String = (jsonArray[i] as AnyObject).object(forKey: "id") as! String
let tName: String = (jsonArray[i] as AnyObject).object(forKey: "testName") as! String
let tStatus1: String = (jsonArray[i] as AnyObject).object(forKey: "testStatus1") as! String
let tStatus2: String = (jsonArray[i] as AnyObject).object(forKey: "testStatus2") as! String
let tURL: String = (jsonArray[i] as AnyObject).object(forKey: "testURL") as! String
// Add Test Objects to Test Array
testArray.add(Test(testName: tName, andTestStatus1: tStatus1, andTestStatus2: tStatus2, andTestURL: tURL, andTestID: tID))
print("retrieveData")
print(jsonArray, testArray)
}
}
catch {
print("Error: (Retrieving Data)")
}
myTableView.reloadData()
}
Am I doing this correctly? Why does my tableview have empty cells?
First, your networking/serialization code shouldn't be in your ViewController, but this is a better way to do things:
func retrieveData() {
let getDataURL = "http://exampleip.org/json.php"
let url: NSURL = NSURL(string: getDataURL)!
do {
let data: Data = try Data(contentsOf: url as URL)
guard let jsonArray = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [[String : AnyObject]] else {
print("Error Retrieving Data")
return
}
let testArray = jsonArray.flatMap(Test.init)
// make sure the add the result in your viewController
self.myTableView.models = testArray
}
catch {
print("Error: (Retrieving Data)")
}
myTableView.reloadData()
}
extension Test {
convenience init?(with jsonDictionary: [String : AnyObject]) {
guard let tID = jsonDictionary["id"] as? String, let tName = jsonDictionary["testName"] as? String, let tStatus1 = jsonDictionary["testStatus1"] as? String,
let tStatus2 = jsonDictionary["testStatus2"] as? String, let tURL = jsonDictionary["testURL"] as? String else {
return nil
}
self(testName: tName, andTestStatus1: tStatus1, andTestStatus2: tStatus2, andTestURL: tURL, andTestID: tID)
}
}
I couldn't really test it so there may be some errors, but that should point you in the right direction.
Removing this line of code worked.
let testArray: NSMutableArray = []
I have got the response data in the log window but I am not able to populate on the tableView dynamically. I have tried many methods but not working
// send request to URL
let urlPath:String = "http://api.androidhive.info/contacts/"
var url:NSURL = NSURL(string: urlPath)!
var request1: NSMutableURLRequest = NSMutableURLRequest(URL: url)
request1.HTTPMethod = "POST"
var stringPost = "msg=123" ///key and value
let data = stringPost.dataUsingEncoding(NSUTF8StringEncoding)
request1.timeoutInterval = 60
request1.HTTPBody = data
request1.HTTPShouldHandleCookies = false
let queue:NSOperationQueue = NSOperationQueue()
NSURLConnection.sendAsynchronousRequest(request1, queue: queue, completionHandler: {(response:NSURLResponse!, data:NSData!, error:NSError!) -> Void in
//print object response
println("response = \(response)")
//print response body
let responseString = NSString(data: data, encoding: NSUTF8StringEncoding)
println("response data = \(responseString)")
The data is coming from the url. I can see it.
// Extract JSON
var err: NSError?
let json : NSDictionary = NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers, error: &err) as! NSDictionary
if let items = json["contacts"] as? [[String:AnyObject]]
{
for item in items {
// construct your model objects here
self.contactList.append(Person(dictionary:item))
}
// dispatch_async(dispatch_get_main_queue()) {
// self.tableView.reloadData()
}
The above code line is not appending data (not working).
Table view code
//how many sections
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
//how many rows
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return contactList.count
//return cellCount
}
//contents
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// var cell = UITableViewCell()
var cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! UITableViewCell
// cell.textLabel?.text = "aaa"
let person = contactList[indexPath.row]
cell.textLabel?.text = person.name
return cell
}
Please tell me where the problem is.
That's a good example to create a custom class
class Person { // can be also a struct
let id : String
let name : String
let email : String
let address : String
let gender : String
let phone : String
init(dictionary : [String : AnyObject]) {
id = dictionary["id"] as? String ?? ""
name = dictionary["name"] as? String ?? ""
email = dictionary["email"] as? String ?? ""
address = dictionary["address"] as? String ?? ""
gender = dictionary["gender"] as? String ?? ""
phone = dictionary["id"] as? String ?? ""
}
}
Then create contactList as
var contactList = [Person]()
and populate the list with
if let items = json["contacts"] as? [[String:AnyObject]]
{
for item in items {
// construct your model objects here
self.contactList.append(Person(dictionary:item))
}
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
}
}
and display the name in each cell
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// var cell = UITableViewCell()
var cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! UITableViewCell
let person = contactList[indexPath.row]
cell.textLabel?.text = person.name
return cell
}
If all values of the dictionary containing the person data are of type String you can change the following lines to be still more specific
in Person
init(dictionary : [String : String]) {
id = dictionary["id"] ?? ""
...
phone = dictionary["id"] ?? ""
}
in the view controller
if let items = json["contacts"] as? [[String:String]]
Create NSObject class
public class Global: NSObject
{
let name : String!
.
.
}
Within for item in items
var object: ObjectClass = ObjectClass()
object.id = item["id"]!
.
.
self.contactList.append(object)
In cellForRowAtIndexPath
var object: ObjectClass = self.contactList [indexPath.row] as! ObjectClass;
///get the values as
cell.label.text = object.name;
Instead create model. you can create Class for Contact.
class Contact {
var id : String?
var name : String?
}
Create a Sample responses.
// Contact1
let cont1 : NSMutableDictionary = NSMutableDictionary.init(object: "7", forKey: "id");
cont1.setValue("vignesh", forKey: "name");
// Contact2
let cont2 : NSMutableDictionary = NSMutableDictionary.init(object: "8", forKey: "id");
cont2.setValue("karthi", forKey: "name");
let contactArray :NSArray = NSArray.init(array: [cont1,cont2]);
// Response Dictionary
let responseDic : NSMutableDictionary = NSMutableDictionary.init(object: contactArray, forKey: "contacts");
Parse Response value.
// Create Contact list Array.
var contactList : Array<Contact> = []
if let items = responseDic["contacts"] as? NSArray
{
for item in items {
// construct your model objects here
let id: NSString = item["id"] as! NSString
let name: NSString = item["name"] as! NSString
let contUser : Contact = Contact.init();
contUser.id = id as String;
contUser.name = name as String;
contactList.append(contUser)
}
}
List item
class ViewController: UIViewController , UITableViewDataSource , UITableViewDelegate {
#IBOutlet weak var tableViewCountry: UITableView!
var names: [String] = []
var contacts: [String] = []
var gender: [String] = []
var mob:[String] = []
override func viewDidLoad() {
super.viewDidLoad()
tableViewCountry.dataSource = self
tableViewCountry.delegate = self
self.tableViewCountry.register(UINib(nibName: "ContactTableViewCell", bundle: nil), forCellReuseIdentifier: "ContactTableViewCell")
let url=URL(string:"http://api.androidhive.info/contacts/")
do {
let allContactsData = try Data(contentsOf: url!)
let allContacts = try JSONSerialization.jsonObject(with: allContactsData, options: JSONSerialization.ReadingOptions.allowFragments) as! [String : AnyObject]
if let arrJSON = allContacts["contacts"] {
for index in 0...arrJSON.count-1 {
let aObject = arrJSON[index] as! [String : AnyObject]
names.append(aObject["name"] as! String)
contacts.append(aObject["email"] as! String)
gender.append(aObject["gender"] as! String)
let phone = aObject["phone"]
mob.append(phone?["mobile"] as! String)
}
}
print(allContacts)
print(names)
print(contacts)
self.tableViewCountry.reloadData()
}
catch {
print("error")
}
}
I have a JSON data which I want to map to CoreData when my tableview loaded at first launch.
I found a way to do it in cellForRowAtIndexPath, but this way I can only save the data to CoreData when the cell is displayed.
I want to do it once for all cells.
var yazarMakaleListesi: [JSON]? = []
var authorList = [AuthorList]() // My CoreData
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("YazarCell") as! YazarTableViewCell
cell.yazar = self.yazarMakaleListesi?[indexPath.row]
cell.yazar = self.yazarMakaleListesi?[indexPath.row]
let authorName = self.yazarMakaleListesi?[indexPath.row]["author_name"].string
let authorID = self.yazarMakaleListesi?[indexPath.row]["author_id"].int
let authorImage = self.yazarMakaleListesi?[indexPath.row]["author_image"].string
let newspaperID = self.yazarMakaleListesi?[indexPath.row]["newspaper_id"].string
let newspaperName = self.yazarMakaleListesi?[indexPath.row]["newspaper"].string
let newsPaperImage = self.yazarMakaleListesi?[indexPath.row]["author_image"].string
let articleEntity = NSEntityDescription.entityForName("AuthorList", inManagedObjectContext: self.context!)
let newAuthor = AuthorList(entity: articleEntity!, insertIntoManagedObjectContext: self.context!)
newAuthor.authorName = authorName!
newAuthor.authorImage = authorImage!
newAuthor.newspaperName = newspaperName!
newAuthor.newsPaperImage = newsPaperImage!
newAuthor.authorID = authorID!
var saveError: NSError?
self.context!.save(&saveError)
if let _error = saveError {
println("\(_error.localizedDescription)")
} else {
println("Author Saved!")
}
var error: NSError?
let request = NSFetchRequest(entityName: "AuthorList")
let results = self.context!.executeFetchRequest(request, error: &error) as! [AuthorList]
return cell
}
I get the JSON data here:
func loadYazar(){
if (gazeteid != nil){
let url = "http:myapi.com" + String(gazeteid)
Alamofire.request(.GET, url).responseJSON { (Request, response, json, error) -> Void in
if (json != nil){
var jsonObj = JSON(json!)
if let data = jsonObj["authors"].arrayValue as [JSON]?{
self.yazarMakaleListesi = data
self.tableView.reloadData()
}
}
}
}
}
EDIT : I get my jsonresponse here, implemented # thefredelement's recommendation.
But I get " 'JSON' does not have a member named 'valueForKey'" from line:
newFakeCoreDataObject.authorName = jsonResult.valueForKey("authorName") as! String
Alamofire.request(.GET, url).responseJSON { (Request, response, json, error) -> Void in
if (json != nil){
var jsonObj = JSON(json!)
if let jsonResults = jsonObj["authors"].arrayValue as [JSON]?{
self.yazarMakaleListesi = jsonResults
var error : NSError?
for jsonResult in jsonResults {
let newFakeCoreDataObject = FakeCoreDataObject()
newFakeCoreDataObject.authorName = jsonResult.valueForKey("authorName") as! String
self.context!.save(&error)
}
self.tableView.reloadData()
}
}
I would highly suggest taking that work out of cellForRowAtIndex path and making a separate function that will iterate through your JSON results and save them each, then load the data from core data as a custom object and put that object into an instance array, then use that array for your table data.
Edit: I wouldn't use this code exactly obviously, it's just an example of what I was trying to explain.
import UIKit
import CoreData
class FakeCoreDataObject : NSObject {
// this would really be your NSManagedObject subclass
var authorName = ""
var authorImage = NSData()
var newspaperName = ""
var newspaperImage = NSData()
var authorId = 0 as NSNumber
}
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var myEntries = [FakeCoreDataObject]()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
fetchJson()
prepareTableData()
}
func fetchJson() {
let appDel = UIApplication.sharedApplication().delegate as! AppDelegate
let context = appDel.managedObjectContext!
var error : NSError?
// Get your json reuslts like you are already
var jsonResults = [AnyObject]() // just for an example
for jsonResult in jsonResults {
let newFakeCoreDataObject = FakeCoreDataObject()
newFakeCoreDataObject.authorName = jsonResult.valueForKey("authorName") as! String
// etc
context.save(&error)
// save whatever else you want for other entities, etc, if you need track out of scope you can do that and then save after the loop
}
}
func prepareTableData() {
let appDel = UIApplication.sharedApplication().delegate as! AppDelegate
let context = appDel.managedObjectContext!
var error : NSError?
let fetchTableDataRequest = NSFetchRequest(entityName: "whateverItIsCalled")
fetchTableDataRequest.returnsObjectsAsFaults = false
myEntries = context.executeFetchRequest(fetchTableDataRequest, error: &error) as! [FakeCoreDataObject]
// If you need to do this often, reload the table data here too and you can call it from notifications, etc.
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return myEntries.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// cell stuff you already have but just use the array
// just a tip to set set values to "" or nil if you're creating a big table so you don't get duplciate data while scrolling
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
you should parse the json you receive inside responseJSON:
let jsonObj = NSJSONSerialization.JSONObjectWithData(json, options:NSJSONReadingOptions(rawValue: 0), error: &err) as! NSDictionary
callback(jsonObj as! Dictionary<String, AnyObject>, nil)
var recs:NSArray = jsonObj.objectForKey("authors") as! NSArray
var ct:Int = 0
for item in recs{
var dict:NSDictionary = item as! NSDictionary
// use self.yazarMakaleListesi[ct] here
// process into the dict "author_name" , "author_id", etc
// increment ct
}
self.tableView.reloadData()