Uploading Photos Swift/iOS - objective-c

Sorry for my English I'll do my best.
I have an issue trying to upload photos from the user's library.
First, I get user's photo with this method
func grabPhotos(){
let imgManager = PHImageManager.defaultManager()
let requestOptions = PHImageRequestOptions()
requestOptions.synchronous = false
requestOptions.deliveryMode = .FastFormat
let fetchOptions = PHFetchOptions()
fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
if let fetchResult : PHFetchResult = PHAsset.fetchAssetsWithMediaType(.Image, options: fetchOptions){
if fetchResult.count > 0{
for i in 0..<fetchResult.count{
let asset = fetchResult.objectAtIndex(i) as! PHAsset
if NSComparisonResult.OrderedSame == asset.creationDate!.compare(self.appDelegate.dateLastUpload!){
print("meme date")
}
else if NSComparisonResult.OrderedAscending == asset.creationDate!.compare(self.appDelegate.dateLastUpload!){
}
else {
imgManager.requestImageDataForAsset(asset, options: requestOptions, resultHandler: { (data, string, orientation, objects) in
self.Upload((UIImage(data: data!)?.CGImage)! , nomImage: "\(asset.creationDate)" )
})
}
}
}
else{
print("you got no photos")
}
}
}
as you can see, each time I get a photo I want to upload it to my server.
the upload part works well.
Here is the upload method
func clickUpload(image:CGImage,nomImage : String){
let url = NSURL(string: "http://192.168.1.20:1993/upload")
let image_photo = UIImage(CGImage: image)
let request = NSMutableURLRequest(URL: url!)
request.HTTPMethod = "POST"
let boundary = generateBoundaryString()
//define the multipart request type
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
if var image_data = UIImageJPEGRepresentation(image_photo,0.8){
let body = NSMutableData()
let fname = nomImage
let mimetype = "image/jpg"
//define the data post parameter
body.appendData("--\(boundary)\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
body.appendData("Content-Disposition:multipart/form-data; name=\"test\"\r\n\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
body.appendData("enctype=\"multipart/form-data".dataUsingEncoding(NSUTF8StringEncoding)!)
body.appendData("hi\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
body.appendData("--\(boundary)\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
body.appendData("Content-Disposition:form-data; name=\"file\"; filename=\"\(fname)\"\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
body.appendData("Content-Type: \(mimetype)\r\n\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
body.appendData(image_data)
body.appendData("\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
body.appendData("--\(boundary)--\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
//request.setValue("multipart/form-data", forHTTPHeaderField: "content-Type")
request.HTTPBody = body
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(request) {
(
let data, let response, let error) in
guard let _:NSData = data, let _:NSURLResponse = response where error == nil else {
print("error")
return
}
let dataString = NSString(data: data!, encoding: NSUTF8StringEncoding)
print(dataString)
}
task.resume()
}
else {
print(« data nil")
}
}
Now problems come... It works well if I upload photos with reduced size, but I want to upload them in HighQualityFormat.
I got 170 photos on my device, and it uploads approximatively 80 photos before crashing with this message
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'NSAllocateMemoryPages(1504802) failed'
Could you guys help me to solve it or give me another way to achieve this?
Thank you all.

Related

POST method API with parameters in swiftUI

I am retrieving details from my api with POST method, I have included the parameters here. I am able to print the response in console., but to the view it's quite complicating. Here added the code which i've tried. I appreciate if someone help me to get this done.
My network code goes here:
class HostApi: ObservableObject {
#Published var todos = [HostsHome]()
#Published var amenity = [AmenitiesHome]()
func loadData() {
let Url = String(format: Host_home)
guard let serviceUrl = URL(string: Url) else {
return
}
let parameters: [String : Any] = [
"request" : ["email" : "xxxxxxxxxxx.com",
"starting" : 0,
"ending" : 10]
]
var request = URLRequest(url: serviceUrl)
request.httpMethod = "POST"
request.setValue("Application/json", forHTTPHeaderField: "Content-Type")
guard let httpBody = try? JSONSerialization.data(withJSONObject: parameters, options: .prettyPrinted) else {
return
}
request.httpBody = httpBody
request.timeoutInterval = 20
let session = URLSession.shared
session.dataTask(with: request) { data, response, error in
if let data = data {
do {
let json = try JSONSerialization.jsonObject(with: data, options: .json5Allowed)
print(json)
} catch {
print(error)
}
}
}.resume()
}
}
ContentView code goes here :
struct Hosts_Home: View {
#StateObject var viewModel = HostApi()
var body: some View {
ForEach(viewModel.todos, id: \.title) { todo in
Text(todo.title!)
}
.onAppear {
viewModel.loadData()
}
}
}
[![api[![parameters][1]][1]][2]
[1]: https://i.stack.imgur.com/R5sBV.png
[2]: https://i.stack.imgur.com/yMj0t.png
Found a solution, I changed my network class like this below and it worked.
class HostApi: ObservableObject {
#Published var todos = [HostsHome]()
#Published var amenity = [AmenitiesHome]()
func loadData() {
let url = URL(string: Host_home)
guard let requestUrl = url else { fatalError() }
var request = URLRequest(url: requestUrl)
request.httpMethod = "POST"
let postString = "email=xxxxxxx#gmail.com&starting=0&ending=10";
request.httpBody = postString.data(using: String.Encoding.utf8);
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
do {
if let todoData = data {
let decodedData = try JSONDecoder().decode([HostsHome].self, from: todoData)
DispatchQueue.main.async {
self.todos = decodedData
self.amenity = decodedData[0].amenities
print(decodedData[0].propertyTypeGroup)
}
} else {
print("No data")
}
} catch {
print(error)
}
}
task.resume()
}
}

The operation couldn’t be completed. (com.amazonaws.AWSS3ErrorDomain error 0.)

When I am uploading video frames in my app it throws an error. I copied the code here, Can anyone please help me to overcome the error?
let directoryURL: URL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
let fileURL: URL = directoryURL.appendingPathComponent("test.h264")
let credentialsProvider = AWSCognitoCredentialsProvider(regionType:.USEast1,
identityPoolId:"us-east-1:5338ad28-9e8f-4347-a150-cabb7bc96ff7")
let configuration = AWSServiceConfiguration(region:.USEast1, credentialsProvider:credentialsProvider)
AWSServiceManager.default().defaultServiceConfiguration = configuration
s3Url = AWSS3.default().configuration.endpoint.url
let key = "test.h264"
let request = AWSS3TransferManagerUploadRequest()!
request.bucket = "skilai"
request.key = key
request.body = fileURL
request.acl = .publicReadWrite
request.contentType = "test/h264"
let transferManager = AWSS3TransferManager.default()
transferManager.upload(request).continueWith(executor: AWSExecutor.mainThread()) { (task) -> Any? in
if let error = task.error
{
print("AWS Upload error \(error.localizedDescription)")
}
if task.result != nil
{
print("Uploaded \(key)")
let contentUrl = self.s3Url.appendingPathComponent("skilai").appendingPathComponent(key)
self.contentUrl = contentUrl
}
return nil
}

I POST file upload(multipart) but it send empty data to web service in swift4

In my application I am trying to upload photos with web service but it send empty to service. There seems to be no errors in the code, but I do not know why it is.However, when I try a different method without photography, the data is full. I really do not understand what is the problem. How can solve this problem?
func apiIsGuvenligi ()
{
let imgData = UIImageJPEGRepresentation(imageView.image!, 0.2)!
var request = URLRequest(url: URL(string: "http://glcwebapi.azurewebsites.net/api/JobSecurity/JobSecurity")!)
request.httpMethod = "POST"
let boundary = generateBoundaryString()
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.setValue("application/json", forHTTPHeaderField: "Accept")
request.addValue("Bearer \(self.token2)", forHTTPHeaderField: "Authorization")
payload = ["MessageBody": textView.text!,
"IsCallEmergencyTeam": acilDurum,
"IsFireExtinguishUsed": yangin,
"SendMyself": kendimeGonder,
"LocationParameter": "\(latitude)-\(longitude)"
] as [String : AnyObject]
if(imgData == nil) { return }
request.httpBody = createBodyWithParameters(parameters: payload as? [String : String], filePathKey: "file", imageDataKey: imgData as NSData, boundary: boundary) as Data
apiKontrol = true
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else {
self.hataMesaji = "Hata=\(String(describing: error))"
return
}
do {
let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as! [String:Any]
let error = json["Data"] as? String
if error == nil
{
}
else
{
self.mesajVer2(mesaj: error!)
self.hataMesaji = "\(String(describing: error))"
}
}
catch let error as NSError {
print(error)
}
// Apiden gelen tüm keys-values, veriler parse edilip kullanılır.
let responseString = String(data: data, encoding: .utf8)
print("responseString iş güvenliği = \(String(describing: responseString))")
}
task.resume()
}
func createBodyWithParameters(parameters: [String: String]?, filePathKey: String?, imageDataKey: NSData, boundary: String) -> NSData {
let body = NSMutableData()
if payload != nil {
for (key, value) in payload {
body.appendString(string: "--\(boundary)\r\n")
body.appendString(string: "Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n")
body.appendString(string: "\(value)\r\n")
print("key \(key) \(value)")
}
}
let filename = "image.jpg"
let mimetype = "image/jpg"
body.appendString(string: "--\(boundary)\r\n")
body.appendString(string: "Content-Disposition: form-data; name=\"PhotoRequest\"; filename=\"\(filename)\"\r\n")
body.appendString(string: "Content-Type: \(mimetype)\r\n\r\n")
body.append(imageDataKey as Data)
body.appendString(string: "\r\n")
body.appendString(string: "--\(boundary)--\r\n")
return body
}
func generateBoundaryString() -> String {
return "Boundary-\(NSUUID().uuidString)"
}
// extension for image uploading
extension NSMutableData {
func appendString(string: String) {
let data = string.data(using: String.Encoding.utf8, allowLossyConversion: true)
append(data!)
}
}

Bad Request: there is no photo in the request

I'm trying to send an image from my application to telegram bot like here
https://newfivefour.com/swift-form-data-multipart-upload-URLRequest.html
Here is the code
let BotToken = "12345"
let ChatID = "123"
func SendToTelegram()
{
var request = URLRequest(url: URL(string: "https://api.telegram.org/bot"+BotToken+"/sendPhoto")!)
request.httpMethod = "POST"
let boundary = "Boundary-\(UUID().uuidString)"
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
let params = [:] as [String: String]
UIGraphicsBeginImageContextWithOptions(ScreenImage.bounds.size, true, 0.0)
ScreenImage.image?.draw(in: CGRect(x: 0, y: 0, width: ScreenImage.frame.size.width, height: ScreenImage.frame.size.height))
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
request.httpBody = createBody(parameters: params,
boundary: boundary,
data: UIImageJPEGRepresentation(image!, 0.7)!,
mimeType: "image/jpg",
filename: "hello.jpg")
print(request.httpBody!)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else { // check for fundamental networking error
return
}
do {
let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? AnyObject
if let parseJSON = json {
print("resp :\(parseJSON)")
}
} catch let error as NSError {
print("error : \(error)")
}
}
task.resume()
}
and get an error
Bad Request: there is no photo in the request";
"error_code" = 400;
ok = 0;
Where do i make a mistake? I'm new in SWIFT and sorry for my English
I know this question is old but the link provided pushed me in the right direction. This is my solution for server side Swift not iOS but you should be able to use it with minimal changes. Remember if you're using iOS, perform none of these operations on the main thread.
class NetworkManager {
func sendTelegramPhoto(_ photo: Data) {
let url = "https://api.telegram.org/bot\(Constants.Telegram.token)/sendPhoto"
let params: [String: Any] = [
"chat_id": Constants.Telegram.uid,
"photo": photo
]
let _ = sendMultiTypePostRequest(url, parameters: params)
}
private func sendMultiTypePostRequest(_ url: String, parameters: [String:String]) -> NetworkResponse {
var networkResponse = NetworkResponse()
let semaphore = DispatchSemaphore(value: 0)
guard let url = URL(string: url) else {
return networkResponse
}
var urlRequest = URLRequest(url: url)
urlRequest.httpMethod = "POST"
let boundary = "Boundary-\(UUID().uuidString)"
urlRequest.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
let httpBody = createBody(parameters: parameters,
boundary: boundary,
mimeType: "image/jpeg",
filename: "snapshot.jpg")
let config = URLSessionConfiguration.default
config.requestCachePolicy = .reloadIgnoringLocalCacheData
let session = URLSession(configuration: config)
let task = session.uploadTask(with: urlRequest, from: httpBody) { (data, response, error) in
networkResponse.data = data
networkResponse.response = response
networkResponse.error = error
semaphore.signal()
}
task.resume()
_ = semaphore.wait(timeout: .distantFuture)
return networkResponse
}
private func createBody(parameters: [String: String],
boundary: String,
mimeType: String,
filename: String) -> Data {
var body = Data()
let boundaryPrefix = "--\(boundary)\r\n"
for (key, value) in parameters {
if let data = value as? Data {
body.appendString(boundaryPrefix)
body.appendString("Content-Disposition: form-data; name=\"\(key)\"; filename=\"\(filename)\"\r\n")
body.appendString("Content-Type: \(mimeType)\r\n\r\n")
body.append(data)
body.appendString("\r\n")
} else if let string = value as? String {
body.appendString(boundaryPrefix)
body.appendString("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n")
body.appendString("\(string)\r\n")
}
}
body.appendString("--".appending(boundary.appending("--")))
return body
}
}
private extension Data {
mutating func appendString(_ string: String) {
let data = string.data(using: String.Encoding.utf8, allowLossyConversion: false)
append(data!)
}
}

How to make HTTP post request with specific body? And how to access token from the server to allow me to login?

I'm having a scenario like :
1) I want to create Http POST request and for this I'm having the data, please see this image:
2) As you can see in the above image, I have to create post a request with the mentioned body and also I'm getting response named: token. How to create post request and fetch this token response?.
3) That token response will allow me to login into myapp.
I'm newbie to this scenario. I have tried some code by my own but still getting confuse in how to combine my app delegate code with this POST Request Code.
Code
#IBAction func signinaction(_ sender: Any) {
self.username.resignFirstResponder()
self.password.resignFirstResponder()
if (self.username.text == "" || self.password.text == "") {
let alertView = UIAlertController(title: "Login failed",
message: "Wrong username or password." as String, preferredStyle:.alert)
let okAction = UIAlertAction(title: "Try Again!", style: .default, handler: nil)
alertView.addAction(okAction)
self.present(alertView, animated: true, completion: nil)
return
}
// Check if the user entered an email
if let actualUsername = self.username.text {
// Check if the user entered a password
if let actualPassword = self.password.text {
// Build the body message to request the token to the web app
self.bodyStr = "username=8870417698&password=1234&grant_type=password" + actualUsername + "&password=" + actualPassword
// Setup the request
let myURL = NSURL(string: "http://ezschoolportalapi.azurewebsites.net/token")!
let request = NSMutableURLRequest(url: myURL as URL)
request.httpMethod = "POST"
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.setValue("application/json", forHTTPHeaderField: "Accept")
request.httpBody = bodyStr.data(using: String.Encoding.utf8)!
let task = URLSession.shared.dataTask(with: request as URLRequest) {
(data, response, error) -> Void in
if data?.count != 0
{
do {
let tokenDictionary:NSDictionary = try JSONSerialization.jsonObject(with: data!, options:.allowFragments) as! NSDictionary
print(tokenDictionary)
// Get the token
let token:String = tokenDictionary["access_token"] as! String
// Keep record of the token
let userdefaults = UserDefaults()
let saveToken = userdefaults.set(token, forKey: "access_token")
userdefaults.synchronize()
// Dismiss login view and go to the home view controller
DispatchQueue.main.async {
self.dismiss(animated: true, completion: nil)
}
}
catch {
// Wrong credentials
// Reset the text fields
self.username.text = ""
self.password.text = ""
// Setup the alert
let alertView = UIAlertController(title: "Login failed",
message: "Wrong username or password." as String, preferredStyle:.alert)
let okAction = UIAlertAction(title: "Try Again!", style:.default, handler: nil)
alertView.addAction(okAction)
self.present(alertView, animated: true, completion: nil)
return
}
}
}
task.resume()
}
}
}
Question is how to combine this code with my above code :
let appDelegate = UIApplication.shared.delegate as! AppDelegate appDelegate.gotoMainvc()
if I use directly this code then in any of the case I'm able to switch over to my home screen it doesn't matter whether m using this POST Request code or not. Please Help.
You are hard coding the username and password in bodyStr update it to
self.bodyStr = "username=" + actualUsername + "&password=" + actualPassword + "&grant_type=password"
Update the statements inside do with
do {
let tokenDictionary:NSDictionary = try JSONSerialization.jsonObject(with: data!, options:.allowFragments) as! NSDictionary
print(tokenDictionary)
// Get the token
if let authToken = tokenDictionary["access_token"] as? String{
self.token = authToken
UserDefaults.standard.set(accessToken, forKey: "access_token")
UserDefaults.standard.synchronize()
DispatchQueue.main.async {
self.dismiss(animated: true, completion: nil)
}
}
}
You can implement a function like isUserLoggedIn which will return true if token is saved in userDefaults. You need to check whether the user has logged in in the appDelegate's applicationdidFinishLaunchingWithOptions.Like
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
if isUserLoggedIn(){
//showHomeViewController
} else{
//showLoginViewController
}
return true
}
func isUserLoggedIn() -> Bool{
if let accessToken = UserDefaults.standard.object(forKey: "access_token") as? String {
if (accessToken.characters.count)! > 0{
return true
} else {
return false
}
}
else {
return false
}
}