Unable to send base64 String to server in Swift on iOS - ios

In my application I have pick the image using UIImagePickerController from photos and then compress and convert to base64 string. Finally I upload the base64 string to server. Here the server was not accept the base64 string and does not work, but in Android and Postman it works well. I couldn't find the mistake in my code.
Here I mention the UIImagePickerControllerDelegate:
// MARK: UIImagePickerControllerDelegate
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
dismiss(animated: true, completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
selectedImage = info[UIImagePickerControllerOriginalImage] as! UIImage
selectedImage = selectedImage.resizeWithWidth(width: 700)!
picker.dismiss(animated: true, completion: nil)
DispatchQueue.main.async {
self.collPhotos.reloadData()
}
}
Here I mention the Base64 Conversion and post the parameter string to server:
func addImagesApiCAll() {
let imagedata1:UIImage = selectedImage as! UIImage
let compressData = UIImagePNGRepresentation(imagedata1)
let base64 = compressData?.base64EncodedString(options: .lineLength64Characters)
print("charCount",base64!.count)
if Reachability()!.isReachable {
let id = Singleton.sharedInstance.selectedCategory!
let parameterStr = "property_id=\(self.PropertyID)&photos=\(base64!)&lang_code=\(lanuguage_selection.value(forKey: "language") ?? "en")&base_id=\(id)&user_id=\(login_session.value(forKey: "UserId")!)"
Network.shared.POSTRequest(withParameterString: parameterStr, serviceURL: SAVE_PHOTO_LISTING, APIKEY: "SAVE_PHOTO_LISTING")
} else {
showInformation(title: "Network Error", message: "Please check your internet connection")
}
}
extension AddPhotoViewController: HTTP_POST_STRING_REQUEST_PROTOCOL {
func httpPostRequest(APIKEY: String, requestURL: String, responseDict: NSDictionary, errorDict: String) {
ListingActivityDelegate.hideActivity()
if APIKEY == "SAVE_PHOTO_LISTING"{
if errorDict.count == 0 {
print(responseDict)
let mod = RentYourSpaceModel(fromDictionary: responseDict as! [String : Any])
if mod.status! != 0 {
Singleton.sharedInstance.rentYourSpace = mod
if Singleton.sharedInstance.rentYourSpace.result[0].step5.productImage.count == 0{
imageFromResponse = "NO"
} else {
imageFromResponse = "YES"
}
}
self.showInformation(title: "Application", message: mod.message)
}
else {
}
}
}
}
Here I mention the code for Select Image from Camera or Gallery:
#IBAction func act_AddPhoto(_ sender: UIButton) {
let actionSheet = UIAlertController(title: "Home Stay", message: "Choose Image", preferredStyle: .actionSheet)
actionSheet.addAction(UIAlertAction(title: "Camera", style: .default, handler: { _ in
self.openCamera()
}))
actionSheet.addAction(UIAlertAction(title: "Photos", style: .default, handler: { _ in
self.openGallary()
}))
actionSheet.addAction(UIAlertAction.init(title: "Cancel", style: .cancel, handler: nil))
//If you want work actionsheet on ipad then you have to use popoverPresentationController to present the actionsheet, otherwise app will crash in iPad
switch UIDevice.current.userInterfaceIdiom {
case .pad:
actionSheet.popoverPresentationController?.sourceView = sender
actionSheet.popoverPresentationController?.sourceRect = sender.bounds
actionSheet.popoverPresentationController?.permittedArrowDirections = .up
default:
break
}
self.present(actionSheet, animated: true, completion: nil)
}
//MARK: - Open the camera
func openCamera() {
if(UIImagePickerController .isSourceTypeAvailable(UIImagePickerControllerSourceType.camera)){
imagePicker.sourceType = UIImagePickerControllerSourceType.camera
//If you dont want to edit the photo then you can set allowsEditing to false
imagePicker.allowsEditing = true
imagePicker.delegate = self
self.present(imagePicker, animated: true, completion: nil)
}
else{
let alert = UIAlertController(title: "Warning", message: "You don't have camera", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
}
//MARK: - Choose image from camera roll
func openGallary(){
imagePicker.sourceType = UIImagePickerControllerSourceType.photoLibrary
//If you dont want to edit the photo then you can set allowsEditing to false
imagePicker.allowsEditing = true
imagePicker.delegate = self
self.present(imagePicker, animated: true, completion: nil)
}
Here I give the POSTRequest Method:
//MARK:- Post request with parameter String.
func POSTRequest(withParameterString: String , serviceURL: String , APIKEY: String)
{
var RESPONSE_ERROR = String()
var RESPONSE_DATA = NSDictionary()
let Url = String(format: serviceURL)
guard let serviceUrl = URL(string: Url) else { return }
var request = URLRequest(url: serviceUrl)
let postString = withParameterString
// print(postString)
request.httpBody = postString.data(using: String.Encoding.utf8);
//request.addValue("application/json", forHTTPHeaderField: "content-type")
request.httpMethod = "POST"
let task = URLSession.shared.dataTask(with: request, completionHandler: {
data, response, error in
if let response = response {
print(response)
}
if let resdata = data {
do {
// print(response)
let json = try JSONSerialization.jsonObject(with: resdata, options: .mutableContainers) as? NSDictionary
if let parseJSON = json {
//print(json)
if parseJSON.object(forKey: "status") as! NSInteger == 1 {
if error != nil {
RESPONSE_ERROR = (error?.localizedDescription)!
}
DispatchQueue.main.async {
RESPONSE_DATA = parseJSON
self.HTTP_POST_STRING_REQUEST_DELEGATE?.httpPostRequest(APIKEY: APIKEY, requestURL: serviceURL, responseDict: RESPONSE_DATA, errorDict: RESPONSE_ERROR)
}
} else {
DispatchQueue.main.async {
RESPONSE_DATA = parseJSON
self.HTTP_POST_STRING_REQUEST_DELEGATE?.httpPostRequest(APIKEY: APIKEY, requestURL: serviceURL, responseDict: RESPONSE_DATA, errorDict: RESPONSE_ERROR)
}
}
} else {
DispatchQueue.main.async {
RESPONSE_ERROR = "No Data"
self.HTTP_POST_STRING_REQUEST_DELEGATE?.httpPostRequest(APIKEY: APIKEY, requestURL: serviceURL, responseDict: RESPONSE_DATA, errorDict: RESPONSE_ERROR)
}
}
}catch {
DispatchQueue.main.async {
RESPONSE_ERROR = "Check your input datas"
self.HTTP_POST_STRING_REQUEST_DELEGATE?.httpPostRequest(APIKEY: APIKEY, requestURL: serviceURL, responseDict: RESPONSE_DATA, errorDict: RESPONSE_ERROR)
}
}
} else {
DispatchQueue.main.async {
RESPONSE_ERROR = (error?.localizedDescription)!
self.HTTP_POST_STRING_REQUEST_DELEGATE?.httpPostRequest(APIKEY: APIKEY, requestURL: serviceURL, responseDict: RESPONSE_DATA, errorDict: RESPONSE_ERROR)
}
}
})
task.resume()
}

It looks like you are trying to send base64 string as query string. It would be too long to be a query string. You need to share details for POSTRequest method. For more information.
Network.shared.POSTRequest(withParameterString: parameterStr, serviceURL: SAVE_PHOTO_LISTING, APIKEY: "SAVE_PHOTO_LISTING")
And you need to avoid using exclamation (!) in your application. Your code would crash in many points.
For example:
if Reachability()?.isReachable
You can use optional values to prevent crashes.
let parameters = ["property_id":self.PropertyID,
"photos":base64 ?? "",
"lang_code":lanuguage_selection.value(forKey: "language") ?? "en",
"base_id":id,
"user_id":login_session.value(forKey: "UserId") ?? ""];
Network.shared.POSTRequest(parameters: parameters, serviceURL: SAVE_PHOTO_LISTING, APIKEY: "SAVE_PHOTO_LISTING")
in method add json data:
if let jsonData = try? JSONSerialization.data(withJSONObject: parameters) {
request.httpBody?.append(jsonData)
}

Related

Download URL of firebase storage not working

I'm using the firebase for chat application and I've already stored the images in firebase storage now I want to get the url to fetch the user profile but it's not working even I've tried but nothing is working
Here is the function on line 3rd it generates an error (Value of type 'DatabaseReference' has no member 'downloadURL')
func downloadURL(for path: String, completion: #escaping (Result<URL, Error>) -> Void) {
let refrence = database.child(path)
refrence.downloadURL(completion: { url, error in //here downnloadUrl not working perfectly
guard let url = url, error == nil else {
completion(.failure(StorageErrors.failedToGetDownloadUrl))
return
}
completion(.success(url))
})
}
NetworkingService Class
struct NetworkingService{
static let shared = NetworkingService()
private init(){
}
private let database = Database.database().reference() //creating refrence
public func test(){
database.child("name").setValue(["faheem":true])
}
static func emailForImage(emailAddress: String) -> String{
var safeEmail = emailAddress.replacingOccurrences(of: ".", with: "-")
safeEmail = safeEmail.replacingOccurrences(of: "#", with: "-")
return safeEmail
}
func downloadURL(for path: String, completion: #escaping (Result<URL, Error>) -> Void) {
let refrence = database.child(path)
refrence.downloadURL(completion: { url, error in
guard let url = url, error == nil else {
completion(.failure(StorageErrors.failedToGetDownloadUrl))
return
}
completion(.success(url))
})
}
func userExists(email: String,completion: #escaping((Bool) -> Void)){ //return boolen
var safeEmail = email.replacingOccurrences(of: ".", with: "-")
safeEmail = safeEmail.replacingOccurrences(of: "#", with: "-")
database.child(safeEmail).observeSingleEvent(of: .value) { (snapshot) in
guard let foundEmail = snapshot.value as? String else {
completion(false)
return
}
}
completion(true)
}
func insertUser(user: CUser, completion: #escaping(Result<CUser,Error>) -> Void){
database.child(user.identifier).setValue(user.getDict) { (err, dbRef) in
if err != nil{
completion(.failure(err!))
}else{
completion(.success(user))
}
}
}
}
StoreManager Class
struct StoreManager{
static let shared = StoreManager()
private let storageRefrence = Storage.storage().reference()
func uploadProfilePic(data: Data, fileName: String, completion: #escaping(Result<String,Error>) -> Void){
storageRefrence.child("images/\(fileName)").putData(data,metadata: nil) { (metaData, error) in
guard error == nil else {
completion(.failure(AppError.failedToUpload))
print("faheem ye he error \(error?.localizedDescription)")
return
}
self.storageRefrence.child("images/\(fileName)").downloadURL { (url, error) in
guard let url = url else {
completion(.failure(AppError.failedtoDownloadUrl))
return
}
let urlString = url.absoluteString
print("download url is\(urlString)")
completion(.success(urlString))
}
}
}
}
SignupUserClass
class SignUpUserViewController: UIViewController {
#IBOutlet weak var userProfile: UIImageView!
#IBOutlet weak var lname: UITextField!
#IBOutlet weak var fname: UITextField!
#IBOutlet weak var email: UITextField!
#IBOutlet weak var password: UITextField!
var imagePicker = UIImagePickerController() // for imagepicker
private let spinner = JGProgressHUD(style: .dark)
var user:CUser!
override func viewDidLoad() {
super.viewDidLoad()
password.isSecureTextEntry = true
userProfile.layer.masksToBounds = true
userProfile.layer.borderWidth = 2
userProfile.layer.borderColor = UIColor.lightGray.cgColor
userProfile.layer.cornerRadius = userProfile.frame.size.height / 2
// for rounder image
userProfile.isUserInteractionEnabled = true /
let gesture = UITapGestureRecognizer(target: self, action: #selector(userProfileChange)) //photopcker
userProfile.addGestureRecognizer(gesture)
}
#objc private func userProfileChange(){
print("profile pic changed")
getPhoto()
}
private func insertUser(_ user:CUser){
NetworkingService.shared.insertUser(user: user) { (result) in
switch result{
case .success(let user):
print("User inserted: ", user.getDict)
CUser.shared = user
print("sahed Data is fahem\(CUser.shared)")
case .failure(let error):
print("Error: ",error.localizedDescription)
self.showAlert(message: error.localizedDescription)
}
}
}
private func createUser(_ user:CUser){
FirebaseAuth.Auth.auth().createUser(withEmail: user.email, password: user.password) { [weak self] (respomse, error) in
guard let data = respomse else {
print("Error: ",error?.localizedDescription ?? "")
self?.showAlert(message: error?.localizedDescription ?? "")
return
}
self?.insertUser(user)
}
}
private func uploadImage(_ imageData:Data) {
StoreManager.shared.uploadProfilePic(data: imageData, fileName: user.imageName) { (result) in
switch result{
case .success(let url):
self.user.imageURL = url
self.createUser(self.user)
case .failure(let error):
print("Error: ",error.localizedDescription)
self.showAlert(message: error.localizedDescription)
}
}
}
// register User
#IBAction func register(_ sender: UIButton) {
if checkTextFields([email,password,fname,lname]) {
showAlert(message: "Some fields are missing")
}else{
spinner.show(in: self.view)
NetworkingService.shared.userExists(email: email.text!) { (response) in//checking user through email
self.spinner.dismiss()
guard response != nil else { //measn user exists
self.showAlert(message: "user account already exits we verify through email")
return
}
self.user = CUser(firstName: self.fname.text!, lastName: self.lname.text!, email: self.email.text!, password: self.password.text!, imageURL: "")
/*image url is nil becuase we not upload the image here wehn calling the upload image method
then after setting create user method here we only setting the data in user model and url nil*/
if let userImage = self.userProfile.image!.jpegData(compressionQuality: 0.2) {
self.uploadImage(userImage)
}else{
print("Error: Image cannot be compressed")
}
}
}
}
func checkTextFields(_ textfields:[UITextField]) -> Bool{
for textfield in textfields {
return textfield.text?.isEmpty == true ? true: false
}
return true
}
func gotOLogin(){
guard let loginController = self.storyboard?.instantiateViewController(withIdentifier: String(describing: LoginUserViewController.self)) as? LoginUserViewController else {return}
self.navigationController?.pushViewController(loginController, animated: true)
}
func showAlert(title:String = "Error", message:String){
let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
let ok = UIAlertAction(title: "ok", style:.default, handler: nil)
alertController.addAction(ok)
self.present(alertController, animated: true, completion: nil)
}
}
extension SignUpUserViewController : UIImagePickerControllerDelegate, UINavigationControllerDelegate{
func getPhoto(){
let actionSheet = UIAlertController(title: "Choose Image", message: nil, preferredStyle: .actionSheet)
actionSheet.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
actionSheet.addAction(UIAlertAction(title: "Take Photo", style: .default, handler: {
[weak self] _ in
self?.presentCamera()
}))
actionSheet.addAction(UIAlertAction(title: "Choose Photo", style: .default, handler: { [weak self] _ in
self?.profilePhotoPicker()
}))
present(actionSheet, animated: true, completion: nil)
}
func presentCamera(){ //not allowed in simualtor to capture photo
imagePicker.sourceType = .camera
imagePicker.delegate = self
imagePicker.allowsEditing = true
present(imagePicker, animated: true, completion: nil)
}
func profilePhotoPicker(){
imagePicker.sourceType = .photoLibrary
imagePicker.delegate = self
imagePicker.allowsEditing = true
present(imagePicker, animated: true, completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { //called when select photo
print(info)
userProfile.image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage
imagePicker.dismiss(animated: true, completion: nil)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
picker.dismiss(animated: true, completion: nil)
}
}
ProfileViewcontroler here is getProfilePic fun i already get all the necessary thing but issue is that in networking class download url is not working
class ProfileViewController: UIViewController {
var logoutUser = ["lgout"]
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var currentUserPic: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
tableView.register(UINib(nibName: String(describing: ProfileCell.self), bundle: .main), forCellReuseIdentifier: String(describing: ProfileCell.self))
}
func getProfilePic(){
guard let userEmail = UserDefaults.standard.value(forKey: "useremail") as? String else {
return}
let userEmailForPic = NetworkingService.emailForImage(emailAddress: userEmail)
let fileName = userEmailForPic + "_profile_image_jpg"
let patheStorage = "images/"+fileName//here i want to fetch the pic but in netwroking class downnload url not working
}
}
Firebase Realtime Database and Firebase Storage are separated services. You should be using downloadURL on a storage reference:
func downloadURL(for path: String, completion: #escaping (Result<URL, Error>) -> Void) {
let reference = Storage.storage().reference().child(path)
reference.downloadURL(completion: { url, error in
guard let url = url, error == nil else {
completion(.failure(StorageErrors.failedToGetDownloadUrl))
return
}
completion(.success(url))
})
}

Upload image to my server via PHP using Swift

I am using the code below to upload image to my server, the code send the request but the response always from the API is (there was an error).
In the same time of uploading the image also some information of this image will be stored in mySql.
Here is my code, I am using Xcode 10.1 and Swift 4.2
#IBAction func uploadImage(_ sender: Any) {
self.showActivityIndicator()
//Post URL
let url = "https://website.com/folder/include/upload.php"
//Getting text from textFiled!
let name = nameField.text!
let age = ageField.text!
//Call Parameters
let params: Parameters = ["name": name,"age": age]
//Checking image place holder
let image = UIImage(named: "map.png")
//Checking if empty name or age fileds
if name.isEmpty || age.isEmpty{
self.hideActivityIndicator()
myAlert(title: "Error", msg: "Make sure you enter all the required information!")
}
//Checking if image is not selected!!
else if imageView.image == image
{
self.hideActivityIndicator()
myAlert(title: "Error", msg: "Make sure you choose an image!")
}else{
let imageToUpload = self.imageView.image!
Alamofire.upload(multipartFormData:
{
(multipartFormData) in
multipartFormData.append(imageToUpload.jpegData(compressionQuality: 0.75)!, withName: "image", fileName: self.generateBoundaryString(), mimeType: "image/jpeg")
for (key, value) in params
{
multipartFormData.append((value as AnyObject).data(using: String.Encoding.utf8.rawValue)!, withName: key)
}
}, to:url,headers:nil)
{ (result) in
switch result {
case .success(let upload,_,_ ):
upload.uploadProgress(closure: { (progress) in
//Print progress
self.showActivityIndicator()
})
upload.responseJSON
{ response in
//print response.result
if let result = response.result.value {
//Calling response from API
let message = (result as AnyObject).value(forKey: "message") as! String
let status = (result as AnyObject).value(forKey: "status") as! String
//Case Success
if status == "1" {
self.hideActivityIndicator()
print("Your Results are ====> ",result)
self.myAlert(title: "Data Upload", msg: message)
self.imageView.image = UIImage(named: "map.png")
self.nameField.text = ""
self.ageField.text = ""
}else{
self.hideActivityIndicator()
self.myAlert(title: "Error Uploading", msg: message)
}
}
}
case .failure(let encodingError):
print(encodingError)
break
}
}
}
}
}
Here is the PHP file code:
<?php
include 'include/connect.php';
//Get Param Data
$name = $_POST["name"];
$age = $_POST["age"];
$xName = mysqli_real_escape_string($conn, $name);
$xAge = mysqli_real_escape_string($conn, $age);
//Results Array
$result = array();
//Image setup
$uploads_dir = 'img';
$tmp_name = $_FILES["image"]["tmp_name"];
$image_name = basename($_FILES["image"]["name"]);
$supported_image = array('gif','jpg','jpeg','png');
$ext = strtolower(pathinfo($image_name, PATHINFO_EXTENSION));
if(empty($xName) || empty($xAge)|| empty($image_name))
{
// Send some dummy result back to the iOS app
$result["message"] = "Sorry, there was an error uploading your file.";
$result["status"] = "0";
$result["post"] = $_POST;
$result["files"] = $_FILES;
}
if (! in_array($ext, $supported_image))
{
// Send some dummy result back to the iOS app
$result["message"] = "Sorry, Image extension is not Allowed!";
$result["status"] = "0";
$result["post"] = $_POST;
$result["files"] = $_FILES;
}
else
{
$query ="INSERT INTO images (name, age, image) VALUES ('$xName', '$xAge','$image_name')";
if (mysqli_query($conn, $query)) {
move_uploaded_file($tmp_name,"$uploads_dir/$image_name");
// Send some dummy result back to the iOS app
$result["message"] = "Data has been uploaded successfully.";
$result["status"] = "1";
$result["post"] = $_POST;
$result["files"] = $_FILES;
}
}
echo json_encode($result);
?>
The response from the API seems to be missing of some information, but I am filling the two fields with informations needed, which are the (name and age).
I do not what I am missing to complete uploading the image and its informations.
Thanks
try this in your button click event--->
let alert = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
let addPhotos = UIAlertAction(title: "Choose Photo", style: .default) { (addPhoto) in
self.imgPicker.sourceType = .photoLibrary
self.imgPicker.allowsEditing = false
self.present(self.imgPicker, animated: true, completion: nil)
}
let camera = UIAlertAction(title: "Camera Photo", style: .default) { (CameraPhoto) in
self.imgPicker.sourceType = .camera
self.imgPicker.allowsEditing = false
self.present(self.imgPicker, animated: true, completion: nil)
}
let cancel = UIAlertAction(title: "Cancel", style: .cancel) { (Cencel) in
self.dismiss(animated: true, completion: nil)
}
alert.addAction(addPhotos)
alert.addAction(camera)
alert.addAction(cancel)
self.present(alert, animated: true, completion: nil)
then add this function in your code...
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let img = info[UIImagePickerControllerOriginalImage] as? UIImage{
self.imgProfileImage.image = img
let imgData = UIImageJPEGRepresentation(img, 0.5)!
let parameters = [String : Any]
Alamofire.upload(multipartFormData: { multipartFormData in
multipartFormData.append(imgData, withName: "Folder Name",fileName: "PicName.jpg", mimeType: "image/jpg")
for (key, value) in parameters {
multipartFormData.append((value as AnyObject).data(using: String.Encoding.utf8.rawValue)!, withName: key)
} //Optional for extra parameters
},
to:"Your API is Here.")
{ (result) in
switch result {
case .success(let upload, _, _):
upload.uploadProgress(closure: { (progress) in
print("Upload Progress: \(progress.fractionCompleted)")
})
upload.responseJSON { response in
print(response.result.value)
}
case .failure(let encodingError):
print(encodingError)
}
}
}
self.dismiss(animated: true, completion: nil)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
self.dismiss(animated: true, completion: nil)
}

why i get different image when downloading to the same path?

I am trying to debug a chunk of code used to upload an image and download that image from my own server.
The image path is "http://localhost/Twitter/Avatar/52/avatar.jpeg"
as we can see, there are two images in that folder, same image but different name. I got a weird result when I hard coded the path when downloading the image
if avatarPath != nil {
let x = "http://localhost/Twitter/Avatar/52/avatar.jpeg"
let imageURL = URL(string: x)
let session = URLSession(configuration: .default)
let task = session.dataTask(with: imageURL!, completionHandler: { (data, response, error) in
DispatchQueue.main.async {
if let imageData = data {
self.avatarImage.image = UIImage(data: imageData)
}
}
})
task.resume()
}
// round courner of avatar
avatarImage.layer.cornerRadius = avatarImage.bounds.width/20
avatarImage.clipsToBounds = true
//Give title to navigation controller
self.navigationItem.title = username.uppercased()
activityIndicator.stopAnimating()
}
when I write let x = "http://localhost/Twitter/Avatar/52/pogba.jpeg"
I go the same image as the path, like this
but when I change to let x = "http://localhost/Twitter/Avatar/52/avatar.jpeg"
I got different image, like this
I once used that image actually when the first time uploading an image, but I don't know why that image appears again. I have not implemented caching image yet. why this happens?
here is the full source code
import UIKit
class HomepageVC: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
#IBOutlet weak var avatarImage: UIImageView!
#IBOutlet weak var usernameLabel: UILabel!
#IBOutlet weak var fullnameLabel: UILabel!
#IBOutlet weak var emailLabel: UILabel!
#IBOutlet weak var editAvatarButton: UIButton!
#IBOutlet weak var activityIndicator: UIActivityIndicatorView!
override func viewDidLoad() {
super.viewDidLoad()
activityIndicator.startAnimating()
// mendeklarasikan variable user yang berasal dari superglobal variable di appdelegate
let username = userInfo?["username"] as! String
let fullname = userInfo?["fullname"] as! String
let email = userInfo?["email"] as! String
let avatarPath = userInfo?["avatar"] as? String
// update user interface text & Label
usernameLabel.text = username.uppercased()
fullnameLabel.text = fullname.capitalized
emailLabel.text = email
// update user interface avatar
if avatarPath != nil {
let x = "http://localhost/Twitter/Avatar/52/pogba.jpeg"
let imageURL = URL(string: x)
let session = URLSession(configuration: .default)
let task = session.dataTask(with: imageURL!, completionHandler: { (data, response, error) in
DispatchQueue.main.async {
if let imageData = data {
self.avatarImage.image = UIImage(data: imageData)
}
}
})
task.resume()
}
// round courner of avatar
avatarImage.layer.cornerRadius = avatarImage.bounds.width/20
avatarImage.clipsToBounds = true
//Give title to navigation controller
self.navigationItem.title = username.uppercased()
activityIndicator.stopAnimating()
}
#IBAction func logoutButtonDidPressed(_ sender: Any) {
//menghapus data userDefault yang sudah ada
UserDefaults.standard.removeObject(forKey: "parsedJSON")
UserDefaults.standard.synchronize()
//menuju ke login page dengan modal segue
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let loginVC = storyboard.instantiateViewController(withIdentifier: "loginVC")
present(loginVC, animated: true, completion: nil)
}
#IBAction func editProfilePictureButtonDidPressed(_ sender: Any) {
// user akan memilih photo dari library atau dari camera nya
let imagePickerController = UIImagePickerController()
imagePickerController.delegate = self
imagePickerController.allowsEditing = true
let actionSheet = UIAlertController(title: "Photo Source", message: "please choose your source", preferredStyle: .actionSheet)
// action camera
let actionCamera = UIAlertAction(title: "Camera", style: .default) { (action) in
if UIImagePickerController.isSourceTypeAvailable(.camera) {
imagePickerController.sourceType = .camera
self.present(imagePickerController, animated: true, completion: nil)
} else {
self.showAlert(alertTitle: "Opppss", alertMessage: "camera can't be used / not available", actionTitle: "OK")
print("camera can't be used / not available")
}
}
// action photo library
let actionPhotoLibrary = UIAlertAction(title: "Photo Library", style: .default) { (action) in
imagePickerController.sourceType = .photoLibrary
self.present(imagePickerController, animated: true, completion: nil)
}
//action cancel
let actionCancel = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
actionSheet.addAction(actionCamera)
actionSheet.addAction(actionPhotoLibrary)
actionSheet.addAction(actionCancel)
self.present(actionSheet, animated: true, completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
let image = info[UIImagePickerControllerOriginalImage] as! UIImage
avatarImage.image = image
picker.dismiss(animated: true, completion: nil)
// call func of uploading file to server
uploadAvatar()
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
picker.dismiss(animated: true, completion: nil)
}
// custom HTTP request body to upload image file
func createBodyWithParams(_ parameters: [String: String]?, filePathKey: String?, imageDataKey: Data, boundary: String) -> Data {
var body = Data();
if parameters != nil {
for (key, value) in parameters! {
body.appendString("--\(boundary)\r\n")
body.appendString("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n")
body.appendString("\(value)\r\n")
}
}
// kita set agar image yang di upload kemudian berformat .jpg
let filename = "avatar.jpeg"
let mimetype = "image/jpeg"
body.appendString("--\(boundary)\r\n")
body.appendString("Content-Disposition: form-data; name=\"\(filePathKey!)\"; filename=\"\(filename)\"\r\n")
body.appendString("Content-Type: \(mimetype)\r\n\r\n")
body.append(imageDataKey)
body.appendString("\r\n")
body.appendString("--\(boundary)--\r\n")
return body as Data
}
// uploading image ke server
func uploadAvatar() {
// mendapatkan ID dari User Default variable
let id = userInfo!["id"] as! String
// membuat request
let url = URL(string: "http://localhost/Twitter/uploadAvatar.php")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
// parameter yang akan dikirim di dalam request body
// parameter ini dibutuhkan karena uploadAvatar.php membutuhkan inputan ID
let param = ["id" : id]
// membuat Boundary
let boundary = "Boundary-\(UUID().uuidString)"
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
// mengassign image yang akan di upload dan melakukan kompresi
let imageData = UIImageJPEGRepresentation(avatarImage.image!, 0.5)
// if not compressed, return ... do not continue to code
if imageData == nil {
return
}
// constructing http body
request.httpBody = createBodyWithParams(param, filePathKey: "file", imageDataKey: imageData!, boundary: boundary)
// filePathKey berupa 'file' agar nanti di PHP $_FILES bisa didentifikasi, contohnya $_FILES['file'][tmp_name]
// launc session
URLSession.shared.dataTask(with: request) { data, response, error in
DispatchQueue.main.async(execute: {
if error == nil {
// maka tampilkan $returnArray dari PHP (response message from server)
do {
// json containes $returnArray from php
let json = try JSONSerialization.jsonObject(with: data!, options: []) as? NSDictionary
// declare new parseJSON to store json
guard let parsedJSON = json else {
print("Error while parsing")
return
}
print(parsedJSON)
// get id from $returnArray["id"] in PHP - parseJSON["id"]
let id = parsedJSON["id"]
// successfully uploaded
if id != nil {
// save user information yang berasal dari server
UserDefaults.standard.set(parsedJSON, forKey: "parsedJSON")
userInfo = UserDefaults.standard.object(forKey: "parsedJSON") as? NSDictionary
// jika tidak ada "id" kiriman dari server, maka ada error message
} else {
// get main queue to communicate back to user
DispatchQueue.main.async(execute: {
let message = parsedJSON["message"] as! String
self.showAlert(alertTitle: "opppps", alertMessage: message, actionTitle: "OK")
})
}
// error ketika melakukan JSON serialization
} catch {
// get main queue to communicate back to user
DispatchQueue.main.async(execute: {
let message = error.localizedDescription
self.showAlert(alertTitle: "SorryBroooo", alertMessage: message, actionTitle: "OK")
})
}
// error ketika koneksi ke server
} else {
// get main queue to communicate back to user
DispatchQueue.main.async(execute: {
let message = error!.localizedDescription
self.showAlert(alertTitle: "oppps", alertMessage: message, actionTitle: "OK")
})
}
})
}.resume()
}
}
// extend data
extension Data {
mutating func appendString(_ string : String) {
let data = string.data(using: String.Encoding.utf8, allowLossyConversion: true)
append(data!)
}
}
When you use this code
let session = URLSession(configuration: .default)
you had automatically signed up for default caching policies, it uses persistent disk based cache as specified in this link:
https://developer.apple.com/documentation/foundation/urlsessionconfiguration/1411560-default
if you want to remove all the caching policies, use this code instead
let session = URLSession(configuration: .ephemeral)

Get value from alert textField

I'm currently trying to get a value from an alert box in swift 3.
The below code is used to prompt the alert and save the data, however, im having trouble with calling back the data and manipulating it so it's just a basic string.
func presentAlert() {
let alertController = UIAlertController(title: "IP?", message: "Please input your unique key:", preferredStyle: .alert)
let confirmAction = UIAlertAction(title: "Confirm", style: .default) { (_) in
if let field = alertController.textFields?[0] {
// store it
UserDefaults.standard.set(field.text, forKey: "userIP")
UserDefaults.standard.synchronize()
} else {
// user did not fill field
print("no input given")
}
}
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { (_) in }
alertController.addTextField { (textField) in
textField.placeholder = "IP"
}
alertController.addAction(confirmAction)
alertController.addAction(cancelAction)
self.present(alertController, animated: true, completion: nil)
}
This method is called here:
override func viewDidAppear(_ animated: Bool) {
presentAlert()
}
I'm trying to call it and assign it in between a string as:
let url_to_unlock:String = "http://\(UserDefaults.standard.value(forKey: "userIP")):3000/unLock"
However, this gives me the output:
http://Optional():3000/unLock
When I try to print it.
Any nudge in the correct direction would be greatly appreciated.
Class Added:
class ViewController: UIViewController {
func presentAlert() {
let alertController = UIAlertController(title: "IP?", message: "Please input your unique key:", preferredStyle: .alert)
let confirmAction = UIAlertAction(title: "Confirm", style: .default) { (_) in
if let field = alertController.textFields?[0] {
// store your data
//this could be lock unique key name etc in future
UserDefaults.standard.set(field.text, forKey: "userIP")
UserDefaults.standard.synchronize()
} else {
// user did not fill field
print("no input given")
}
}
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { (_) in }
alertController.addTextField { (textField) in
textField.placeholder = "IP"
}
alertController.addAction(confirmAction)
alertController.addAction(cancelAction)
self.present(alertController, animated: true, completion: nil)
}
//view did appear for the alert
override func viewDidAppear(_ animated: Bool) {
presentAlert()
}
//to post to an /unLock it must be put in the URL
// let url_to_unlock:String = "http://\(UserDefaults.standard.value(forKey: "userIP")):3000/unLock"
//let url_to_lock:String = "http://\(textField):3000/Lock"
let url_to_unlock:String = "http://10.73.195.218:3000/unLock"
let url_to_lock:String = "http://10.73.195.218:3000/Lock"
override func viewDidLoad() {
super.viewDidLoad()
}
var Timestamp: String {
return "\(NSDate().timeIntervalSince1970 * 1000)"
}
func un_lock()
{
print(url_to_unlock)
let url:URL = URL(string: url_to_unlock)!
let session = URLSession.shared
let request = NSMutableURLRequest(url: url)
request.httpMethod = "POST"
request.cachePolicy = NSURLRequest.CachePolicy.reloadIgnoringCacheData
let paramString = "data=unLocking at \(Timestamp)"
request.httpBody = paramString.data(using: String.Encoding.utf8)
let task = session.dataTask(with: request as URLRequest, completionHandler: {
(
data, response, error) in
guard let _:Data = data, let _:URLResponse = response , error == nil else {
print("error")
return
}
//for errors
let dataString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
print(dataString! )
})
task.resume()
}
func lock()
{
let url:URL = URL(string: url_to_lock)!
let session = URLSession.shared
let request = NSMutableURLRequest(url: url)
request.httpMethod = "POST"
request.cachePolicy = NSURLRequest.CachePolicy.reloadIgnoringCacheData
let paramString = "data=Locking at \(Timestamp)"
request.httpBody = paramString.data(using: String.Encoding.utf8)
let task = session.dataTask(with: request as URLRequest, completionHandler: {
(
data, response, error) in
guard let _:Data = data, let _:URLResponse = response , error == nil else {
print("error")
return
}
//for errors
let dataString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
print(dataString! )
})
task.resume()
}
#IBAction func lock(_ sender: UIButton) {
lock()
}
#IBAction func unLock(_ sender: Any) {
un_lock()
}
}
Thank you.
The value for this is optional:
// let url_to_unlock:String = "http://\(UserDefaults.standard.value(forKey: "userIP")):3000/unLock"
try:
let url = UserDefaults.standard.value(forKey: "userIP")!
let url_to_unlock:String = "http://\(url):3000/unLock"

Simple explanation needed why delegate does not pass when placed in this section of code

I am trying to pass a users' email address to another ViewController via a delegate when the user has successfully logged in.
The snippet of code in question (marked *) works fine where it is and the data is passed successfully. However, at this point the user has not successfully logged in, therefore I would rather insert the snippet where the /**** is, a little further down.
However it does work when in that position. Why is that? (I am new to Swift)
Thanks
#IBAction func loginButtonTapped(_ sender: AnyObject)
{
let userEmail = userEmailTextField.text;
let userPassword = userPasswordTextField.text;
if (userPassword!.isEmpty || userEmail!.isEmpty) { return; }
// send user data to server side
let myUrl = URL(string: "http://www.quasisquest.uk/KeepScore/userLogin.php");
var request = URLRequest(url:myUrl!);
request.httpMethod = "POST";
let postString = "email=\(userEmail!)&password=\(userPassword!)";
request.httpBody = postString.data(using: String.Encoding.utf8);
let task = URLSession.shared.dataTask(with: request) { (data: Data?, response: URLResponse?, error: Error?) in
DispatchQueue.main.async
{
// spinningActivity!.hide(true)
if(error != nil)
{
//Display an alert message
let myAlert = UIAlertController(title: "Alert", message: error!.localizedDescription, preferredStyle: UIAlertControllerStyle.alert);
let okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler:nil)
myAlert.addAction(okAction);
self.present(myAlert, animated: true, completion: nil)
return
}
do {
let json = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String:AnyObject]
*if self.delegate != nil {
self.delegate?.userLoggedIn(data: userEmail! )
}
// retrieve login details and check to see if all ok
if let parseJSON = json {
let returnValue = parseJSON["status"] as? String
if(returnValue != "error")
{
/**** if self.delegate != nil {
self.delegate?.userLoggedIn(data: userEmail! )
} ****/
UserDefaults.set(UserDefaults.standard)(true, forKey: "isUserLoggedIn");
let mainPage = self.storyboard?.instantiateViewController(withIdentifier: "ViewController")
let mainPageNav = UINavigationController(rootViewController: mainPage!)
let appDelegate = UIApplication.shared.delegate
appDelegate?.window??.rootViewController = mainPageNav
self.dismiss(animated: true, completion: nil)
} else {
// display an alert message
let userMessage = parseJSON["message"] as? String
let myAlert = UIAlertController(title: "Alert", message: userMessage, preferredStyle: UIAlertControllerStyle.alert);
let okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler:nil)
myAlert.addAction(okAction);
self.present(myAlert, animated: true, completion: nil)
}
}
} catch
{
print(error)
}
}
}

Resources