This blog post is brought to you by the developer of BitBudget. BitBudget is an automated budgeting app for Android and iOS which syncs with your bank account and helps you avoid overspending. If you’d like to quit living paycheck-to-paycheck and get a better handle on your finances, download it today! https://bitbudget.io
After a fruitful late night hacking session, I’ve finally figured out how to dynamically create JSON in Swift using dictionaries, and then how to send that JSON data over the network to a backend server running PHP. I’ve published something like five blog posts on this topic over the past week, but this is my final answer!
If you haven’t read any of my other posts on this topic, the problem which I kept running into was that I needed to generate a fairly large JSON object with an indeterminate number of items. So naturally, I needed to be able to generate the JSON dynamically using a simple for-loop. However, in Swift you need to generate your JSON using dictionaries which as you probably know, can only use strings for keys! How are you suppose to dynamically generate a large number of items without using numbers to identify the individual pieces of data? Well as one user on StackOverflow cleverly pointed out, you can simply turn your indices into strings by wrapping them in quotes! (Technically you call the String() method, but you get the idea). So 1 becomes “1”! That’s all there is to it.
So here it is, my final sample app demonstrating how to generate JSON with Swift and then send it over the internet to a backend server running PHP:
Single View (Main.storyboard)
ViewController.swift
// // ViewController.swift // JSONxAlamofire // // Created by Christopher Pedersen on 3/3/19. // Copyright © 2019 Christopher Pedersen. All rights reserved. // import UIKit import Foundation import Alamofire class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. } @IBAction func onButtonClick(_ sender: Any) { let numberOfDataPoints: Int = 99 // Note, numberOfDataPoints is actually an inaccurate name. // However, I don't have time to fix it right now. // The variable would be more accurately named something like // numberOfDataPointsMinusOne. var parameters: [String:Any] = [ "numberOfDataPoints": numberOfDataPoints, "firstTypeOfData": [:], "secondTypeOfData": [:] ] var subDictionaryA: [String:Any] = [:] for i in 0...numberOfDataPoints { let indexAsString: String = String(i) subDictionaryA[indexAsString] = ["foo": Int.random(in: 1...100), "bar": Int.random(in: 1...100), "baz": Int.random(in: 1...100)] } var subDictionaryB: [String:Any] = [:] for i in 0...numberOfDataPoints { let indexAsString: String = String(i) subDictionaryB[indexAsString] = ["foo": Int.random(in: 1...100), "bar": Int.random(in: 1...100)] } parameters["firstTypeOfData"] = subDictionaryA parameters["secondTypeOfData"] = subDictionaryB Alamofire.request("http://wingsuitgp.com/networkingtest2.php", method: .post, parameters: parameters, encoding: JSONEncoding.default).response { response in if let data = response.data, let utf8Text = String(data: data, encoding: .utf8) { print("Server Repsonse: \(response)") // print server response to console } else { print("ERROR: PC LOAD LETTER") // cryptic error message } } } }
networkingtest2.php
// Receive JSON Data Via HTTP POST $data = json_decode(file_get_contents('php://input')); $numberOfDataPoints = $data->{'numberOfDataPoints'}; // Note, $numberOfDataPoints is actually a misleading name. // Since the index starts at zero, this number is actually // the highest number, but is not actually the number of data points. // A more accurate name would be $numberOfDataPointsMinusOne. // Don't have time to change the name of this variable right now so... // o well! if ($numberOfDataPoints connect_error) { die("Connection failed: " . $conn->connect_error); } // Insert First Type of Data into MySQL Database for ($i = 0; $i {'firstTypeOfData'}->{"$i"}->{'foo'}; $bar = $data->{'firstTypeOfData'}->{"$i"}->{'bar'}; $baz = $data->{'firstTypeOfData'}->{"$i"}->{'baz'}; $stmt = $conn->prepare("INSERT INTO networkingtest_table (datatype_column, foo_column, bar_column, baz_column) VALUES (?, ?, ?, ?)"); $stmt->bind_param("siii", $datatype, $foo, $bar, $baz); $stmt->execute(); $stmt->close(); } // Insert Second Type of Data into MySQL Database for ($i = 0; $i {'secondTypeOfData'}->{"$i"}->{'foo'}; $bar = $data->{'secondTypeOfData'}->{"$i"}->{'bar'}; $baz = 0; $stmt = $conn->prepare("INSERT INTO networkingtest_table (datatype_column, foo_column, bar_column, baz_column) VALUES (?, ?, ?, ?)"); $stmt->bind_param("siii", $datatype, $foo, $bar, $baz); $stmt->execute(); $stmt->close(); } // Close MySQL Database Connection $conn->close(); echo "data_received"; // echo server response back to client iPhone app