String(data: data, encoding: NSUTF8StringEncoding) return nil - swift

I am using JSQMessage and pare to send and save video files
if (mediaType == kUTTypeVideo as String) || (mediaType == kUTTypeMovie as String) {
let movieURL = info[UIImagePickerControllerMediaURL] as? NSURL
let videoMediaItem = JSQVideoMediaItem.init(fileURL: movieURL, isReadyToPlay: true)
let message = JSQMessage(senderId: self.senderId, senderDisplayName: senderDisplayName, date: NSDate(), media: videoMediaItem)
self.saveMediaToParse(message, data: NSData(contentsOfURL: movieURL!)!, fileName:"videoFile")
self.messages += [message]
self.publishMessageToChannel(message)
self.finishSendingMessage()
}
func saveMediaToParse(message:JSQMessage, data:NSData, fileName:String) {
let imageFile = PFFile.init(data: data)
let msg = PFObject(className: "test")
msg["senderId"] = message.senderId
msg[fileName] = imageFile
msg["senderDisplayName"] = message.senderDisplayName
msg["user"] = PFUser.currentUser()
msg.saveInBackgroundWithBlock { (success, error) -> Void in
if(error != nil) {
NSLog("error: %#",(error?.localizedDescription)!)
}
}
}
when I am trying to get the video URL from the data as String I get back nil value. What am I doing wrong?
message["videoFile"].getDataInBackgroundWithBlock({ (data, error) -> Void in
if let data = data where error == nil {
**let dataStr = String(data: data, encoding: NSUTF8StringEncoding)**
let movieUrl = NSURL(string: dataStr!)
let videoMediaItem = JSQVideoMediaItem.init(fileURL: movieUrl, isReadyToPlay:true)
jsqMessage = JSQMessage(senderId:message["senderId"] as! String, displayName: message["senderDisplayName"] as! String, media: videoMediaItem)
self.messages.append(jsqMessage)
self.collectionView?.reloadData()
self.scrollToBottomAnimated(true)
}
})
}
self.messages.append(jsqMessage)

Ended up doing
let dataStr = NSTemporaryDirectory() + "temp.mov"
data.writeToFile(dataStr, atomically: true)
let movieUrl = NSURL(fileURLWithPath: dataStr)
Instead of
let dataStr = String(data: data, encoding: NSUTF8StringEncoding)**

Related

Why is this URLSession.datatask not working in Swift 5 for macos

I am trying to make my own DynamicIP updater as a command line tool so I can set it up to run as a launch agent. I thought this would be a pretty simple thing to do, but I am not getting anything when I run this bit of code.
main.swift:
import AppKit
let userName = "yourUserName"
let password = "yourPassword"
let domain = "yourDomainName"
let ftp = "ftp"
let www = "www"
let checkIPURL = URL(string: "https://svc.joker.com/nic/checkip")
let domainUpdateURL = URL(string: "https://svc.joker.com/nic/update?username=\(userName)&password=\(password)&hostname=\(domain)")
let ftpUpdateURL = URL(string: "https://svc.joker.com/nic/update?username=\(userName)&password=\(password)&hostname=\(ftp).\(domain)")
let wwwUpdateURL = URL(string: "https://svc.joker.com/nic/update?username=\(userName)&password=\(password)&hostname=\(www).\(domain)")
var ipAddress = ""
if let url = checkIPURL {
print("1 - \(url)")
var request = URLRequest(url: url)
print("2 - \(request.url!)")
request.httpMethod = "POST"
print("3")
let session = URLSession.shared
print("4")
session.dataTask(with: request) { data, response, error in
print("4.1")
guard error == nil else {
print("Error:", error ?? "")
return
}
print("4.2")
guard (response as? HTTPURLResponse)?
.statusCode == 200 else {
print("down")
return
}
print("4.3")
if let data = data {
if let dataString = String(decoding: data, as: UTF8.self).removeHtmlTags() {
if let startIndex = dataString.lastIndex(of: " ") {
let chars = dataString.distance(from: startIndex, to: dataString.endIndex)-1
ipAddress = String(dataString.suffix(chars))
}
}
print(ipAddress)
} else {
print("No data")
}
print("up - \(response!)")
}.resume()
print("Done.")
}
extension String {
// Credit - Andrew - https://stackoverflow.com/questions/25983558/stripping-out-html-tags-from-a-string
func removeHtmlTags() -> String? {
do {
guard let data = self.data(using: .utf8) else {
return nil
}
let attributed = try NSAttributedString(data: data, options: [.documentType: NSAttributedString.DocumentType.html, .characterEncoding: String.Encoding.utf8.rawValue], documentAttributes: nil)
return attributed.string
} catch {
return nil
}
}
}
Everything outside of the session prints, but nothing inside of it prints (4.x statements).
I deleted the AppSandbox because when I have AppSandbox as a Capability and turn on Outgoing Connections I get a crash with EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0).
But even with AppSandbox deleted it does not work.
The strange thing is this works fine in a playground (with a slight modification turning the String extension into a function within the playground), which really makes this a head scratcher for me.
Here's my playground code:
import AppKit
let userName = "yourUserName"
let password = "yourPassword"
let domain = "yourDomainName"
let ftp = "ftp"
let www = "www"
let checkIPURL = URL(string: "https://svc.joker.com/nic/checkip")
let domainUpdateURL = URL(string: "https://svc.joker.com/nic/update?username=\(userName)&password=\(password)&hostname=\(domain)")
let ftpUpdateURL = URL(string: "https://svc.joker.com/nic/update?username=\(userName)&password=\(password)&hostname=\(ftp).\(domain)")
let wwwUpdateURL = URL(string: "https://svc.joker.com/nic/update?username=\(userName)&password=\(password)&hostname=\(www).\(domain)")
var ipAddress = ""
if let url = checkIPURL {
print("1 - \(url)")
var request = URLRequest(url: url)
print("2 - \(request.url!)")
request.httpMethod = "POST"
print("3")
let session = URLSession.shared
print("4")
session.dataTask(with: request) { data, response, error in
print("4.1")
guard error == nil else {
print("Error:", error ?? "")
return
}
print("4.2")
guard (response as? HTTPURLResponse)?
.statusCode == 200 else {
print("down")
return
}
print("4.3")
if let data = data {
//if let dataString = String(decoding: data, as: UTF8.self).removeHtmlTags() {
if let dataString = removeHtmlTags(data: data) {
if let startIndex = dataString.lastIndex(of: " ") {
let chars = dataString.distance(from: startIndex, to: dataString.endIndex)-1
ipAddress = String(dataString.suffix(chars))
}
}
print(ipAddress)
} else {
print("No data")
}
print("up - \(response!)")
}.resume()
print("Done.")
}
func removeHtmlTags(data: Data) -> String? {
do {
let attributed = try NSAttributedString(data: data, options: [.documentType: NSAttributedString.DocumentType.html, .characterEncoding: String.Encoding.utf8.rawValue], documentAttributes: nil)
return attributed.string
} catch {
return nil
}
}
Is there something else I need to do to get this to work within the command line tool app I am trying to build?

Get image thumbnails from Rumble?

I want to get a thumbnail image for videos from Rumble.
When getting images from Youtube I just do like this:
https://img.youtube.com/vi/f3ZccBBjmQg/0.jpg
Want to same from Rumble video url-
https://rumble.com/vxhedt-80000-matches-chain-reaction-domino-effect.html?mref=7ju1&mc=4w36m
I checked the rumble webpage of the link you provided. I am not sure if there is a smarter/faster way but here is a way to get the thumbnailUrl from their html code.
func getThumbnailFromRumble() {
let url = URL(string:"https://rumble.com/vxhedt-80000-matches-chain-reaction-domino-effect.html?mref=7ju1&mc=4w36m")!
URLSession.shared.dataTask(with: url){ data, response, error in
guard error == nil else { return }
guard let httpURLResponse = response as? HTTPURLResponse,
httpURLResponse.statusCode == 200,
let data = data else {
return
}
let str = String(data: data, encoding: .utf8) // get the htm response as string
let prefix = "\"thumbnailUrl\":"
let suffix = ",\"uploadDate\""
let matches = str?.match("(\(prefix)(...*)\(suffix))")
if let thumbnailUrlMatch = matches?.first?.first {
let thumbnailUrl = thumbnailUrlMatch
.replacingOccurrences(of: prefix, with: "") // remove prefix from urlstring
.replacingOccurrences(of: suffix, with: "") // remove suffix from urlstring
.replacingOccurrences(of: "\"", with: "") // remove escaping characters from urlstring
if let url = URL(string: thumbnailUrl),
let data = try? Data(contentsOf: url) {
let uiImage = UIImage(data: data)
// use the uiimage
}
}
}.resume()
}
I use this extension to get the necessary string part from the html response
extension String {
func match(_ regex: String) -> [[String]] {
let nsString = self as NSString
return (try? NSRegularExpression(pattern: regex, options: []))?.matches(in: self, options: [], range: NSMakeRange(0, nsString.length)).map { match in
(0..<match.numberOfRanges).map { match.range(at: $0).location == NSNotFound ? "" : nsString.substring(with: match.range(at: $0)) }
} ?? []
}
}
Feel free to improve the code.

How can I send nil picture as a Swift Data type in to REST service in Swift?

I am trying to upload pictures(with FTP way) by REST Service. So I have a function like below:
func saveFeedBack(feedbackType: String, feedbackText: String, picture1: Data, picture2: Data, picture3: Data)
{
let parameters = [
"ofeedbackType": feedbackType,
"ofeedbackText": feedbackText
]
let oimage1 = UIImage(data: picture1)
let oimage2 = UIImage(data: picture2)
let oimage3 = UIImage(data: picture3)
guard let mediaImage1 = Media(withImage: oimage1!, forKey: "pic1") else { return }
guard let mediaImage2 = Media(withImage: oimage2!, forKey: "pic2") else { return }
guard let mediaImage3 = Media(withImage: oimage3!, forKey: "pic3") else { return }
guard let url = URL(string: "http://abc.def.com/Mobile/SSS/feedback") else { return }
var request = URLRequest(url: url)
request.httpMethod = "POST"
let boundary = generateBoundary()
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
let dataBody = createDataBody(withParameters: parameters, media: [mediaImage1, mediaImage2, mediaImage3], boundary: boundary)
request.httpBody = dataBody
let session = URLSession.shared
session.dataTask(with: request) { (data, response, error) in
if let response = response {
print(response)
}
if let data = data
{
do
{
if let jsonResult = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any]
{
//some code in here
}
}
catch
{
print(error)
}
}
}.resume()
}
Here is the Media struct:
import UIKit
struct Media {
let key: String
let filename: String
let data: Data
let mimeType: String
init?(withImage image: UIImage, forKey key: String) {
self.key = key
self.mimeType = "image/jpeg"
self.filename = "fotograf.jpg"
guard let data = image.jpegData(compressionQuality: 1) else { return nil }
self.data = data
}
}
Let's talk about this scenario: Let's say I am sending picture 1 and picture 2. But I am not sending picture 3. Of course I am getting below error because of this code: guard let mediaImage3 = Media(withImage: oimage3!, forKey: "pic3") else { return }
Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value
How can I get rid of above problem? Pictures should be optional. I mean: functions should work fine if I don't send any picture.
Here is the CreateDataBody function
func createDataBody(withParameters params: Parameters?, media: [Media]?, boundary: String) -> Data {
let lineBreak = "\r\n"
var body = Data()
if let parameters = params {
for (key, value) in parameters {
body.append("--\(boundary + lineBreak)")
body.append("Content-Disposition: form-data; name=\"\(key)\"\(lineBreak + lineBreak)")
body.append("\(value + lineBreak)")
}
}
if let media = media {
for photo in media {
body.append("--\(boundary + lineBreak)")
body.append("Content-Disposition: form-data; name=\"\(photo.key)\"; filename=\"\(photo.filename)\"\(lineBreak)")
body.append("Content-Type: \(photo.mimeType + lineBreak + lineBreak)")
body.append(photo.data)
body.append(lineBreak)
}
}
body.append("--\(boundary)--\(lineBreak)")
return body
}
Can you try this?
import UIKit
struct Media {
let key: String
let filename: String
let data: Data?
let mimeType: String
init?(withImage image: UIImage, forKey key: String) {
self.key = key
self.mimeType = "image/jpeg"
self.filename = "photo.jpg"
self.data = image.jpegData(compressionQuality: 1)
}
}
func createDataBody(withParameters params: Parameters?, media: [Media]?, boundary: String) -> Data {
let lineBreak = "\r\n"
var body = Data()
if let parameters = params {
for (key, value) in parameters {
body.append("--\(boundary + lineBreak)")
body.append("Content-Disposition: form-data; name=\"\(key)\"\(lineBreak + lineBreak)")
body.append("\(value + lineBreak)")
}
}
if media != nil {
print("media cnt: ", media!.count)
if let media = media {
for photo in media {
body.append("--\(boundary + lineBreak)")
body.append("Content-Disposition: form-data; name=\"\(photo.key)\"; filename=\"\(photo.filename)\"\(lineBreak)")
body.append("Content-Type: \(photo.mimeType + lineBreak + lineBreak)")
body.append(photo.data!)
body.append(lineBreak)
print("photo.key", photo.key)
}
}
}
body.append("--\(boundary)--\(lineBreak)")
return body
}
func saveFeedBack(feedbackType: String, feedbackText: String, picture1: Data, picture2: Data, picture3: Data)
{
var imageList : [Media] = []
let parameters = [
"ofeedbackType": feedbackType,
"ofeedbackText": feedbackText
]
if let img1 = UIImage(data: picture1) {
if img1.size.width > 0 {
if let oImg1 = Media(withImage: img1, forKey: "pic1") {
imageListe.append(oImg1)
}
}
}
if let img2 = UIImage(data: picture2) {
if img2.size.width > 0 {
if let oImg2 = Media(withImage: img2, forKey: "pic2") {
imageListe.append(oImg2)
}
}
}
if let img3 = UIImage(data: picture3) {
if img3.size.width > 0 {
if let oImg3 = Media(withImage: img3, forKey: "pic3") {
imageListe.append(oImg3)
}
}
}
guard let url = URL(string: "http://abc.des.com/Test/SSS/feedback") else { return }
var request = URLRequest(url: url)
request.httpMethod = "POST"
let boundary = generateBoundary()
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
let dataBody = createDataBody(withParameters: parameters, media:imageList , boundary: boundary)
request.httpBody = dataBody
let session = URLSession.shared
session.dataTask(with: request) { (data, response, error) in
if let response = response {
print(response)
}
if let data = data
{
do
{
if let jsonResult = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any]
{
//some code in here
}
}
catch
{
print(error)
}
}
}.resume()
}
Just try with that hopefully this will work. I have made some changes.
Model:
struct Media {
let key: String
let filename: String
let data: Data
let mimeType: String
init?(withImage image: UIImage, forKey key: String) {
self.key = key
self.mimeType = "image/jpeg"
self.filename = "fotograf.jpg"
guard let data = image.jpegData(compressionQuality: 1) else { return nil }
self.data = data
}
}
Code:
func saveFeedBack(feedbackType: String, feedbackText: String, picture1: Data, picture2: Data, picture3: Data)
{
let parameters = [
"ofeedbackType": feedbackType,
"ofeedbackText": feedbackText
]
guard let oimage1 = UIImage(data: picture1) else { return }
guard let oimage2 = UIImage(data: picture2) else { return }
guard let oimage3 = UIImage(data: picture3) else { return }
let mediaImage1 = Media(withImage: oimage1, forKey: "pic1")
let mediaImage2 = Media(withImage: oimage2, forKey: "pic2")
let mediaImage3 = Media(withImage: oimage3, forKey: "pic3")
guard let url = URL(string: "http://abc.def.com/Mobile/SSS/feedback") else { return }
var request = URLRequest(url: url)
request.httpMethod = "POST"
let boundary = generateBoundary()
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
let dataBody = createDataBody(withParameters: parameters, media: [mediaImage1, mediaImage2, mediaImage3], boundary: boundary)
request.httpBody = dataBody
let session = URLSession.shared
session.dataTask(with: request) { (data, response, error) in
if let response = response {
print(response)
}
if let data = data
{
do
{
if let jsonResult = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any]
{
//some code in here
}
}
catch
{
print(error)
}
}
}.resume()
}

How to put image to NSCache in Swift?

I make some code using swift 4 to load image from URL, but every time I add images to server, it took a lot of time to load it in colection view or table view. I want to try store it in NScache but i dont understand to do it. can anyone help me, I'm new in swift :(
#objc func loadPosts() {
let url = URL(string: "http://someURL/Url.php")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
let body = "phomepost=\(homepost)"
request.httpBody = body.data(using: String.Encoding.utf8)
URLSession.shared.dataTask(with: request) { data, response, error in
DispatchQueue.main.async(execute: {
if error == nil {
do{
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
self.comments.removeAll(keepingCapacity: false)
self.images.removeAll(keepingCapacity: false)
self.collectionView?.reloadData()
guard let parseJSON = json else {
print("Error While Parsing")
return
}
guard let posts = parseJSON["posts"] as? [AnyObject] else {
print("Error while parseJSONing")
return
}
self.comments = posts.reversed()
for i in 0 ..< self.comments.count {
let path = self.comments[i]["path"] as? String
if !path!.isEmpty {
let url = NSURL(string: path!)!
let imageData = try? Data(contentsOf: url as URL)
let image = UIImage(data: imageData! as Data)!
self.images.append(image)
} else {
let image = UIImage()
self.images.append(image)
}
}
self.collectionView?.reloadData()
//print(posts.count)
} catch {
print(error)
}
}else{
print(error)
}
})
}.resume()
}
You can use something like this:
private let cache = NSCache<NSString, NSData>()
.....
func downloadImage(url: String, handler: #escaping(Data?, Error?) -> Void){
let cacheID = NSString(string: url)
if let cachedData = cache.object(forKey: cacheID) {
handler((cachedData as Data), nil)
}else{
if let url = URL(string: url) {
let session = URLSession(configuration: urlSessionConfig)
var request = URLRequest(url: url)
request.cachePolicy = .returnCacheDataElseLoad
request.httpMethod = "get"
session.dataTask(with: request) { (data, response, error) in
if let _data = data {
self.cache.setObject(_data as NSData, forKey: cacheID)
handler(_data, nil)
}else{
handler(nil, error)
}
}.resume()
} else {
// NetworkError is a custom error
handler(nil, NetworkError.invalidURL)
}
}
}
}
This will add a small animation while loading using image set.
let imageCache = NSCache<AnyObject, AnyObject>()
extension UIImageView {
func loadImageFromUrl(urlString: String) {
let loader1 = UIImage(named: "loaderImage1.png")
let loader2 = UIImage(named: "loaderImage2.png")
let loader3 = UIImage(named: "loaderImage3.png")
let imageArray = [loader1, loader2, loader3]
let animatedImage = UIImage.animatedImage(with: imageArray as! [UIImage], duration: 1.7)
if let imageFromCache = imageCache.object(forKey: urlString as AnyObject) as? UIImage{
self.image = imageFromCache
return
} else {
self.image = animatedImage
Alamofire.request(urlString, method: .get).response { (responseData) in
if let data = responseData.data {
DispatchQueue.main.async {
if let imageToCache = UIImage(data: data){
imageCache.setObject(imageToCache, forKey: urlString as AnyObject)
self.image = imageToCache
}
}
}
} //alamofire
}
}
}

Alamofire3 - Alamofire.download : responseArray return response nil

My code ******
let responseDownloaded = Alamofire.download(.GET, url, destination: { (url, response) -> NSURL in
let pathComponent = "recent.json"
let fileManager = NSFileManager.defaultManager()
let directoryURL = fileManager.URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0]
let fileUrl = directoryURL.URLByAppendingPathComponent(pathComponent)
return fileUrl
})
responseDownloaded.responseArray(keyPath: "aTracks") {[unowned self] (response: Response< [DataMusic], NSError>) in
switch response.result {
case .Success(let music):
// some code
case .Failure(let error):
// some code
}
}
File with json is downloaded to disk, but responseArray give me response nil. What is it wrong ?
Alamofire.download() is not returning any value.
If you need to access a response data:
Alamofire.download(
url,
method: .get,
parameters: parameters,
encoding: JSONEncoding.default,
headers: nil,
to: destination).downloadProgress(closure: { (progress) in
//progress closure
}).response(completionHandler: { (DefaultDownloadResponse) in
//here you able to access the DefaultDownloadResponse
//result closure
})
My solution (with ObjectMapper and SwiftyJSON) :
var fileName: String?
var finalPath: NSURL?
Alamofire.download(.GET, url, destination: { (temporaryURL, response) in
if let directoryURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0] as? NSURL {
fileName = response.suggestedFilename!
finalPath = directoryURL.URLByAppendingPathComponent(fileName!)
return finalPath!
}
return temporaryURL
})
.response { (request, response, data, error) in
var fileExist: Bool!
let path = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as String
let url = NSURL(fileURLWithPath: path)
let filePath = url.URLByAppendingPathComponent("recent.json").path!
let fileManager = NSFileManager.defaultManager()
fileExist = fileManager.fileExistsAtPath(filePath) ? true : false
if fileExist != nil {
let jsonData = JSON(data: NSData(contentsOfURL: NSURL(fileURLWithPath: filePath))!)
if let aTracks = jsonData.dictionary {
if let track = aTracks["aTracks"] {
if let arrTack = Mapper<DataMusic>().mapArray(track.rawString()) {
}
}
}
}
}