如何将JSON加载到TableView中?

时间:2016-11-08 14:50:22

标签: json swift

我正在尝试将练习JSON加载到表视图中,我有一个服务函数,它将来自源的数据作为JSON,以及一个视图控制器,其中包含我想要将信息加载到的表。代码中没有错误,但表加载空白行,调试部分通过打印命令显示JSON数据。我是一个初学者,所以我确定我错过了一个核心元素,但不能解决它!

api服务

package de.cowabuja.androiduriaccess;

import android.content.Intent;
import android.net.Uri;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        String uriString = "content://com.android.externalstorage.documents/document/primary%3ADCIM%2FAny%2Dir%2FtheFile.txt";
        Uri uri = Uri.parse(uriString);

        getApplicationContext().grantUriPermission(getPackageName(), uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
    }
}

查看控制器

...
E/AndroidRuntime: FATAL EXCEPTION: main
                  Process: de.cowabuja.androiduriaccess, PID: 2972
                  java.lang.RuntimeException: Unable to start activity ComponentInfo{de.cowabuja.androiduriaccess/de.cowabuja.androiduriaccess.MainActivity}: java.lang.SecurityException: Uid 10132 does not have permission to uri 0 @ content://com.android.externalstorage.documents/document/primary%3ADCIM%2FAny%2FDir%2FtheFile.txt
                      at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2646)
                      at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2707)
                      at android.app.ActivityThread.-wrap12(ActivityThread.java)
                      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1460)
                      at android.os.Handler.dispatchMessage(Handler.java:102)
                      at android.os.Looper.loop(Looper.java:154)
                      at android.app.ActivityThread.main(ActivityThread.java:6077)
                      at java.lang.reflect.Method.invoke(Native Method)
                      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
                   Caused by: java.lang.SecurityException: Uid 10132 does not have permission to uri 0 @ content://com.android.externalstorage.documents/document/primary%3ADCIM%2FAny%2FDir%2theFile.txt
                      at android.os.Parcel.readException(Parcel.java:1683)
                      at android.os.Parcel.readException(Parcel.java:1636)
                      at android.app.ActivityManagerProxy.grantUriPermission(ActivityManagerNative.java:4808)
                      at android.app.ContextImpl.grantUriPermission(ContextImpl.java:1655)
                      at android.content.ContextWrapper.grantUriPermission(ContextWrapper.java:712)
                      at de.cowabuja.androiduriaccess.MainActivity.onCreate(MainActivity.java:19)
                      at android.app.Activity.performCreate(Activity.java:6664)
                      at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118)
                      at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2599)
                      at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2707) 
                      at android.app.ActivityThread.-wrap12(ActivityThread.java) 
                      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1460) 
                      at android.os.Handler.dispatchMessage(Handler.java:102) 
                      at android.os.Looper.loop(Looper.java:154) 
                      at android.app.ActivityThread.main(ActivityThread.java:6077) 
                      at java.lang.reflect.Method.invoke(Native Method) 
                      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865) 
                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755) 
...

2 个答案:

答案 0 :(得分:1)

你应该异步加载你的JSON,这意味着你应该在方法中有一个关闭,使你的alamofire调用。

    class ExerciseDatabaseController: UIViewController, UITableViewDataSource, UITableViewDelegate {
    //these should start with lower cases(exerciseSearchField), never uppercased
    @IBOutlet weak var ExerciseSearchField: UISearchBar!
    @IBOutlet weak var ExercisesTableView: UITableView!

    var arrRes = [[String:AnyObject]]() // Array of dictionary

    override func viewDidLoad() {
      super.viewDidLoad()
      //you said you would use these delegates up top when you created the class, so you have to set them
      ExercisesTableView.delegate = self
      ExercisesTableView.dataSource = self
      fetchData()
      // Do any additional setup after loading the view.
    }

    //this method will make the api call
    //you'll notice that if you set breakpoints, it will reach the end of the method before hitting self?.arrRes = dictArray
    //this is normal and how asynchronous calls work, look into tableview threading for a deeper explanation of why that is. It is super important to understand threading in iOS
    //once it gets data back from the API call, it will go to the main thread and tell the tableview to reload with that data

    func fetchData() {
      ApiService.getExerciseData { [weak self] (dictArray) in
        self?.arrRes = dictArray
        print(self?.arrRes)
        if self?.arrRes.count > 0 {
          DispatchQueue.main.async {
            self?.ExercisesTableView.reloadData()
          }
        }
      }
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
      return arrRes.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
      let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
      var dict = arrRes[indexPath.row]
      cell.textLabel?.text = dict["name"] as? String
      cell.detailTextLabel?.text = dict["description"] as? String
      return cell
    }

所以现在我们已经进行了异步调用(一般情况下,只要您通过互联网调用直观地显示信息,而这些调用尚未预先加载/保存在应用程序的某个地方)。

接下来,我们希望在tableview加载时在tableview中显示此信息。

<?php 

if($_SERVER['REQUEST_METHOD']=='POST'){
    //Getting values 
    $username = $_POST['email'];
    $password = $_POST['password'];

    //Creating sql query
    $sql = "SELECT * FROM users WHERE email='$username' AND password='$password'";

    //importing dbConnect.php script 
    require_once('dbConnect.php');

    //executing query
    $result = mysqli_query($con,$sql);

    //fetching result
    $check = mysqli_fetch_array($result);

    //if we got some result 
    if(isset($check)){
        //displaying success 
        echo "success";
    }else{
        //displaying failure
        echo "failure";
    }
    mysqli_close($con);
}

你会看到我在上面使用过[弱自我]。有关异步互联网调用/使用闭包时为何需要更多解释的原因,您可以在此处阅读: http://krakendev.io/blog/weak-and-unowned-references-in-swift

有许多其他资源可供阅读iOS中弱弱和强引用/父子项目的快速谷歌搜索。此外,在iOS中研究异步/同步。这两个主题在开始时都非常重要。

答案 1 :(得分:0)

收到异步请求中的JSON数据后,重新加载tableView。所以你的

self.ExercisesTableView.reloadData()

将进入内部

Alamofire.request("https://wger.de/api/v2/exercise/?format=json").responseJSON { (responseData) -> Void in
    if((responseData.result.value) != nil) {
        swiftyJsonVar = JSON(responseData.result.value!)
        print(swiftyJsonVar ?? nil)
    }
}