NSCocoa使用Swift

时间:2018-10-28 13:03:41

标签: json swift

我已经在一个iPhone应用程序上工作了几个月,该应用程序使用PHP脚本从MYSQL数据库中提取/更新信息,该脚本将任何结果转换为JSON数据。在尝试将我的PHP脚本与我的应用程序集成时,我在接收通过PHP脚本传递回应用程序的JSON数据时遇到一些问题。这是脚本的文本,我已经验证它可以正常工作。

<?php
//Read zip code from POST request
$queryzip = $_POST["ZipID"];

//Create MYSQL connection
$conn = new mysqli("localhost", "root", "Gov4Me", "Gov4Me");

//Check connection
if (mysqli_connect_error()) {
    die("Database connection failed: " .mysqli_connect_error());
}

//Query DB for FedConOfficeModel results using POST ZipID
$sql = "SELECT FedCon.FedConName, FedConOffice.FedConOfficeAddress,                                                 FedConOffice.FedConOfficeAddress2, Cities.City, Cities.ZipID, FedConOffice.Phone, ConDistricts.ConDistrict AS FedConDistrict, FedConOffice.Latitude, FedConOffice.Longitude
    FROM ConDistricts JOIN FedCon ON ConDistricts.ConDistrict = FedCon.FedConDistrict
        JOIN FedConOffice ON FedConOffice.FedConName = FedCon.FedConName
        JOIN Cities ON Cities.ZipID = FedConOffice.ZipID
    WHERE ConDistricts.ZipID = '$queryzip'";

$sqlresults = mysqli_query($conn, "SELECT FedCon.FedConName, FedConOffice.FedConOfficeAddress,                                                 FedConOffice.FedConOfficeAddress2, Cities.City, Cities.ZipID, FedConOffice.Phone, ConDistricts.ConDistrict AS FedConDistrict, FedConOffice.Latitude, FedConOffice.Longitude
    FROM ConDistricts JOIN FedCon ON ConDistricts.ConDistrict = FedCon.FedConDistrict
        JOIN FedConOffice ON FedConOffice.FedConName = FedCon.FedConName
        JOIN Cities ON Cities.ZipID = FedConOffice.ZipID
    WHERE ConDistricts.ZipID = '$queryzip'")
    or die(mysqli_error($conn));

//Check if there are results
if ($result = mysqli_query($conn, $sql)){
    //If so, then create a results array and a temporary one to hold the data
    $resultArray = array();
    $tempArray = array();

    //Loop through each row in the result set
    while($row = $result->fetch_object()){
        //Add each row into our results array
        $tempArray = $row;
        array_push($resultArray, $tempArray);
    }

    //Finally, encode the array to JSON and output the results
    echo json_encode($resultArray);
}

//Close connections
mysqli_close($conn);
?>

当我运行此脚本并通过POST传递有效的邮政编码时,输出如下所示:

[{"FedConName":"Adrian Smith","FedConOfficeAddress":"1811 West Second Street","FedConOfficeAddress2":"Suite 275","City":"Grand Island","ZipID":"68803","Phone":"(308) 384-3900","FedConDistrict":"NE-3","Latitude":"40.917091","Longitude":"-98.358109"},{"FedConName":"Adrian Smith","FedConOfficeAddress":"416 Valley View Drive","FedConOfficeAddress2":"Suite 600","City":"Scottsbluff","ZipID":"69361","Phone":"(308) 633-6333","FedConDistrict":"NE-3","Latitude":"41.878609","Longitude":"-103.656822"}]

这是在其中调用此脚本的Swift文件。

//
// FedConRetrieve.Swift
//
// Created by John Tree on 10/20/2018
// Copyright © 2018 John Tree. All rights reserved.
//

import UIKit
import Foundation

protocol FedConRetrieveProtocol: class{
    func itemsDownloaded(items: NSArray)
}

class FedConRetrieve: NSObject, URLSessionDelegate {
    //properties

    //Declare a delegate property
    weak var delegate: FedConRetrieveProtocol!
    //Declare data variable to store incoming bits
    var data = Data()
    //Declare urlPath to phpservice
    let urlPath: String = "http://localhost/~johntree/FedConOfficeQuery.php"

    //Define function to retrieve data from MYSQL and handle it
    func downloadItems(){
        //Define function local variable to hold value from urlPath variable
        let url: URL = URL(string: urlPath)!
        //Instantiate a URLSession object, with a default configuration
        let defaultSession = Foundation.URLSession(configuration: URLSessionConfiguration.default)
        //Assign a data task in the URLSession using the local url variable
        let task = defaultSession.dataTask(with: url){(data, response, error)
            in
                //If there is an error, notify of failure
                if error != nil{
                    print("Failed to download data")
                }
                //If there are no errors, notify success and parse JSON data
                else{
                    print("Data downloaded")
                    self.parseJSON(_data: data!)
                }
        }   
        task.resume()
    }

    func parseJSON(_data: Data){
        //Create an array variable to hold the data
        var jsonResult = NSArray()
        //Use JSON data to return a foundation object
        do{
            jsonResult = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.allowFragments) as! NSArray
        }
        //If there is an error, print it to the console
        catch let error as NSError{
            print(error)
        }

        //Create an NSDictionary to hold key-value pairs
        var jsonElement = NSDictionary()
        //Create an array to hold each instance of the FedConOffice model
        let offices = NSMutableArray()

        //Loop through the JSON result Array to the last entry
        for i in 0 ..< jsonResult.count{
            //For each line in the JSON data, add it as a key-value pair to the dictionary
            jsonElement = jsonResult[i] as! NSDictionary
            //Instantiate a FedConOfficeModel object to hold the values from the DB
            let office = FedConOfficeModel()

        //Ensure none of the JsonElement values are nil, assign Dictionary entries to the variable names declared
        if let FedConName = jsonElement["FedConName"] as? String,
            let FedConOfficeAddress = jsonElement["FedConOfficeAddress"] as? String,
            let FedConOfficeAddress2 = jsonElement["FedConOfficeAddress2"] as? String,
            let City = jsonElement["City"] as? String,
            let ZipID = jsonElement["ZipID"] as? String,
            let Phone = jsonElement["Phone"] as? String,
            let Latitude = jsonElement["Latitude"] as? String,
            let Longitude = jsonElement["Longitude"] as? String
            {
                //Use the above variable names to assign values to the FedConOfficeModel object's properties
                office.FedConName = FedConName
                office.FedConOfficeAddress = FedConOfficeAddress
                office.FedConOfficeAddress2 = FedConOfficeAddress2
                office.City = City
                office.ZipID = ZipID
                office.Phone = Phone
                office.Latitude = Latitude
                office.Longitude = Longitude
            }
            //Add the fully populate FedConOfficeModel to the Array
            offices.add(office)
            print(offices.description)
        }

        //Pass the offices array to the protocol method for the view controller to use
        DispatchQueue.main.async(execute: { () -> Void in self.delegate.itemsDownloaded(items: offices)
        })
    }
}

用作办公地点数据模型的Swift文件

//
//  FedConOfficeModel.swift
// Gov4Me
//
// Created by John Tree on 10/20/18.
// Copyright © 2018 John Tree. All rights reserved.
//

import UIKit

class FedConOfficeModel: NSObject {
    //properties
    var FedConName: String?
    var FedConOfficeAddress: String?
    var FedConOfficeAddress2: String?
    var City: String?
    var ZipID: String?
    var Phone: String?
    var FedConDistrict: String?
    var Latitude: String?
    var Longitude: String?

    //empty constructor
    override init()
    {

    }

    //construct with variable values
    init(FedConName: String, FedConOfficeAddress: String, FedConOfficeAddress2: String, City: String, ZipID: String, Phone: String, FedConDistrict: String, Latitude: String, Longitude: String)
    {
        self.FedConName = FedConName
        self.FedConOfficeAddress = FedConOfficeAddress
        self.FedConOfficeAddress2 = FedConOfficeAddress2
        self.City = City
        self.ZipID = ZipID
        self.Phone = Phone
        self.FedConDistrict = FedConDistrict
        self.Latitude = Latitude
        self.Longitude = Longitude  
    }

    //print objects current state
    override var description: String
    {
        return "Name: \(String(describing: FedConName))," +
               "Address: \(String(describing: FedConOfficeAddress))," +
               "Address Line 2: \(String(describing: FedConOfficeAddress2))," +
               "City: \(String(describing: City))," +
               "Zip Code: \(String(describing: ZipID))," +
               "Phone: \(String(describing: Phone))," +
               "Congressional District: \(String(describing: FedConDistrict))," +
               "Latitude: \(String(describing: Latitude))," +
               "Longitude: \(String(describing: Longitude))"
    }

}

还有从调用中接收数据的Swift文件。

//
//  MyElectedOfficials.swift
//  Gov4Me App
//
//  Created by John Tree on 8/25/18.
//  Copyright © 2018 John Tree. All rights reserved.
//

import UIKit
import CoreLocation
import Alamofire

class MyElectedOfficials: UIViewController, UITextFieldDelegate, CLLocationManagerDelegate
{

    //Properties
    //Variable to hold query URL selection from previous view
    var queryURL = String()

    //Outlet for textfield
    @IBOutlet weak var ZipField: UITextField!
    //Variable to hold user input
    lazy var postZipID: String = ZipField.text!
    //Variable to hold DB response in label
    @IBOutlet weak var responseLabel: UILabel!


    //Create a variable to contain the gradient layer data
    var gradientLayer : CAGradientLayer!

    //Set status bar to light text
    override var preferredStatusBarStyle: UIStatusBarStyle {
        return .lightContent
    }

    //Outlet for submit button
    @IBAction func Submit(_ sender: Any) {
        let url = URL(string: queryURL)!
            var request = URLRequest(url: url)
            request.httpMethod = "POST"
            request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
        let postString = "ZipID=" + postZipID
            print(postString)
            request.httpBody = postString.data(using: .utf8)
            let task = URLSession.shared.dataTask(with: request) { data, response, error in
                guard let data = data, error == nil else {
                    //check for fundamental networking error
                    print("error=\(String(describing: error))")
                    return
                }

                if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 {
                    //check for http errors
                    print("statusCode should be 200, but is \(httpStatus.statusCode)")
                    print("response = \(String(describing: response))")
                }

                let responseString = String(data: data, encoding: .utf8)
                print("responseString =" + responseString!)

                self.responseLabel.text = responseString
            }

            task.resume()

        performSegue(withIdentifier: "Officials1-Officials2", sender: self)
    }


   //Outlet for Back Button
    @IBAction func backbuttontap(_ sender: Any) {
        performSegue(withIdentifier: "Elected1-Pick", sender: self)
    }

    func createGradientLayer(){
        gradientLayer = CAGradientLayer()
        //Initialize gradienLayer object

        gradientLayer.frame=self.view.bounds
        //Set frame to view controller's bounds

        gradientLayer.colors = [UIColor.green.cgColor, UIColor.cyan.cgColor]
        //Create an array to hold the gradient colors

        self.view.layer.insertSublayer(gradientLayer, at: 0)
        //Add the gradient layer as a sublayer to the view
    }

    override func viewWillAppear(_ animated: Bool){
        super.viewWillAppear(animated)
        createGradientLayer()
        //Before the view is added to the hierarchy, draw the gradient background
    }

    override func viewDidLoad(){
        super.viewDidLoad()
        ZipField.delegate = self
        // Do any additional setup after loading the view.
    }

    override func didReceiveMemoryWarning(){
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    func textFieldShouldReturn(_ textField: UITextField) -> Bool{
        textField.resignFirstResponder()
        performSegue(withIdentifier: "Officials1-Officials2", sender: self)
        return true
    }



    /*
    // MARK: - Navigation

    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        // Get the new view controller using segue.destinationViewController.
        // Pass the selected object to the new view controller.
    }
    */

}

当我尝试运行此应用程序时,该应用程序不会崩溃,但是没有数据填充到我的应用程序中。我知道问题出在我的FedConRetrieve.Swift文件中的某个地方,但是我觉得上下文需要其他问题。当我一起尝试所有操作时,xcode控制台中的日志将提供以下输出。

2018-10-28 09:00:59.535344-0400 Gov4Me App[24587:13858262] libMobileGestalt MobileGestalt.c:890: MGIsDeviceOneOfType is not supported on this platform.
2018-10-28 09:01:03.641829-0400 Gov4Me App[24587:13858262] [MC] System group container for systemgroup.com.apple.configurationprofiles path is /Users/johntree/Library/Developer/CoreSimulator/Devices/D2A0C1BC-26A5-4C06-802B-71105AC6345F/data/Containers/Shared/SystemGroup/systemgroup.com.apple.configurationprofiles
2018-10-28 09:01:03.726773-0400 Gov4Me App[24587:13858262] [MC] Reading from private effective user settings.
ZipID=68803
Data downloaded
Error Domain=NSCocoaErrorDomain Code=3840 "No value." UserInfo={NSDebugDescription=No value.}
responseString =[{"FedConName":"Adrian Smith","FedConOfficeAddress":"1811 West Second Street","FedConOfficeAddress2":"Suite 275","City":"Grand Island","ZipID":"68803","Phone":"(308) 384-3900","FedConDistrict":"NE-3","Latitude":"40.917091","Longitude":"-98.358109"},{"FedConName":"Adrian Smith","FedConOfficeAddress":"416 Valley View Drive","FedConOfficeAddress2":"Suite 600","City":"Scottsbluff","ZipID":"69361","Phone":"(308) 633-6333","FedConDistrict":"NE-3","Latitude":"41.878609","Longitude":"-103.656822"}]
=================================================================
Main Thread Checker: UI API called on a background thread: -[UILabel setText:]
PID: 24587, TID: 13858294, Thread name: (none), Queue name: NSOperationQueue 0x6000020fce20 (QOS: UNSPECIFIED), QoS: 0
Backtrace:
4   Gov4Me App                          0x0000000106a33f78 $S10Gov4Me_App18MyElectedOfficialsC6SubmityyypFy10Foundation4DataVSg_So13NSURLResponseCSgs5Error_pSgtcfU_ + 2664
5   Gov4Me App                          0x0000000106a3420d $S10Gov4Me_App18MyElectedOfficialsC6SubmityyypFy10Foundation4DataVSg_So13NSURLResponseCSgs5Error_pSgtcfU_TA + 13
6   Gov4Me App                          0x0000000106a1f820 $S10Foundation4DataVSgSo13NSURLResponseCSgs5Error_pSgIegggg_So6NSDataCSgAGSo7NSErrorCSgIeyByyy_TR + 336
7   CFNetwork                           0x0000000109784ef0 __75-[__NSURLSessionLocal taskForClass:request:uploadFile:bodyData:completion:]_block_invoke + 19
8   CFNetwork                           0x000000010979b0bc __49-[__NSCFLocalSessionTask _task_onqueue_didFinish]_block_invoke + 172
9   Foundation                          0x0000000106f8119d __NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__ + 7
10  Foundation                          0x0000000106f810a4 -[NSBlockOperation main] + 68
11  Foundation                          0x0000000106f7de13 -[__NSOperationInternal _start:] + 689
12  Foundation                          0x0000000106f83e4a __NSOQSchedule_f + 227
13  libdispatch.dylib                   0x000000010ac1e5d1 _dispatch_call_block_and_release + 12
14  libdispatch.dylib                   0x000000010ac1f63e _dispatch_client_callout + 8
15  libdispatch.dylib                   0x000000010ac22589 _dispatch_continuation_pop + 565
16  libdispatch.dylib                   0x000000010ac21963 _dispatch_async_redirect_invoke + 859
17  libdispatch.dylib                   0x000000010ac30028 _dispatch_root_queue_drain + 351
18  libdispatch.dylib                   0x000000010ac309cd _dispatch_worker_thread2 + 130
19  libsystem_pthread.dylib             0x000000010b006169 _pthread_wqthread + 1387
20  libsystem_pthread.dylib             0x000000010b005be9 start_wqthread + 13
2018-10-28 09:01:06.956276-0400 Gov4Me App[24587:13858294] [reports] Main Thread Checker: UI API called on a background thread: -[UILabel setText:]
PID: 24587, TID: 13858294, Thread name: (none), Queue name: NSOperationQueue 0x6000020fce20 (QOS: UNSPECIFIED), QoS: 0
Backtrace:
4   Gov4Me App                          0x0000000106a33f78 $S10Gov4Me_App18MyElectedOfficialsC6SubmityyypFy10Foundation4DataVSg_So13NSURLResponseCSgs5Error_pSgtcfU_ + 2664
5   Gov4Me App                          0x0000000106a3420d $S10Gov4Me_App18MyElectedOfficialsC6SubmityyypFy10Foundation4DataVSg_So13NSURLResponseCSgs5Error_pSgtcfU_TA + 13
6   Gov4Me App                          0x0000000106a1f820 $S10Foundation4DataVSgSo13NSURLResponseCSgs5Error_pSgIegggg_So6NSDataCSgAGSo7NSErrorCSgIeyByyy_TR + 336
7   CFNetwork                           0x0000000109784ef0 __75-[__NSURLSessionLocal taskForClass:request:uploadFile:bodyData:completion:]_block_invoke + 19
8   CFNetwork                           0x000000010979b0bc __49-[__NSCFLocalSessionTask _task_onqueue_didFinish]_block_invoke + 172
9   Foundation                          0x0000000106f8119d __NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__ + 7
10  Foundation                          0x0000000106f810a4 -[NSBlockOperation main] + 68
11  Foundation                          0x0000000106f7de13 -[__NSOperationInternal _start:] + 689
12  Foundation                          0x0000000106f83e4a __NSOQSchedule_f + 227
13  libdispatch.dylib                   0x000000010ac1e5d1 _dispatch_call_block_and_release + 12
14  libdispatch.dylib                   0x000000010ac1f63e _dispatch_client_callout + 8
15  libdispatch.dylib                   0x000000010ac22589 _dispatch_continuation_pop + 565
16  libdispatch.dylib                   0x000000010ac21963 _dispatch_async_redirect_invoke + 859
17  libdispatch.dylib                   0x000000010ac30028 _dispatch_root_queue_drain + 351
18  libdispatch.dylib                   0x000000010ac309cd _dispatch_worker_thread2 + 130
19  libsystem_pthread.dylib             0x000000010b006169 _pthread_wqthread + 1387
20  libsystem_pthread.dylib             0x000000010b005be9 start_wqthread + 13

您可以看到JSON响应字符串包含有效的格式化JSON数据,但从未将其添加到我的数据模型中,而且我无法弄清原因。一直试图解决这个问题两个星期都没有结果。如果有人可以提供任何见解,我将不胜感激。

我在这里尝试过的线程上找到了一种解决方案,但是它不起作用,将content-type标头值设置为使用JSON,

request.addValue("application/json", forHTTPHeaderField: "Content-Type")

但是当我尝试这种方法时,响应字符串返回完全为空。

0 个答案:

没有答案