I am creating a social network app in order to learn swift (using Swift 4) and complete a project . I have a TableView that shows videos and I have added the functionality of 'liking' videos like any social network. My issue is that when you like a video the TableView gets reloaded to show the '+ 1 like' and the Video starts all over again. How can I make it so that the video doesn't restart every time you like a video . This is my code here
1st You get the user clicking the Like Action which sends a call to the database and insert the like and add '+1 to the like field'
#IBAction func LikeAction(_ sender: UIButton) {
DontReload = sender.tag
let url:URL = URL(string:ConnectionString+"insert_like")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.cachePolicy = NSURLRequest.CachePolicy.reloadIgnoringCacheData
let parameter = "parameters"
request.httpBody = parameter.data(using: String.Encoding.utf8)
URLSession.shared.dataTask(with: request) { (data: Data?, response: URLResponse?, error: Error?) in
if error != nil
{
print("error=\(String(describing: error))")
return
}
DispatchQueue.main.async {
self.reloadTable()
}
}.resume()
}
Then I query the database and return the new data showing the +1 like and other data in Json Format.
func reloadTable() {
var url = URL(string:ConnectionString+"streams")!
let session = URLSession.shared
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.cachePolicy = NSURLRequest.CachePolicy.reloadIgnoringCacheData
let parameter = "Parameters"
request.httpBody = parameter.data(using: String.Encoding.utf8)
session.dataTask(with:request, completionHandler: {(data, response, error) in
if error != nil {
} else {
do {
let parsedData = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as! [String:Any]
if let Streams = parsedData["Results"] as? [AnyObject]? {
// check for misspelled words
if streamsModel.Locations.count >= 0 {
// Set My Arrays
}
for Stream in Streams! {
// Gets Json Values
}
TableSource.reloadData()
}
}
else {
DispatchQueue.main.async {
streamsModel.Locations.removeAll()
TableSource.reloadData()
}
} catch let error as NSError {
print(error)
}
}
}).resume()
}
This is my TableViewCell and this is obviously called to show the new updated data, however if the user is watching a video and likes it while it is playing then the video restarts... any suggestions on solving this would be great.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "HomeTVC", for: indexPath) as! HomeTVC
// Starts Video Plays
cell.videoView = cell.VideoViewArray[indexPath.row]
cell.videoView.tag = indexPath.row
let movieURL = URL(string: cell.stream_image_string[indexPath.row])
cell.videoCapHeight.constant = CGFloat(Float(cell.pic_height!))
cell.playerView = AVPlayer(url: movieURL!)
cell.MyAVPlayer.player = cell.playerView
cell.MyAVPlayer.videoGravity = AVLayerVideoGravity.resizeAspectFill.rawValue
cell.MyAVPlayer.showsPlaybackControls = false
cell.MyAVPlayer.view.frame = cell.videoView.bounds
cell.videoView.addSubview(cell.MyAVPlayer.view)
controller.addChildViewController(cell.MyAVPlayer)
cell.playerView?.isMuted = false
cell.MyAVPlayer.player?.play()
// Ends Video play
return cell
}
Again my code works the only issue is that my videos restart on Table Reloads . I want to create some type of condition or flag that If a Table View Cell gets 'liked' and there is a video then I want that video to not get reloaded . Any suggestions would be great . Based on suggestions below I will stop using ReloadTable and attempt to grab a reference for that UIButton perhaps something like this
let indexPath = NSIndexPath()
let cell = self.TableSource.dequeueReusableCell(withIdentifier: "HomeTVC", for: indexPath as IndexPath) as! HomeTVC
cell.votes.setTitle("result from server",for: UIControlState.normal)
As per your requirement is seems you don't need to reload whole table view in case of just update like, Once you receive API response of "insert_like" You can update your array and directly get reference of your video running cell and update data source of it.
Related
ScreenshotHi all I'm working on a project where when the user selects a particular cell in a table view, it should show them the data( which is a JSON Decoded object), Now I did all the networking stuff but not sure how to pass the values in such a way that when the user selects a particular cell, corresponding values should appear.
This is the contents of my tableview
var items = [Canada,Delhi,Mumbai,London]
When the user selects pen then the first value(kindly see my screenshot) should be displayed, Also I don't want to store these values as a hardcoded value, I want it to update whenever the user taps on that cell, I've added my networking struct, I'm new here so forgive me if there is any error in my question.
Thank You!
struct StateManager {
func geturl(){
let url = "https://api.covidindiatracker.com/state_data.json"
networking(stateUrl: url)
}
func networking(stateUrl : String){
if let url = URL(string: stateUrl){
let session = URLSession(configuration: .default)
let task = session.dataTask(with: url) { (data, response, error) in
if error != nil{
print("Error fetching Data")
return
}else{
//This is the decoded Data
if let safeData = data{
do{
let json = try JSON(data: safeData)
for i in 0..<38{
if let total = json[i]["confirmed"].int{
print(total)
}
}
}catch{
print("Error ")
}
}
}
}
task.resume()
}
}
}
I have a tableView that is populated by Json. One of the fields returned has the full URL to the image that it needs to download . I do that and everything works however sometimes as I am scrolling down you see the wrong image in a TableView row then it changes back after 2 seconds and this happens after I see about 12 or 13 images then it starts to get slower . I would like to correct that. The code I have so far is this .
stream_image_string: It has the full path to the URL of the image
var Stream_Cache = NSCache() : caches images
The code below is inside the TableView -> UITableViewCell
again everything works the way it's supposed to, just wondering if I can get better performance .
// if more than 0 then it has a URL
if stream_image_string[indexPath.row].characters.count > 0 {
if let image = Stream_Cache.object(forKey: stream_image_string[indexPath.row] as AnyObject) as? UIImage {
cell.stream_image.image = image
} else {
if cell.stream_image != nil {
let strCellImageURL = self.stream_image_string[indexPath.row]
let imgURL: NSURL = NSURL(string: strCellImageURL)!
let request:NSURLRequest = NSURLRequest(url: imgURL as URL)
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
cell.Stream_Image_Height.constant = 400
let task = session.dataTask(with: request as URLRequest, completionHandler: {(data, response, error) in
DispatchQueue.main.async(execute: { () -> Void in
if data != nil {
cell.stream_image.image = UIImage(data: data!)
} else {
cell.Stream_Image_Height.constant = 0
}
})
});
task.resume()
}
}
} else {
cell.Stream_Image_Height.constant = 0
}
You can set the image to a placeholder (instead of nil) and use prefetching (see WWDC'16 session 219) to start fetching for your images earlier:
protocol UITableViewDataSourcePrefetching {
func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [NSIndexPath])
optional func tableView(_ tableView: UITableView, cancelPrefetchingForRowsAt indexPaths:
[NSIndexPath])
}
The image downloading is probably fine, what you need to do is implement:
override func prepareForReuse() {
stream_image.image = nil
}
Inside your cell
I'm trying to load some pictures from different URL in order to add them to my Table View Cells. Each cell contains an UIImageView and the pictures (UIImage) are not loading correctly.
Sometimes the URL connection fails, and sometimes not. I'm going crazy,
help me please!!
This is the part of my code that tries to download a picture from an specific URL:
let imageURL = NSURL(string: "https://upload.wikimedia.org/wikipedia/commons/thumb/9/98/Angels_Stadium.JPG/1920px-Angels_Stadium.JPG")!
let task = URLSession.shared.dataTask(with: imageURL as URL) { (data, response, error) in
guard error == nil, let data = data else { return }
let downloadedImage = UIImage(data: data)
self.foto = downloadedImage!
tableWiew.reloadData()
}
task.resume()
This code is inside the init function of my class (User). After instantiate the class, I try to add the picture to my tableview in other class like this:
let user:User = User(json: obj, tableWiew: self.tableView)
addCell(cell: cell, name: user.nombre, job: user.puesto, nIdeas: "0", mProp: "0", image: user.foto)
The "addCell" method just creates a custom cell and inserts it into my tableView. That's working fine except for the damn picture.
If I add a picture from my Assets it works fine, but I don't know what's wrong when I try to add a picture from an URL.
Please download an image inside cellForRowAt method of UITableViewDataSource and if possible use SDWebImage that will help you with many options eg placeholder. It handles the caching internally and it is async.
let imageURL = NSURL(string: "https://upload.wikimedia.org/wikipedia/commons/thumb/9/98/Angels_Stadium.JPG/1920px-Angels_Stadium.JPG")!
let request = URLRequest(url: imageURL as URL)
let session = URLSession.shared
let task = session.dataTask(with: request, completionHandler: {data, response, error -> Void in
// print("Task completed")
// print(response)
DispatchQueue.main.async(execute: {
self.imgVW.image = UIImage(data: data!)
})
})
task.resume()
I have data coming from Json and populating it inside a TableView . One of those elements that I am getting back from Json is a String that has a URL to an image . If a particular Json string is null or blank I get the following error
fatal error: Index out of range
Every post will not have an Image but I do not know how to tell swift to ignore a certain section of code if the String is blank . This is my code
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "HomePageTVC", for: indexPath) as! HomePageTVC
cell.post.text = Posts[indexPath.row]
// Start Display Image
// right here I get the fatal out of index if there is no image
if profile_image_string[indexPath.row] != nil {
let imgURL: NSURL = NSURL(string: profile_image_string[indexPath.row])!
let request:NSURLRequest = NSURLRequest(url: imgURL as URL)
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
let task = session.dataTask(with: request as URLRequest, completionHandler: {(data, response, error) in
DispatchQueue.main.async(execute: { () -> Void in
if data != nil {
cell.profile_image.image = UIImage(data: data!)
}
})
});
task.resume()
}
// End Display Image
return cell
}
This is my Json being returned
{"post":"Check check","profile_image":null},
{"post":"check check","profile_image":"http://www.myurl.com/cats.jpg}
notice that if no image url exist then the default value is null . How can I check for that inside my TableView code ? Because what I am sure that is happening is that it's taking that null value and trying to convert it into an image thus I am getting the error. The value of the string URL is kept inside this string Array
profile_image_string[indexPath.row]
and this is how I append it
if let profile_picture = Stream["profile_image"] as? String {
self.profile_image_string.append(profile_picture)
}
anyways as stated before I am successfully getting the URL String from Json and if it is a URL then the image shows, I just want to know how can I check for Nulls that way I stop getting that error any help would be great .
This part is pretty wrong
if let profile_picture = Stream["profile_image"] as? String {
self.profile_image_string.append(profile_picture)
}
If you want consistent array value, you have to make your profile_image_string can contains nil by make it's type [String?] and if the if let fail, append nil value into the array like:
if let....else {
self.profile_image_string.append(nil)
}
Still, this way is very messy and not advised, i suggest you create proper object to hold your JSON data
I try to create an page-based navigation watch app with Swift 2.
My app is below:
For both interfaces I have unique controllers named InterfaceController and EconomyInterfaceController.
In each controller I read some JSON data with function in controller init() function
func setFeed(url: String) {
let session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
let request = NSURLRequest(URL: NSURL(string: url)!)
let task: NSURLSessionDataTask = session.dataTaskWithRequest(request) { (data, response, error) -> Void in
if let data = data {
do {
let _data: AnyObject? = try NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments)
if let items = _data!["data"] as? NSArray{
self.tableOutlet.setNumberOfRows(items.count, withRowType: "row")
for (index, item) in items.enumerate() {
if let title = self.JSONString(item["title"]) {
if let spot = self.JSONString((item["spot"])) {
let news = newsItem(title: title, spot: spot)
let row = self.tableOutlet!.rowControllerAtIndex(index) as? RowController
row!.rowLabel!.setText(news.title) }
}
}
}
} catch {
}
}
}
task.resume()
}
As I know this is not best way for HTTP request because of all request run on main thread and on app startup. This is not my main question but if you have any offer I cannot refuse :)
My main question is if I call setFeed() method in willActivate() method and set table labels with
row!.rowLabel!.setText(news.title)
my app works but this is not a good choice because on each time page changed this updates content again and again.
If I call setFeed() method in init() method and set table labels with
row!.rowLabel!.setText(news.title)
Only app's first page being displayed and other pages not being displayed. What is wrong here?