NSJSONSerialization nasıl kullanılır


156

Bir JSON dizesi var (PHP'den json_encode()şöyle görünüyor:

[{"id": "1", "name":"Aaa"}, {"id": "2", "name":"Bbb"}]

Bunu iPhone uygulamam için bir tür veri yapısına ayrıştırmak istiyorum. Bana sözlükler dizisini sahip olacaktır için dizideki 0 eleman tuşlarıyla bir sözlük olduğu bu yüzden, en iyi şey sanırım "id" => "1"ve "name" => "Aaa".

NSJSONSerializationVerileri nasıl sakladığını anlamıyorum . İşte şimdiye kadar benim kod:

NSError *e = nil;
NSDictionary *JSON = [NSJSONSerialization 
    JSONObjectWithData: data 
    options: NSJSONReadingMutableContainers 
    error: &e];

Bu sadece başka bir web sitesinde örnek olarak gördüğüm bir şey. JSONNesnelerin sayısını ve bunun gibi şeyleri yazdırarak nesne üzerinde bir okumaya çalışıyorum , ama her zaman alıyorum EXC_BAD_ACCESS.

NSJSONSerializationYukarıdaki JSON'u ayrıştırmak ve bahsettiğim veri yapısına dönüştürmek için nasıl kullanabilirim ?


sizin veri değişken muhtemelen nil
d.lebedev

Bunu zaten test etmedim.
Logan Serman

Hata nesnesinde ilgili herhangi bir bilgi olup olmadığını görmeye çalıştınız mı?
Monolo

Yanıtlar:


214

Kök json nesneniz bir sözlük değil, bir dizidir:

[{"id": "1", "name":"Aaa"}, {"id": "2", "name":"Bbb"}]

Bu, nasıl ele alınacağına dair net bir resim verebilir:

NSError *e = nil;
NSArray *jsonArray = [NSJSONSerialization JSONObjectWithData: data options: NSJSONReadingMutableContainers error: &e];

if (!jsonArray) {
  NSLog(@"Error parsing JSON: %@", e);
} else {
   for(NSDictionary *item in jsonArray) {
      NSLog(@"Item: %@", item);
   }
}

Teşekkürler ben bunu deneyeceğim, ama [JSON count]bana EXC_BAD_ACCESS vermek yerine bir şey döndürmemeliyim?
Logan Serman

Bu yüzden, çek olup olmadığını kontrol ettim !jsonArrayve hatayı yazdırdım. Bu, ayrıştırma sırasında meydana gelen herhangi bir hatayı görüntülemelidir.
rckoenes

1
@ xs2bush hayır, yaratmadığınız için otomatik jsonArrayçalıştırma olmalıdır.
rckoenes

@Logan: Evet, [JSON sayısı] bir değer döndürmelidir. Zombilerle ilgili aşağıdaki cevabımı görün. EXC_BAD_ACCESS neredeyse her zaman zombi ile ilgilidir.
Olie

Bu durumda, öğe verilen JSON anahtar / değer çiftindeki anahtardır. For döngüsü, JSON anahtarlarımın her birini mükemmel şekilde çıktılamak için çalışır. Ancak zaten istediğim değerin anahtarını biliyorum, yani 'anahtar'. Bu anahtarın değerini alma ve günlüğe kaydetme çabalarım başarısız oldu. Başka bir fikir var mı?
Thomas Clowes

75

Alınan json bir dizi veya sözlük olup olmadığını kontrol etmek için benim kod budur:

NSError *jsonError = nil;
id jsonObject = [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:&jsonError];

if ([jsonObject isKindOfClass:[NSArray class]]) {
    NSLog(@"its an array!");
    NSArray *jsonArray = (NSArray *)jsonObject;
    NSLog(@"jsonArray - %@",jsonArray);
}
else {
    NSLog(@"its probably a dictionary");
    NSDictionary *jsonDictionary = (NSDictionary *)jsonObject;
    NSLog(@"jsonDictionary - %@",jsonDictionary);
}

Bu seçenekler için denedim: kNilOptions ve NSJSONReadingMutableContainers ve her ikisi için de doğru çalışıyor.

Açıkçası, asıl kod if-else bloğu içinde NSArray veya NSDictionary işaretçisini oluşturduğum bu şekilde olamaz.


29

Benim için çalışıyor. Sizin datanesne muhtemelen nilrckoenes belirtildiği gibi kök nesnesi (değişebilir) dizi olmalıdır ve. Bu koda bakın:

NSString *jsonString = @"[{\"id\": \"1\", \"name\":\"Aaa\"}, {\"id\": \"2\", \"name\":\"Bbb\"}]";
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
NSError *e = nil;
NSMutableArray *json = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&e];
NSLog(@"%@", json);

(JSON dizesindeki tırnak işaretleri ters eğik çizgilerden kaçmak zorunda kaldım.)


9

Kodunuz bir sonuç NSArraydeğil NSDictionary, bir örnek olması dışında iyi görünüyor , işte bir örnek:

İlk iki satır sadece JSON ile bir veri nesnesi oluşturur.

NSString *jsonString = @"[{\"id\": \"1\", \"name\":\"Aaa\"}, {\"id\": \"2\", \"name\":\"Bbb\"}]";
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];

NSError *e;
NSMutableArray *jsonList = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&e];
NSLog(@"jsonList: %@", jsonList);

NSLog içerikleri (sözlüklerin listesi):

jsonList: (
           {
               id = 1;
               name = Aaa;
           },
           {
               id = 2;
               name = Bbb;
           }
           )

Bu seçeneğin anlamı (NSJSONReadingMutableContainers). Ben kNilOption ve her şey iyi çalışıyor. Bana bu seçeneği kullanma amacını söyle
Zar E Ahmer

Google'da en çok hit NSJSONReadingMutableLeaves:: "JSON nesne grafiğindeki yaprak dizelerinin NSMutableString örnekleri olarak oluşturulduğunu belirtir."
zaph

Peki ya MutableContainer
Zar E Ahmer

Hata! Yine üst Google sonucundan:: NSJSONReadingMutableContainers"Dizilerin ve sözlüklerin değiştirilebilir nesneler olarak oluşturulduğunu belirtir."
zaph

1
Bunlar yalnızca döndürülen JSON nesnesini değiştirmeyi ve geri kaydetmeyi planlıyorsanız yardımcı olur. Her iki durumda da, nesneler büyük olasılıkla otomatik olarak yayımlanan nesnelerdir ve bu temel neden gibi görünmektedir.
Deepak GM

6
[{"id": "1", "name":"Aaa"}, {"id": "2", "name":"Bbb"}]

Yukarıdaki JSON verilerinde, sözlük sayısını düzenleyen bir dizimiz olduğunu gösteriyoruz.

Ayrıştırmak için bu kodu kullanmanız gerekir:

NSError *e = nil;
NSArray *JSONarray = [NSJSONSerialization JSONObjectWithData: data options: NSJSONReadingMutableContainers error: &e];
        for(int i=0;i<[JSONarray count];i++)
        {
            NSLog(@"%@",[[JSONarray objectAtIndex:i]objectForKey:@"id"]);
             NSLog(@"%@",[[JSONarray objectAtIndex:i]objectForKey:@"name"]);
        }

Hızlı 3/3 + için

   //Pass The response data & get the Array
    let jsonData = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as! [AnyObject]
    print(jsonData)
    // considering we are going to get array of dictionary from url

    for  item  in jsonData {
        let dictInfo = item as! [String:AnyObject]
        print(dictInfo["id"])
        print(dictInfo["name"])
    }

3

Aşağıdaki kod, bir web sunucusundan bir JSON nesnesi alır ve bir NSDictionary ayrıştırır. Bu örnek için basit bir JSON yanıtı döndüren openweathermap API kullandım. Basitleştirmek için, bu kod senkronize istekler kullanır.

   NSString *urlString   = @"http://api.openweathermap.org/data/2.5/weather?q=London,uk"; // The Openweathermap JSON responder
   NSURL *url            = [[NSURL alloc]initWithString:urlString];
   NSURLRequest *request = [NSURLRequest requestWithURL:url];
   NSURLResponse *response;
   NSData *GETReply      = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
   NSDictionary *res     = [NSJSONSerialization JSONObjectWithData:GETReply options:NSJSONReadingMutableLeaves|| NSJSONReadingMutableContainers error:nil];
   Nslog(@"%@",res);

Sanırım cevabınız en iyi cevap olmalı çünkü JSON yapısına erişmenin en hızlı yolu gibi görünüyor.
Porizm

2
Seçenekler iki | tek bir | çünkü bitli ORed olmaları gerekir.
Deepak GM

Soru ağ istekleri hakkında hiçbir şey sormuyor
Noah Gilmore

2

@rckoenes, verilerinizi JSON dizesinden nasıl doğru şekilde alacağınızı zaten gösterdi.

Sorduğunuz soruya: EXC_BAD_ACCESSneredeyse her zaman bir nesneye [otomatik-] serbest bırakıldıktan sonra erişmeye çalıştığınızda gelir. Bu JSON [de-] serileştirmesine özgü değildir, aksine, bir nesneyi alıp serbest bırakıldıktan sonra ona erişmenizle ilgilidir. JSON aracılığıyla gelmesi önemli değil.

Bunu nasıl ayıklayacağınızı açıklayan çok sayıda sayfa var - Google'a (veya SO'ya) obj-c zombie objectsve özellikle de NSZombieEnabledzombi nesnelerinizin kaynağını belirlemenize yardımcı olacak çok değerli olacak. ("Zombi", bir nesneyi serbest bırakıp ona bir işaretçi tutup daha sonra başvurmaya çalıştığınızda buna denir.)


1

Do / try / catch bloğu ile Xcode 7 (Beta) üzerinde Swift 2.0:

// MARK: NSURLConnectionDataDelegate

func connectionDidFinishLoading(connection:NSURLConnection) {
  do {
    if let response:NSDictionary = try NSJSONSerialization.JSONObjectWithData(receivedData, options:NSJSONReadingOptions.MutableContainers) as? Dictionary<String, AnyObject> {
      print(response)
    } else {
      print("Failed...")
    }
  } catch let serializationError as NSError {
    print(serializationError)
  }
}

1

NOT: Swift 3 için . JSON Dizeniz Sözlük yerine Array döndürüyor. Lütfen aşağıdakileri deneyin:

        //Your JSON String to be parsed
        let jsonString = "[{\"id\": \"1\", \"name\":\"Aaa\"}, {\"id\": \"2\", \"name\":\"Bbb\"}]";

        //Converting Json String to NSData
        let data = jsonString.data(using: .utf8)

        do {

            //Parsing data & get the Array
            let jsonData = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as! [AnyObject]

            //Print the whole array object
            print(jsonData)

            //Get the first object of the Array
            let firstPerson = jsonData[0] as! [String:Any]

            //Looping the (key,value) of first object
            for (key, value) in firstPerson {
                //Print the (key,value)
                print("\(key) - \(value) ")
            }

        } catch let error as NSError {
            //Print the error
            print(error)
        }

0
#import "homeViewController.h"
#import "detailViewController.h"

@interface homeViewController ()

@end

@implementation homeViewController

- (id)initWithStyle:(UITableViewStyle)style
{
    self = [super initWithStyle:style];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.tableView.frame = CGRectMake(0, 20, 320, 548);
    self.title=@"Jason Assignment";

    // Uncomment the following line to preserve selection between presentations.
    // self.clearsSelectionOnViewWillAppear = NO;

    // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
    // self.navigationItem.rightBarButtonItem = self.editButtonItem;
    [self clientServerCommunication];
}

-(void)clientServerCommunication
{
    NSURL *url = [NSURL URLWithString:@"http://182.72.122.106/iphonetest/getTheData.php"];
    NSURLRequest *req = [NSURLRequest requestWithURL:url];
    NSURLConnection *connection = [[NSURLConnection alloc]initWithRequest:req delegate:self];
    if (connection)
    {
        webData = [[NSMutableData alloc]init];
    }
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
    [webData setLength:0];
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    [webData appendData:data];
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    NSDictionary *responseDict = [NSJSONSerialization JSONObjectWithData:webData options:0 error:nil];

    /*Third party API
     NSString *respStr = [[NSString alloc]initWithData:webData encoding:NSUTF8StringEncoding];
     SBJsonParser *objSBJson = [[SBJsonParser alloc]init];
     NSDictionary *responseDict = [objSBJson objectWithString:respStr]; */
    resultArray = [[NSArray alloc]initWithArray:[responseDict valueForKey:@"result"]];
    NSLog(@"resultArray: %@",resultArray);
    [self.tableView reloadData];
}


- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
//#warning Potentially incomplete method implementation.
    // Return the number of sections.
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
//#warning Incomplete method implementation.
    // Return the number of rows in the section.
    return [resultArray count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
    }

    // Configure the cell...
    cell.textLabel.text = [[resultArray objectAtIndex:indexPath.row] valueForKey:@"name"];
    cell.detailTextLabel.text = [[resultArray objectAtIndex:indexPath.row] valueForKey:@"designation"];

    NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:[[resultArray objectAtIndex:indexPath.row] valueForKey:@"image"]]];
cell.imageview.image = [UIImage imageWithData:imageData];

    return cell;
}

/*
// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Return NO if you do not want the specified item to be editable.
    return YES;
}
*/

/*
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        // Delete the row from the data source
        [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
    }   
    else if (editingStyle == UITableViewCellEditingStyleInsert) {
        // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
    }   
}
*/

/*
// Override to support rearranging the table view.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
}
*/

/*
// Override to support conditional rearranging of the table view.
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Return NO if you do not want the item to be re-orderable.
    return YES;
}
*/


#pragma mark - Table view delegate

// In a xib-based application, navigation from a table can be handled in -tableView:didSelectRowAtIndexPath:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Navigation logic may go here, for example:
     //Create the next view controller.
    detailViewController *detailViewController1 = [[detailViewController alloc]initWithNibName:@"detailViewController" bundle:nil];

 //detailViewController *detailViewController = [[detailViewController alloc] initWithNibName:@"detailViewController" bundle:nil];

 // Pass the selected object to the new view controller.

 // Push the view controller.
 detailViewController1.nextDict = [[NSDictionary alloc]initWithDictionary:[resultArray objectAtIndex:indexPath.row]];
 [self.navigationController pushViewController:detailViewController1 animated:YES];

    // Pass the selected object to the new view controller.

    // Push the view controller.
  //  [self.navigationController pushViewController:detailViewController animated:YES];
}



@end

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.
    empName.text=[nextDict valueForKey:@"name"];
    deptlbl.text=[nextDict valueForKey:@"department"];
    designationLbl.text=[nextDict valueForKey:@"designation"];
    idLbl.text=[nextDict valueForKey:@"id"];
    salaryLbl.text=[nextDict valueForKey:@"salary"];
    NSString *ImageURL = [nextDict valueForKey:@"image"];
    NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:ImageURL]];
    image.image = [UIImage imageWithData:imageData];
}

0

Sorun, nesnelerin otomatik olarak serbest bırakılmasıyla ilgili gibi görünüyor. NSJSONSerialization JSONObjectWithData, bazı otomatik olarak yayınlanmış nesneler oluşturuyor ve size geri aktarıyor. Bunu farklı bir iş parçacığına götürmeye çalışırsanız, farklı bir iş parçacığında yeniden yerleştirilemediğinden çalışmaz.

Hile, sözlüğün veya dizinin değiştirilebilir bir kopyasını oluşturmayı ve kullanmayı denemek olabilir.

NSError *e = nil;
id jsonObject = [NSJSONSerialization 
JSONObjectWithData: data 
options: NSJSONReadingMutableContainers 
error: &e] mutableCopy];

Bir NSDictionary NSArray olarak tedavi edilmesi, Kötü erişim istisnasına neden olmaz, bunun yerine bir yöntem çağrısı yapıldığında muhtemelen çökecektir.

Ayrıca, seçenekler burada gerçekten önemli olmayabilir ama NSJSONReadingMutableContainers | NSJSONReadingMutableContainers | NSJSONReadingAllowFragments ancak otomatik olarak yayınlanmış nesneler olsalar bile bu sorunu çözemeyebilir.


Deepak, NSJSONReadingMutableContainers'ı iki kez listelediniz. Birinin NSJSONReadingMutableLeaves olması mı demek istediniz?
jk7

0

kötü örnek, şöyle bir şey olmalı {"id": 1, "name": "ad olarak bir şey"}

sayı ve dize karıştırılır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.