Unarchive custom object with secure coding in iOS - ios

I'm encoding an array of objects that conform to NSSecureCoding successfully like this.
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:array requiringSecureCoding:YES error:nil];
How do I unarchive this data? I'm trying like this but it's returning nil.
NSError *error = nil;
NSArray<MyClass *> *array = [NSKeyedUnarchiver unarchivedObjectOfClass:[NSArray class] fromData:data error:&error];
This is the error it returns.
The data couldn’t be read because it isn’t in the correct format.

Here is a simple example
#interface Secure:NSObject<NSSecureCoding> {
NSString* name;
}
#property NSString* name;
#end
#implementation Secure
#synthesize name;
// Confirms to NSSecureCoding
+ (BOOL)supportsSecureCoding {
return true;
}
- (void)encodeWithCoder:(nonnull NSCoder *)coder {
[coder encodeObject:self.name forKey: #"name"];
}
- (nullable instancetype)initWithCoder:(nonnull NSCoder *)coder {
self = [self init];
if (self){
self.name = [coder decodeObjectOfClass:[NSString class] forKey:#"name"];
}
return self;
}
#end
Usage
Secure *archive = [[Secure alloc] init];
archive.name = #"ARC";
NSArray* array = #[archive];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:array requiringSecureCoding:YES error:nil];
NSArray<Secure *> *unarchive = [NSKeyedUnarchiver unarchivedObjectOfClass:[NSObject class] fromData:data error:nil];
NSLog(#"%#", unarchive.firstObject.name);

Related

How to check the user is logged in or not in objective c?

I'm trying to do login page and logout page. I completed the api calling and login successfully, but i am trying to check whether the user is already logged in or not. if the user is logged in and kills the app, and after sometimes the user opens the app means the app should show the home page, but my app shows the sign in page. I tried the below code along with api calling.
NSString *mailID=mailTextField.text;
NSString *password=passwordTextField.text;
NSString *noteDataString = [NSString stringWithFormat:#"email=%#&password=%#",mailID,password];
NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
sessionConfiguration.HTTPAdditionalHeaders = #{#"language": #"en"};
NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfiguration];
NSURL *url = [NSURL URLWithString:#"https://qa-user.moneyceoapp.com/user/login"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
NSData *data = [noteDataString dataUsingEncoding:NSUTF8StringEncoding];
request.HTTPBody=data;
request.HTTPMethod = #"POST";
NSURLSessionDataTask *postDataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSHTTPURLResponse *httpResponse= (NSHTTPURLResponse *)response;
if(httpResponse.statusCode == 200)
{
NSDictionary *responseDictionary = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSLog(#"The response is - %#",responseDictionary);
NSInteger status = [[responseDictionary objectForKey:#"status"] integerValue];
if(status == 1)
{
NSLog(#"Login SUCCESS");
NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
[defs setObject:mailID forKey:#"email"];
[defs setObject:password forKey:#"password"];
[defs synchronize];
[[NSOperationQueue mainQueue] addOperationWithBlock:^
{
if(mailID && password)
{
HomePageVC *homepageVC = [[HomePageVC alloc] initWithNibName:#"HomePageVC" bundle:nil];
[self.navigationController pushViewController:homepageVC animated:YES];
}
}];
}
else
{
[[NSOperationQueue mainQueue] addOperationWithBlock:^
{
NSLog(#"Login FAILURE");
[self alertView:#"Invalid user account"];
}];
}
}
else
{
NSLog(#"Error");
}
}];
[postDataTask resume];
I use class that uses NSUserDefaults to create a dictionary with the parameters of the user's login information. Also, I use Boolean values to check a value equivalently named joinedApp.
*DataModel.h*
//
#class Message;
// The main data model object
#interface DataModel : NSObject
// The complete history of messages this user has sent and received, in
// chronological order (oldest first).
#property (nonatomic, strong) NSMutableArray* messages;
// Loads the list of messages from a file.
- (void)loadMessages;
// Saves the list of messages to a file.
- (void)saveMessages;
// Adds a message that the user composed himself or that we received through
// a push notification. Returns the index of the new message in the list of
// messages.
- (int)addMessage:(Message*)message;
// Get and set the user's nickname.
- (NSString*)nickname;
- (void)setNickname:(NSString*)name;
// Get and set the secret code that the user is registered for.
- (NSString*)secretCode;
- (void)setSecretCode:(NSString*)string;
// Determines whether the user has successfully joined a chat.
- (BOOL)joinedChat;
- (void)setJoinedChat:(BOOL)value;
- (BOOL)joinedApp;
- (void)setJoinedApp:(BOOL)value;
- (NSString*)userId;
- (NSString*)deviceToken;
- (void)setDeviceToken:(NSString*)token;
#end
DataModel.m
#import "DataModel.h"
#import "Message.h"
#import "ViewController.h"
// We store our settings in the NSUserDefaults dictionary using these keys
static NSString* const NicknameKey = #"Nickname";
static NSString* const SecretCodeKey = #"SecretCode";
static NSString* const JoinedChatKey = #"JoinedChat";
static NSString* const JoinedAppKey = #"JoinedApp";
static NSString* const DeviceTokenKey = #"DeviceToken";
static NSString* const UserId = #"UserId";
#implementation DataModel
+ (void)initialize
{
if (self == [DataModel class])
{
// Register default values for our settings
[[NSUserDefaults standardUserDefaults] registerDefaults:
#{NicknameKey: #"",
SecretCodeKey: #"",
JoinedChatKey: #0,
JoinedAppKey: #0,
DeviceTokenKey: #"0",
UserId:#""}];
}
}
// Returns the path to the Messages.plist file in the app's Documents directory
- (NSString*)messagesPath
{
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString* documentsDirectory = paths[0];
return [documentsDirectory stringByAppendingPathComponent:#"Messages.plist"];
}
- (void)loadMessages
{
NSString* path = [self messagesPath];
if ([[NSFileManager defaultManager] fileExistsAtPath:path])
{
// We store the messages in a plist file inside the app's Documents
// directory. The Message object conforms to the NSCoding protocol,
// which means that it can "freeze" itself into a data structure that
// can be saved into a plist file. So can the NSMutableArray that holds
// these Message objects. When we load the plist back in, the array and
// its Messages "unfreeze" and are restored to their old state.
NSData* data = [[NSData alloc] initWithContentsOfFile:path];
NSKeyedUnarchiver* unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
self.messages = [unarchiver decodeObjectForKey:#"Messages"];
[unarchiver finishDecoding];
}
else
{
self.messages = [NSMutableArray arrayWithCapacity:20];
}
}
- (void)saveMessages
{
NSMutableData* data = [[NSMutableData alloc] init];
NSKeyedArchiver* archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
[archiver encodeObject:self.messages forKey:#"Messages"];
[archiver finishEncoding];
[data writeToFile:[self messagesPath] atomically:YES];
}
- (int)addMessage:(Message*)message
{
[self.messages addObject:message];
[self saveMessages];
return self.messages.count - 1;
}
- (NSString*)nickname
{
return [[NSUserDefaults standardUserDefaults] stringForKey:NicknameKey];
}
- (void)setNickname:(NSString*)name
{
[[NSUserDefaults standardUserDefaults] setObject:name forKey:NicknameKey];
}
- (NSString*)secretCode
{
return [[NSUserDefaults standardUserDefaults] stringForKey:SecretCodeKey];
}
- (void)setSecretCode:(NSString*)string
{
[[NSUserDefaults standardUserDefaults] setObject:string forKey:SecretCodeKey];
}
- (BOOL)joinedApp
{
return [[NSUserDefaults standardUserDefaults] boolForKey:JoinedAppKey];
}
- (void)setJoinedApp:(BOOL)value
{
[[NSUserDefaults standardUserDefaults] setBool:value forKey:JoinedAppKey];
}
- (BOOL)joinedChat
{
return [[NSUserDefaults standardUserDefaults] boolForKey:JoinedChatKey];
}
- (void)setJoinedChat:(BOOL)value
{
[[NSUserDefaults standardUserDefaults] setBool:value forKey:JoinedChatKey];
}
- (NSString*)userId
{
NSString *userId = [[NSUserDefaults standardUserDefaults] stringForKey:UserId];
if (userId == nil || userId.length == 0) {
userId = [[[NSUUID UUID] UUIDString] stringByReplacingOccurrencesOfString:#"-" withString:#""];
[[NSUserDefaults standardUserDefaults] setObject:userId forKey:UserId];
}
return userId;
}
- (NSString*)deviceToken //used in appdelegate
{
return [[NSUserDefaults standardUserDefaults] stringForKey:DeviceTokenKey];
}
- (void)setDeviceToken:(NSString*)token //used in app delegate
{
[[NSUserDefaults standardUserDefaults] setObject:token forKey:DeviceTokenKey];
}
#end
I then call the message in the viewIsLoaded method and print verification in the debugger window.
*ViewController.h*
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#class DataModel;
#interface ViewController : UIViewController
#property (nonatomic, strong, readonly) DataModel* dataModel;
#property (retain, strong) UIImage* Image;
#end
ViewController.m
#import "ViewController.h"
#import "DataModel.h"
#import "PushChatStarter-Swift.h"
#implementation ViewController
- (id) initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
_dataModel = [[DataModel alloc] init];
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
MockApiclient *client = [MockApiclient new];
[client executeRequest];
[self.dataModel setJoinedApp:YES];
if ([_dataModel joinedApp] == YES)
{
NSLog(#"hi from viewcontroller 1 ");//Here you know which button has pressed
}
...
}
 NSUserDefaults:
An interface to the user’s defaults database, where you store key-value pairs persistently across launches of your app.
I also call joinedApp from the login method being used along with other messages.

Troubles storing and loading custom object into NSUserDefaults Objective-C

I've been trying to store and recover from the NSUserDefaults an Array of custom objects in my project but it seems something is going wrong. I've researched a lot about this issue but I couldn't find any answer to my problem.
It seems that the storing it's done OK because I don't get any error when saving data in NSUserDefaults, the problem comes when I try to get back those data: the app will crash completely with libc++abi.dylib: terminating with uncaught exception of type NSException error.
Here's my code:
Wine.h
#import <Foundation/Foundation.h>
#import UIKit;
#define NO_RATING -1
#interface WineModel : NSObject <NSCoding>
#property(copy, nonatomic) NSString *type;
#property(strong, nonatomic) UIImage *photo;
#property(strong, nonatomic) NSURL *photoURL;
#property(strong, nonatomic) NSURL *wineCompanyWeb;
#property(copy, nonatomic) NSString *notes;
#property(copy, nonatomic) NSString *origin;
#property(nonatomic) int rating;
#property(strong, nonatomic) NSArray *grapes;
#property(copy, nonatomic) NSString *name;
#property(copy, nonatomic) NSString *wineCompanyName;
- (id) initWithCoder: (NSCoder *) decoder;
- (void) encodeWithCoder: (NSCoder *) encoder;
//SOME OTHER METHODS...//
-(id) initWithName: (NSString *) aName
wineCompanyName: (NSString *) aWineCompanyName
type: (NSString *) aType
origin: (NSString *) anOrigin
grapes: (NSArray *) arrayOfGrapes
wineCompanyWeb: (NSURL *) aURL
notes: (NSString *) aNotes
rating: (int) aRating
photoURL: (NSURL *) aPhotoURL;
//For JSON
-(id) initWithDictionary: (NSDictionary *) aDict;
#end
Wine.m
#import "WineModel.h"
#implementation WineModel
#synthesize photo = _photo;
#pragma mark - Properties
-(UIImage *) photo {
//SOME MORE CODE...
return _photo;
}
- (id) initWithCoder:(NSCoder *)decoder {
if (self = [super init]) {
self.name = [decoder decodeObjectForKey:#"name"];
self.wineCompanyName = [decoder decodeObjectForKey:#"company"];
self.type = [decoder decodeObjectForKey:#"type"];
self.origin = [decoder decodeObjectForKey:#"origin"];
self.grapes = [self extractGrapesFromJSONArray:[decoder decodeObjectForKey:#"grapes"]];
self.wineCompanyWeb = [NSURL URLWithString:[decoder decodeObjectForKey:#"wine_web"]];
self.notes = [decoder decodeObjectForKey:#"notes"];
self.rating = [[decoder decodeObjectForKey:#"rating"] intValue];
self.photoURL = [NSURL URLWithString:[decoder decodeObjectForKey:#"picture"]];
}
return self;
}
- (void) encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:self.name forKey:#"name"];
[encoder encodeObject:self.wineCompanyWeb forKey:#"company"];
[encoder encodeObject:self.type forKey:#"type"];
[encoder encodeObject:self.origin forKey:#"origin"];
[encoder encodeObject:self.grapes forKey:#"grapes"];
[encoder encodeObject:self.wineCompanyWeb forKey:#"wine_web"];
[encoder encodeObject:self.notes forKey:#"notes"];
[encoder encodeInt:self.rating forKey:#"rating"];
[encoder encodeObject:self.photoURL forKey:#"picture"];
}
#pragma mark - Init
-(id) initWithName: (NSString *) aName
wineCompanyName: (NSString *) aWineCompanyName
type: (NSString *) aType
origin: (NSString *) anOrigin
grapes: (NSArray *) arrayOfGrapes
wineCompanyWeb: (NSURL *) aURL
notes: (NSString *) aNotes
rating: (int) aRating
photoURL: (NSURL *) aPhotoURL {
if(self==[super init]) {
_name = aName;
_wineCompanyName = aWineCompanyName;
_type = aType;
_origin = anOrigin;
_grapes = arrayOfGrapes;
_wineCompanyWeb = aURL;
_notes = aNotes;
_rating = aRating;
_photoURL = aPhotoURL;
}
return self;
}
#pragma mark - JSON
-(id) initWithDictionary:(NSDictionary *)aDict {
return [self initWithName:[aDict objectForKey:#"name"]
wineCompanyName:[aDict objectForKey:#"company"]
type:[aDict objectForKey:#"type"]
origin:[aDict objectForKey:#"origin"]
grapes:[self extractGrapesFromJSONArray:[aDict objectForKey:#"grapes"]]
wineCompanyWeb:[NSURL URLWithString:[aDict objectForKey:#"wine_web"]]
notes:[aDict objectForKey:#"notes"]
rating:[[aDict objectForKey:#"rating"]intValue]
photoURL:[NSURL URLWithString:[aDict objectForKey:#"picture"]]
];
}
-(NSArray *) extractGrapesFromJSONArray: (NSArray *)JSONArray {
//SOME MORE CODE...
return grapes;
}
#end
This is the wine class. It has the <NSCoding> protocol and both methods (id) initWithCoder: (NSCoder *) decoder; and (void) encodeWithCoder: (NSCoder *) encoder;. So far I looks OK, lets move on to the next class:
Winery.h
#import <Foundation/Foundation.h>
#import "Wine.h"
#define RED_WINE_KEY #"Red"
#define WHITE_WINE_KEY #"White"
#define OTHER_WINE_KEY #"Others"
#interface WineryModel : NSObject
#property (strong, nonatomic) NSMutableArray *redWines;
#property (strong, nonatomic) NSMutableArray *whiteWines;
#property (strong, nonatomic) NSMutableArray *otherWines;
#property(readonly, nonatomic) int redWineCount;
#property(readonly, nonatomic) int whiteWineCount;
#property(readonly, nonatomic) int otherWineCount;
-(WineModel *) redWineAtIndex: (NSUInteger) index;
-(WineModel *) whiteWineAtIndex: (NSUInteger) index;
-(WineModel *) otherWineAtIndex: (NSUInteger) index;
#end
Winery.m
#import "Winery.h"
#implementation WineryModel
#pragma mark - Properties
-(int) redWineCount {
return [self.redWines count];
}
-(int) whiteWineCount {
return [self.whiteWines count];
}
-(int) otherWineCount {
return [self.otherWines count];
}
-(id) init {
if(self == [super init]) {
NSUserDefaults *userDefault=[NSUserDefaults standardUserDefaults];
//Check if there is data stored locally
if(([[[userDefault dictionaryRepresentation] allKeys] containsObject:#"redWines"])
&&([[[userDefault dictionaryRepresentation] allKeys] containsObject:#"whiteWines"])
&&([[[userDefault dictionaryRepresentation] allKeys] containsObject:#"otherWines"])) {
if([userDefault objectForKey:#"redWines"] != nil && [userDefault objectForKey:#"whiteWines"] != nil && [userDefault objectForKey:#"otherWines"] != nil) {
//Try to load data from NSUserDefaults
NSData *decodedRedWines = [userDefault objectForKey:#"redWines"];
self.redWines = [[NSKeyedUnarchiver unarchiveObjectWithData: decodedRedWines] mutableCopy]; //IT WILL CRASH HERE
NSData *decodedWhiteWines = [userDefault objectForKey:#"whiteWines"];
self.whiteWines = [[NSKeyedUnarchiver unarchiveObjectWithData: decodedWhiteWines] mutableCopy];
NSData *decodedOtherWines = [userDefault objectForKey:#"otherWines"];
self.otherWines = [[NSKeyedUnarchiver unarchiveObjectWithData: decodedOtherWines] mutableCopy];
}
} else {
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://url.com/wines.json"]]; //JSON URL
NSURLResponse *response = [[NSURLResponse alloc]init];
NSError *error;
NSData *data = [NSURLConnection sendSynchronousRequest:request
returningResponse:&response
error:&error];
if(data != nil) { //No errors
//Passing from JSON to an NSArray
NSArray * JSONObjects = [NSJSONSerialization JSONObjectWithData:data
options:kNilOptions
error:&error];
if (JSONObjects != nil) {
//No errors
for(NSDictionary *dict in JSONObjects){
WineModel *wine = [[WineModel alloc] initWithDictionary:dict];
if(wine.name != nil && wine.wineCompanyName != nil && wine.type != nil && wine.origin != nil ) {
if ([wine.type isEqualToString:RED_WINE_KEY]) {
if (!self.redWines) {
self.redWines = [NSMutableArray arrayWithObject:wine];
}
else {
[self.redWines addObject:wine];
}
}
else if ([wine.type isEqualToString:WHITE_WINE_KEY]) {
if (!self.whiteWines) {
self.whiteWines = [NSMutableArray arrayWithObject:wine];
}
else {
[self.whiteWines addObject:wine];
}
}
else {
if (!self.otherWines) {
self.otherWines = [NSMutableArray arrayWithObject:wine];
}
else {
[self.otherWines addObject:wine];
}
}
}
}
} else {
NSLog(#"JSON parsing error: %#", error.localizedDescription);
}
} else {
NSLog(#"Server error: %#", error.localizedDescription);
}
//Storing the array of wine objects in the NSUserDefaults
NSData *encodedRedWines = [NSKeyedArchiver archivedDataWithRootObject:_redWines];
[userDefault setObject:encodedRedWines forKey:#"redWines"];
NSData *encodedWhiteWines = [NSKeyedArchiver archivedDataWithRootObject:_whiteWines];
[userDefault setObject:encodedWhiteWines forKey:#"whiteWines"];
NSData *encodedOtherWines = [NSKeyedArchiver archivedDataWithRootObject:_otherWines];
[userDefault setObject:encodedOtherWines forKey:#"otherWines"];
}
}
return self;
}
-(WineModel *) redWineAtIndex: (NSUInteger) index {
return [self.redWines objectAtIndex:index];
}
-(WineModel *) whiteWineAtIndex: (NSUInteger) index{
return [self.whiteWines objectAtIndex:index];
}
-(WineModel *) otherWineAtIndex: (NSUInteger) index{
return [self.otherWines objectAtIndex:index];
}
#end
So, the first time you launch the app it will download the data from a JSON file that is in the web, then store the info in the NSUserDefaults. It seems like this step it's done correctly (at least doesn't crash at this point). The problem comes after launching the app the second time. It will check if there are local data store under the NSUserDefault, if so, it'll try to load the data and store into an NSMutableAtray. Unfortunately it won't do so, It crashes here self.redWines =[NSKeyedUnarchiver unarchiveObjectWithData: decodedRedWines]; with the error code I wrote before. When debugging, I can see that there is data when retrieving the redWineskey, but it seems like something it's going wrong.
Mind that I'm using a customized initializer (initWithDictionary) for creating my wines object instead of the default init method. I don't know if it could be the reason of the crash...
Here's the full log:
2017-05-22 20:31:30.354640+0200 App[1905:891526] -[NSTaggedPointerString objectForKey:]: unrecognized selector sent to instance 0xa5c064950b08843b
2017-05-22 20:31:30.354932+0200 App[1905:891526] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSTaggedPointerString objectForKey:]: unrecognized selector sent to instance 0xa5c064950b08843b'
*** First throw call stack:
(0x18e0bafe0 0x18cb1c538 0x18e0c1ef4 0x18e0bef54 0x18dfbad4c 0x1000591d8 0x100057dec 0x18eb0a430 0x18eb10f10 0x18eaa684c 0x18eb0a430 0x18eb09b68 0x18eb08d94 0x100061118 0x1000621d0 0x10005c120 0x19425d204 0x194469738 0x19446f1e0 0x194483d18 0x19446c474 0x18fc63884 0x18fc636f0 0x18fc63aa0 0x18e06942c 0x18e068d9c 0x18e0669a8 0x18df96da4 0x194256384 0x194251058 0x100060b90 0x18cfa559c)
libc++abi.dylib: terminating with uncaught exception of type NSException
Any ideas??
Thanks in advance!!
There is a typo in your initWithCoder method:
self.wineCompanyName = [decoder decodeObjectForKey:#"comapny"];
If that does not fix it, I would look at the NSUserDefaults documentation more closely - it says "Values returned from NSUserDefaults are immutable, even if you set a mutable object as the value." Your redWines property is defined as an NSMutableArray.
To make an immutable object mutable just call mutableCopy
#property (strong, nonatomic) NSMutableArray *redWines;
...
self.redWines = [[NSKeyedUnarchiver unarchiveObjectWithData: decodedRedWines] mutableCopy];

Getting data from a service Objective-C

am new to iOS, Getting issue with displaying data from below service data
[{
"Name": Rahul,
"FatherName": Ravinder,
"Designation": Engineering,
"Profession": Software Eng,
"Height": "5 ft 3 in",
"Weight": "134.5 lbs"
}]
below is the code what i have tried. Please help me to find the issue. Thanks In Advance.
NameDetails.m
---------------
- (void)viewDidLoad {
[super viewDidLoad];
[self callService:[appDelegate.signUpdata objectForKey:#"id"]];
}
-(void)callService:(NSString *)userid
{
[Utility showIndicator:nil view1:self.view];
JsonServicePostData = [[JsonServiceCls alloc] init];
JsonServicePostData.delegate = self;
[JsonServicePostData Getdata:userid];
}
-(void)DidFinishWebServicesPostData
{
[Utility hideIndicator];
NSMutableDictionary *dict = [[NSMutableDictionary alloc]init];
_txtName.text=[dict objectForKey:#"Name"];
_txtFName.text=[dict objectForKey:#"FatherName"];
_txtDesg.text=[dict objectForKey:#"Designation"];
_txtprof.text=[dict objectForKey:#"Profession"];
_txtHeight.text=[dict objectForKey:#"Height"];
_txtWeight.text=[dict objectForKey:#"Weight"];
}
}
+(void)makeHttpGETresponceParsingwithSerVer:(NSString *)strServer withCallBack:(void(^)(NSDictionary *dicArr,NSError *error))handler
{
NSURL *urlServer = [NSURL URLWithString:strServer];
NSURLRequest *request = [NSURLRequest requestWithURL:urlServer];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *postDataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSDictionary *res = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&error];
handler(res,error);
}];
[postDataTask resume];
}
then call your method In viewDidLoad...
[RestClient makeHttpGETresponceParsingwithSerVer:#"YOUR_URL" withCallBack:^(NSDictionary *responceDic, NSError *error) {
_txtName.text =[responceDic objectForKey:#"Name"];
_txtFName.text =[responceDic objectForKey:#"FatherName"];
_txtDesg.text =[responceDic objectForKey:#"Designation"];
_txtprof.text =[responceDic objectForKey:#"Profession"];
_txtHeight.text =[responceDic objectForKey:#"Height"];
_txtWeight.text =[responceDic objectForKey:#"Weight"];
}];
// RestClient is the class name as it is a class method, You can use instance method.
Hi The better approach is for this kind of API call activity you have to go with AFNetworking - https://github.com/AFNetworking/AFNetworking
Its Pretty simple and more powerful. Once you get the json response you have to go for Model Approach.
#import <UIKit/UIKit.h>
#interface NameDetails : NSObject
#property (nonatomic, strong) NSString * designation;
#property (nonatomic, strong) NSString * fatherName;
#property (nonatomic, strong) NSString * height;
#property (nonatomic, strong) NSString * name;
#property (nonatomic, strong) NSString * profession;
#property (nonatomic, strong) NSString * weight;
-(instancetype)initWithDictionary:(NSDictionary *)dictionary;
-(NSDictionary *)toDictionary;
#end
#import "RootClass.h"
NSString *const kRootClassDesignation = #"Designation";
NSString *const kRootClassFatherName = #"FatherName";
NSString *const kRootClassHeight = #"Height";
NSString *const kRootClassName = #"Name";
NSString *const kRootClassProfession = #"Profession";
NSString *const kRootClassWeight = #"Weight";
#interface RootClass ()
#end
#implementation RootClass
/**
* Instantiate the instance using the passed dictionary values to set the properties values
*/
-(instancetype)initWithDictionary:(NSDictionary *)dictionary
{
self = [super init];
if(![dictionary[kRootClassDesignation] isKindOfClass:[NSNull class]]){
self.designation = dictionary[kRootClassDesignation];
}
if(![dictionary[kRootClassFatherName] isKindOfClass:[NSNull class]]){
self.fatherName = dictionary[kRootClassFatherName];
}
if(![dictionary[kRootClassHeight] isKindOfClass:[NSNull class]]){
self.height = dictionary[kRootClassHeight];
}
if(![dictionary[kRootClassName] isKindOfClass:[NSNull class]]){
self.name = dictionary[kRootClassName];
}
if(![dictionary[kRootClassProfession] isKindOfClass:[NSNull class]]){
self.profession = dictionary[kRootClassProfession];
}
if(![dictionary[kRootClassWeight] isKindOfClass:[NSNull class]]){
self.weight = dictionary[kRootClassWeight];
}
return self;
}
/**
* Returns all the available property values in the form of NSDictionary object where the key is the approperiate json key and the value is the value of the corresponding property
*/
-(NSDictionary *)toDictionary
{
NSMutableDictionary * dictionary = [NSMutableDictionary dictionary];
if(self.designation != nil){
dictionary[kRootClassDesignation] = self.designation;
}
if(self.fatherName != nil){
dictionary[kRootClassFatherName] = self.fatherName;
}
if(self.height != nil){
dictionary[kRootClassHeight] = self.height;
}
if(self.name != nil){
dictionary[kRootClassName] = self.name;
}
if(self.profession != nil){
dictionary[kRootClassProfession] = self.profession;
}
if(self.weight != nil){
dictionary[kRootClassWeight] = self.weight;
}
return dictionary;
}
The above one is Model Class.
Your JSON look like a array. So you need to iterate the Dictionary values on it. Other than that you may pass it directly.
Now in your ViewController class initiate the mutable array
and pass the response like
NSArray *arrayData = ResponseFromAFNETWORKING
for (NSDictionary *data in arrayData) {
NameDetails *modelFeed = [[NameDetails alloc] initFromDictinary:data]
[self.YourMutableDictionary addObject:modelFeed]
}
self.updateDisplay:self.YourMutableDictionary[0] // If not array No iteration, you can prepare the model and pass it directly
----------------------------------------
- (void)updateDisplay:(NameDetails *)feed {
_txtName.text =feed.Name;
_txtFName.text =feed.FatherName;
_txtDesg.text =feed.Designation;
_txtprof.text =feed.Profession;
_txtHeight.text =feed.Height;
_txtWeight.text =feed.Weight;
}
Hope this will help. This is a robust and elastic approach, thread safe mechanism too

NSCoding data not saved when returning to the app?

I don't understand why previousArrays returns (null), I would like to save a class containing a bezier path and its color.
The code : (after touchesEnded is called, a path is created and saved in memory. When I come back to the app with initWithCoder, previousArrays is (null) ) :
-(id)initWithCoder:(NSCoder *)aDecoder{
if ( !(self=[super initWithCoder:aDecoder])) return nil;
CGContextRef context = UIGraphicsGetCurrentContext();
NSArray *previousArrays = [SaveData loadDict];
NSLog(#"previousArrays : %#", previousArrays);//***HERE*** : return (null)
for ( id object in previousArrays){
//for ( NSDictionary*dict in previousArrays){
NSLog(#"obj %#", [[object class] description]);
//...
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
UIBezierPath *bezierPath = [UIBezierPath bezierPathWithCGPath:myPath];//nscoding compliant
DataForPath *firstPath = [[DataForPath alloc] init];
firstPath.path = bezierPath;
firstPath.colorInArray = #(currentColor);
NSLog(#"touchEnded, firstPath : %#", firstPath);
NSDictionary *dict = #{#"firstPath":firstPath};
[SaveData saveDict:dict];
}
#implementation SaveData
static NSString* kMyData = #"data1";
+ (void) saveDict:(NSDictionary*) dict{
NSLog(#"saving data...");
//retrieve previous data
NSData *previousData = [[NSUserDefaults standardUserDefaults] objectForKey:kMyData];
NSMutableArray *previousArray = [[NSKeyedUnarchiver unarchiveObjectWithData:previousData] mutableCopy];
[previousArray addObject:dict];
//add new data, and save
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:previousArray];
[[NSUserDefaults standardUserDefaults] setObject:data forKey:kMyData];
//NSLog(#"%#", [[NSUserDefaults standardUserDefaults] dictionaryRepresentation]);
}
+(NSArray*) loadDict {
NSLog(#"loading data...");
NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:kMyData];
NSArray *array = [NSKeyedUnarchiver unarchiveObjectWithData:data];
return array;
}
#import <Foundation/Foundation.h>
#import UIKit;
#interface DataForPath : NSObject <NSCoding>
#property (nonatomic, strong) UIBezierPath* path;
#property (nonatomic, strong) NSNumber *colorInArray;
#end
#implementation DataForPath
- (id)initWithCoder:(NSCoder *)decoder{
if ( !(self = [super init]) ) return nil;
self.path = [decoder decodeObjectForKey:#"path"];
self.colorInArray = [decoder decodeObjectForKey:#"colorInArray"];
return self;
}
- (void)encodeWithCoder:(NSCoder *)encoder{
[encoder encodeObject:self.path forKey:#"path"];
[encoder encodeObject:self.colorInArray forKey:#"colorInArray"];
}
Also, is there a way to see what is in the NSUserDefault, such as a "prettyjson" format? -dictionaryRepresentation returns some figures like that <124d1f>
Did you checked saveDict method for previousArray == nil ?, Because before you saved something you have nothing in userDefaults
I had to use this : if ( previousArray == nil ) ...
NSMutableArray *previousArray = [[NSKeyedUnarchiver unarchiveObjectWithData:previousData] mutableCopy];
if ( previousArray == nil ) previousArray = [[NSMutableArray alloc] init];
Not enough information.
Objects can be converted to and from data if they conform to the NSCoding protocol. You have to write code for both the encodeWithCoder and initWithCoder methods that saves all your object's properties.
If you are un-archiving an object that you saved with encodeWithCoder and one of it's properties is not loading then there is most likely a problem with your encodeWithCoder method.
Post the header for the class you're trying to encode, all of the encodeWithCoder and initWithCoder methods, and information about the properties of your object that you are encoding.
Also post the code that converts your object to data and saves it, and provide a description of when/how it is saved.

Write Object to Plist using NSCoding and NSCoder

I've created a class that conforms to NSCoding
- (id) initWithCoder:(NSCoder *)aDecoder
{
self = [super init];
if (self) {
self.name = [aDecoder decodeObjectForKey:#"name"];
self.type = [aDecoder decodeObjectForKey:#"type"];
}
return self;
}
- (void) encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeObject:self.name forKey:#"name"];
[aCoder encodeObject:self.type forKey:#"type"];
}
Then the methods used for saving to and reading from the plist are as follows:
- (IBAction)read:(id)sender
{
NSDictionary *dic = [NSDictionary dictionaryWithContentsOfFile:self.plistDocPath];
//NSLog(#"plist contents: %#",dic);
NSData *dataObj = [dic objectForKey:#"obj2"];
NSLog(#"dataObj: %#",dataObj);
ObjClass *obj = [NSKeyedUnarchiver unarchiveObjectWithData:dataObj];
NSLog(#"decoded object: %#",obj);
}
- (IBAction)write:(id)sender
{
ObjClass *obj = [[ObjClass alloc] initWithName:#"nick" andType:#"human"];
//NSString *str = #"example";
NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithContentsOfFile:self.plistDocPath];
NSString *key = [NSString stringWithFormat:#"obj%i",dic.count];
NSData *objData = [NSKeyedArchiver archivedDataWithRootObject:obj];
[dic setObject:objData forKey:key];
[dic writeToFile:self.plistDocPath atomically:YES];
}
The writing to process seems to be working fine if I look into the file I'm seeing an NSData object for key "obj2" with bytes in it.
The problem is when I try to read from the file I'm getting
2014-02-17 20:48:53.780 FileManagerSample[589:70b] *** NSForwarding: warning: object 0x1661f24 of class 'Object' does not implement methodSignatureForSelector: -- trouble ahead
2014-02-17 20:48:53.780 FileManagerSample[589:70b] *** NSForwarding: warning: object 0x1661f24 of class 'Object' does not implement doesNotRecognizeSelector: -- abort
Can someone please help because I'm stuck big time.

Resources