I don't know why this code error.
Please help.
I read some articles and I think the problem is about context.
What Should I do?
This program is about shows data in coredata to label in viewcontroller.
AppDelegate.h
#import <UIKit/UIKit.h>
#import <CoreData/CoreData.h>
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
#property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
#property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
- (void)saveContext;
- (NSURL *)applicationDocumentsDirectory;
#end
AppDelegate.m
#import "AppDelegate.h"
#import "Test.h"
#import "ViewController.h"
#interface AppDelegate ()
#end
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
NSManagedObjectContext *context = [self managedObjectContext];
Test *t = [NSEntityDescription insertNewObjectForEntityForName:#"Test"
inManagedObjectContext:context];
t.name = #"please";
return YES;}
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *label;
#property (nonatomic,strong) NSArray *temp;
#property (nonatomic,strong) NSManagedObjectContext* managedObjectContext;
#end
ViewController.m
#import "ViewController.h"
#import "Test.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize managedObjectContext;
#synthesize temp;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription
entityForName:#"Test"
inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
NSError *error;
self.temp = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
for(Test *info in temp){
_label.text = info.name;
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
Test.h
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#interface Test : NSManagedObject
#property (nonatomic, retain) NSString * name;
#end
Test.m
#import "Test.h"
#implementation Test
#dynamic name;
#end
I don't know why this code error.
Please help.
I read some articles and I think the problem is about context.
What Should I do?
In your view controller, replace the line:
#synthesize managedObjectContext;
With this:
- (NSManagedObjectContext *) managedObjectContext {
return ((AppDelegate *)[[UIApplication sharedApplication] delegate]).managedObjectContext;
}
Instead of storing another, different object context in your view controller, this property will return the object context that you set up in the app delegate.
There are other ways to do this, such as creating a Core Data helper class following the Singleton pattern (as #NewYork167 suggests), but this should at least solve your current problem.
For any future reference, you can also try subclassing the NSManagedObjectContext like this:
#interface MyManagedObjectContext : NSManagedObjectContext
+ (MyManagedObjectContext *)mainThreadContext;
#end
#implementation MyManagedObjectContext
+ (MyManagedObjectContext *)mainThreadContext;
{
static MyManagedObjectContext *moc;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
moc = [[self alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
// Setup persistent store coordinator here
});
return moc;
}
#end
Reference: Best practices for passing NSManagedObjectContext around to UITabBarController child view controllers?
Related
I am in the middle of an app re-design and am refactoring and extending my model.
One aspect of my apps model is that the app retrieves data from a web service and populates the model.
My question is: Should my model objects have the capability to implement NSURLSession or should I rely on the VC to provide the connection?
I'm asking from a best practices standpoint. What's the best way to think about this? Should the model be totally on its own or should it have network access?
One consideration is that these model objects are essentially useless without data from the network, meaning data from the Internet is a fundamental aspect of their existence.
If we take SOLID — especially the S for Single Responsible Principle — in account, it becomes obvious, that neither the VC nor the model should do the networking:
a VC's single responsible would be to handle views
the model's purpose would be to hold data
networking should be done by a third class, a networking controller.
This three points will fulfill SOLID, but how do you get data from the network into model objects show on a view?
Well, this depends on your overall architectural design on the app, but a common approach would be to use callback — either a delegate protocol or a block — with your network controller.
You create a network controller in the app delegate and pass it from view controller to view controller via properties to any place in the app were newly fetched data is needed. I wouldn't use a singleton here, as that violates O, I & D of SOLID.
Add a class method to your model +(NSArray *)modelObjectsFromDictionaries:(NSArray *) or similar.
In the view controller you can now do
-(void)viewDidLoad
{
[super viewDidLoad];
__weak typeof(self) weakSelf = self;
[self.networkController fetchModels:^(NSArray *modelDictionaries, NSError *error){
typeof(weakSelf) self = weakSelf;
if(self) {
if(!error){
[self.dataSource addOrUpdateData:[Model modelObjectsFromDictionaries:modelDictionaries]];
} else {
// error handling
}
}
}];
}
This is just a starting point. For more complicated APIs it might be useful to use an api controller that itself uses the networking controller and maybe a persistence controller.
Although instead of a Model class method you might want to use some sort of mapping and abstract factory pattern… But all this things would require more information about your app and are out of the scope for this question.
Update:
I created a sample project to demonstrate this.
It is slightly different than what I say above:
As it uses a table view, I am using a data source class to populate it. Instead of the view controller the data source will tell the network controller to fetch new data.
I am using OFAPopulator for this, a library written by me to populate table views and collection views in a SOLID-conform fashion, or to «Keep view controllers clean and MVC smart».
#import "AppDelegate.h"
#import "VSNetworkController.h"
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[self.window.rootViewController setValue:[[VSNetworkController alloc] initWithBaseURL:[NSURL URLWithString:#"http://api.goeuro.com/api/v2/"]]
forKey:#"networkController"];
return YES;
}
#end
// VSNetworkController.h
#import <Foundation/Foundation.h>
#interface VSNetworkController : NSObject
-(instancetype)initWithBaseURL:(NSURL *) baseURL;
-(void)suggestionsForString:(NSString *)suggestionString
responseHandler:(void(^)(id responseObj, NSError *error))responseHandler;
#end
// VSNetworkController.m
#import "VSNetworkController.h"
#interface VSNetworkController ()
#property (nonatomic, strong) NSURL *baseURL;
#end
#implementation VSNetworkController
-(instancetype)initWithBaseURL:(NSURL *)baseURL
{
self = [super init];
if (self) {
_baseURL = baseURL;
}
return self;
}
-(void)suggestionsForString:(NSString *)suggestionString
responseHandler:(void(^)(id responseObj, NSError *error))responseHandler
{
NSURL *url = [self.baseURL URLByAppendingPathComponent:[NSString stringWithFormat:#"position/suggest/en/%#", suggestionString]];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response,
NSData *data,
NSError *connectionError) {
responseHandler([NSJSONSerialization JSONObjectWithData:data options:0 error:nil], connectionError);
}];
}
#end
// VSLocationSuggestion.h
#import <Foundation/Foundation.h>
#import CoreLocation;
#interface VSLocationSuggestion : NSObject
#property (nonatomic, copy, readonly) NSString *name;
#property (nonatomic, copy, readonly) NSString *country;
#property (nonatomic, strong, readonly) CLLocation *position;
+(NSArray *)suggestionsFromDictionaries:(NSArray *)dictionaries;
#end
// VSLocationSuggestion.m
#import "VSLocationSuggestion.h"
#interface VSLocationSuggestion ()
#property (nonatomic, copy) NSString *name;
#property (nonatomic, copy) NSString *country;
#property (nonatomic, strong) CLLocation *position;
#end
#implementation VSLocationSuggestion
+(NSArray *)suggestionsFromDictionaries:(NSArray *)dictionaries
{
NSMutableArray *array = [#[] mutableCopy];
[dictionaries enumerateObjectsUsingBlock:^(NSDictionary *suggestionDict, NSUInteger idx, BOOL *stop) {
[array addObject:[[self alloc] initWithDictionary:suggestionDict]];
}];
return [array copy];
}
-(instancetype)initWithDictionary:(NSDictionary *)dict
{
self = [super init];
if (self) {
_name = dict[#"name"];
_country = dict[#"country"];
CLLocationDegrees latitude = [dict[#"geo_position"][#"latitude"] doubleValue];
CLLocationDegrees longitude =[dict[#"geo_position"][#"longitude"] doubleValue];
_position = [[CLLocation alloc] initWithLatitude:latitude longitude:longitude];
}
return self;
}
#end
// VSSuggestionDataSource.h
#import <Foundation/Foundation.h>
#import <OFADataProvider.h>
#class VSNetworkController;
#interface VSSuggestionDataSource : NSObject <OFADataProvider>
-(instancetype)initWithNetworkController:(VSNetworkController *)networkController;
-(void)setNewSuggestions:(NSArray *)suggetsions;
-(void)enteredStringForSuggestions:(NSString *)suggestionString;
#end
// VSSuggestionDataSource.m
#import "VSSuggestionDataSource.h"
#import "VSNetworkController.h"
#import "VSLocationSuggestion.h"
#interface VSSuggestionDataSource ()
#property (nonatomic, copy) void (^available)(void);
#property (nonatomic, strong) VSNetworkController *networkController;
#end
#implementation VSSuggestionDataSource
#synthesize sectionObjects;
-(instancetype)initWithNetworkController:(VSNetworkController *)networkController
{
self = [super init];
if (self) {
_networkController = networkController;
}
return self;
}
-(void)dataAvailable:(void (^)(void))available
{
_available = available;
}
-(void)setNewSuggestions:(NSArray *)suggetsions
{
self.sectionObjects = suggetsions;
self.available();
}
-(void)enteredStringForSuggestions:(NSString *)s
{
__weak typeof(self) weakSelf = self;
[self.networkController suggestionsForString:s responseHandler:^(NSArray *responseObj, NSError *error) {
typeof(weakSelf) self = weakSelf;
if (self) {
if (!error && responseObj) {
NSArray *suggestion = [VSLocationSuggestion suggestionsFromDictionaries:responseObj];
[self setNewSuggestions:suggestion];
}
}
}];
}
#end
// ViewController.h
#import <UIKit/UIKit.h>
#class VSNetworkController;
#interface ViewController : UIViewController
#property (nonatomic, strong) VSNetworkController *networkController;
#end
// ViewController.m
#import "ViewController.h"
#import "VSLocationSuggestion.h"
#import <OFAViewPopulator.h>
#import <OFASectionPopulator.h>
#import "VSSuggestionDataSource.h"
#interface ViewController ()
#property (weak, nonatomic) IBOutlet UITableView *tableView;
#property (strong, nonatomic) OFAViewPopulator *viewPopultor;
#property (strong, nonatomic) VSSuggestionDataSource *dataSource;
- (IBAction)textChanged:(UITextField *)sender;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.dataSource = [[VSSuggestionDataSource alloc] initWithNetworkController:self.networkController];
OFASectionPopulator *sectionPopulator = [[OFASectionPopulator alloc] initWithParentView:self.tableView
dataProvider:self.dataSource
cellIdentifier:^NSString *(id obj, NSIndexPath *indexPath) {
return #"Cell";
} cellConfigurator:^(VSLocationSuggestion *obj, UITableViewCell *cell, NSIndexPath *indexPath) {
cell.textLabel.text = obj.name;
}];
sectionPopulator.objectOnCellSelected = ^(VSLocationSuggestion *suggestion, UIView *cell, NSIndexPath *indexPath ){
NSString * string =[NSString stringWithFormat:#"%#, %# (%f %f)", suggestion.name, suggestion.country, suggestion.position.coordinate.latitude, suggestion.position.coordinate.longitude];
UIAlertController *avc = [UIAlertController alertControllerWithTitle:#"Selected" message:string preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *cancelAction = [UIAlertAction
actionWithTitle:NSLocalizedString(#"Cancel", #"Cancel action")
style:UIAlertActionStyleCancel
handler:^(UIAlertAction *action)
{
;
}];
[avc addAction:cancelAction];
[self presentViewController:avc animated:YES completion:NULL];
};
self.viewPopultor = [[OFAViewPopulator alloc] initWithSectionPopulators:#[sectionPopulator]];
}
- (IBAction)textChanged:(UITextField *)sender
{
NSString *s = sender.text;
if ([s length]) {
[self.dataSource enteredStringForSuggestions:s];
}
}
#end;
I made this code available on github: https://github.com/vikingosegundo/LocationSugesstion
[self.managedObjectContext deletedObjects:lastPoint];
This line shows me an error
No visible #interface for 'NSManagedObjectContext' declares the selector 'deletedObjects'.
Here is my code
can any one solve this?
Appdelegate.h
#import <UIKit/UIKit.h>
#import <CoreData/CoreData.h>
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
#property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
#property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
- (void)saveContext;
- (NSURL *)applicationDocumentsDirectory;
#end
Appdelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
/* crete the fetch request first*/
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc]initWithEntityName:#"Rectangle"];
NSError *requestError = nil;
/*And execute the fetch request on the context*/
NSArray *rectangle = [self.managedObjectContext executeFetchRequest:fetchRequest error:&requestError];
/*make sure we get the array*/
if ([rectangle count] > 0) {
/*delete the last person in the array*/
Rectangle *lastPoint = [rectangle lastObject];
[self.managedObjectContext deletedObjects:lastPoint];
if ([lastPoint isDeleted]) {
NSLog(#"Successfully deleted the last point...");
NSError *savingError = nil;
if ([self.managedObjectContext save:&savingError]) {
NSLog(#"successfully saved the context");
} else {
NSLog(#"Failed to save the context");
}
} else {
NSLog(#"Failed to delete the last point");
}
} else {
NSLog(#"Could not find any rectangle entities in the context.");
}
return YES;
}
The error message
No visible #interface for 'NSManagedObjectContext' declares the
selector 'deletedObjects'.
tells you that the class NSManagedObjectContext doesn't implement the method deletedObjects. You can check this in the API documentation.
You can use deleteObject: to delete single objects. So change your code to:
[self.managedObjectContext deleteObject:lastPoint];
As the documentation says deletedObjects is the read only property, so it has only getter method without any parameters
So you should access it just by using next
self.managedObjectContext.deletedObjects
I have created a simple 1 entity data model through Core Data. I add an entity in "didFinishLaunchingWithOptions" of "AppDelegate". Then, I am trying to load the data of the model to an array and then a table view.
I am aware that there are similar post, but I still can't find out whats wrong with my code.
List of things I have tried and checked:
The entity is added properly into the model
I have already checked the entity names and they are correct.
I have tried deleting the app and clean rebuilding it but still nothing.
So there must be a more major issue with my code. Any help is appreciated.
Here is my error:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '+entityForName: could not locate an NSManagedObjectModel for entity name 'FavoritesInfo'
AppDelegate.h
#import <UIKit/UIKit.h>
#import "favTable.h"
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (strong, nonatomic) favTable *viewController;
#property (strong, nonatomic) UINavigationController *navController;
#property (nonatomic, retain, readonly) NSManagedObjectModel *managedObjectModel;
#property (nonatomic, retain, readonly) NSManagedObjectContext *managedObjectContext;
#property (nonatomic, retain, readonly) NSPersistentStoreCoordinator *persistentStoreCoordinator;
- (NSURL *)applicationDocumentsDirectory; // reference files for core data
#end
AppDelegate.m
#import "AppDelegate.h"
#implementation AppDelegate
#synthesize window = _window;
#synthesize viewController = _viewController;
#synthesize navController = _navController;
#synthesize managedObjectContext = _managedObjectContext;
#synthesize managedObjectModel = _managedObjectModel;
#synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSManagedObjectContext *context = [self managedObjectContext];
NSManagedObject *favoritesInfo = [NSEntityDescription
insertNewObjectForEntityForName:#"FavoritesInfo"
inManagedObjectContext:context];
[favoritesInfo setValue:#"Product 1" forKey:#"name"];
[favoritesInfo setValue:[NSNumber numberWithInt:15] forKey:#"score"];
NSError *error;
if (![context save:&error]) {
NSLog(#"Whoops, couldn't save: %#", [error localizedDescription]);
}
return YES;
}
Then in the class of the table viewcontroller favtable.h
#import <UIKit/UIKit.h>
#interface favTable : UITableViewController <NSFetchedResultsControllerDelegate>
{
NSFetchedResultsController *fetchedResultsController;
NSManagedObjectContext *managedObjectContext;
NSArray *favArr;
int num;
}
#property (nonatomic, strong) NSArray *favArr;
#property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;
#property (nonatomic, retain) NSFetchedResultsController *fetchedResultsController;
#end
favtable.m viewdidload
#import "favTable.h"
#import "AppDelegate.h"
#interface favTable ()
#end
#implementation favTable
#synthesize favArr;
#synthesize spVC;
#synthesize managedObjectContext = _managedObjectContext;
#synthesize fetchedResultsController;
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = #"Favorites";
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription
entityForName:#"FavoritesInfo" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
NSError *error=nil;
self.favArr=[managedObjectContext executeFetchRequest:fetchRequest error:&error];
if (error!=nil) {
NSLog(#" fetchError=%#,details=%#",error,error.userInfo);
}
}
Your managedObjectContext is not set in your ViewController.
Set it in your AppDelegate didFinishLaunchingWithOptions, usually looks like:
ViewControllerClass *controller = (ViewControllerClass*)self.window.rootViewController;
or with a navigation controller:
UINavigationController *navigationController = (UINavigationController *)self.window.rootViewController;
ViewControllerClass *controller = (ViewControllerClass *)navigationController.topViewController;
And then:
controller.managedObjectContext = self.managedObjectContext;
In my favtable.m class I added this to set the managedObjectContext and it works properly.
self.managedObjectContext = ((AppDelegate *) [UIApplication sharedApplication].delegate).managedObjectContext;
I have variable in my AppDelegate.m called message, that i would like to use in a view controller, but it's not working. I've tried this solution:
If i import the AppDelegate.m into my ViewController.m, i get an error: clang: error: linker command failed with exit code 1 (use -v to see invocation), but if i don't import it i get this: No known class method for selector 'message' at this line: self.toSort = [AppDelegate message];. But when i import ViewController.m into AppDelegate.m i don't get the linker command error, however the other error already exists.
My AppDelegate.h
#property (strong, nonatomic) UIWindow *window;
#property (nonatomic, strong) PNChannel *myChannel;
- (void)getMessage;
AppDelegate.m
#import "AppDelegate.h"
#import "ViewController.m"
static NSArray *_message = nil;
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// [self.window makeKeyAndVisible];
self.myChannel = [PNChannel channelWithName:currentChannel.username
shouldObservePresence:YES];
[self getMessage];
}
+ (NSArray *)message
{
if (_message)
return _message;
AppDelegate *appDelegate =(AppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate getMessage];
return nil;
}
- (void)getMessage {
[PubNub requestFullHistoryForChannel:self.myChannel withCompletionBlock:^(NSArray *contentArray, PNChannel *channel, PNDate *fromDate, PNDate *toDate, PNError *error) {
_message = contentArray;
NSLog(#"test log %#", _message);
}];
}
ViewController.m
#import "ViewController.h"
//#import "AppDelegate.h"
//#import "AppDelegate.m"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)viewWillAppear:(BOOL)animated {
//AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
//[appDelegate getMessage];
self.toSort = [AppDelegate message];
[self getMessageList];
}
I'm sure i did some beginner mistake, but i can't figure it out. The "test log" works, so i think i have to call it in a different way.
Already tried this, but also get an error because message is not a property.
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSArray *variableTest = appDelegate.message;
NSLog(#"TEST : %#",variableTest);
UPDATE: I've tried this, but the test log shows null, so something is still wrong.
AppDelegate.h
#property (strong, nonatomic) UIWindow *window;
#property (nonatomic, strong) PNChannel *myChannel;
#property (strong, nonatomic) NSArray *message;
- (void)getMessage;
AppDelegate.m
#import "AppDelegate.h"
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// [self.window makeKeyAndVisible];
self.myChannel = [PNChannel channelWithName:currentChannel.username
shouldObservePresence:YES];
[self getMessage];
}
return YES;
}
+ (NSArray *)message
{
if (self.message)
return self.message;
AppDelegate *appDelegate =(AppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate getMessage];
return nil;
}
- (void)getMessage {
[PubNub requestFullHistoryForChannel:self.myChannel withCompletionBlock:^(NSArray *contentArray, PNChannel *channel, PNDate *fromDate, PNDate *toDate, PNError *error) {
self.message = contentArray;
NSLog(#"dev log %#", self.message);
}];
}
ViewController.m
- (void)viewWillAppear:(BOOL)animated {
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSArray *variableTest = appDelegate.message;
NSLog(#"TEST : %#",variableTest);
}
My try based on o Pi's answer:
#interface MessageHistoryData : NSObject {
NSArray *yourData;
}
#property(nonatomic,retain) NSArray *yourData;
+(MessageHistoryData *)getInstance;
#end
#import "MessageHistoryData.h"
#implementation MessageHistoryData #synthesize yourData;
static MessageHistoryData *instance =nil;
+(MessageHistoryData *)getInstance {
#synchronized(self) {
if(instance==nil) {
instance= [MessageHistoryData new];
}
}
return instance;
}
#end
in my ViewController.m (MessageHistoryData is imported into the .h)
-(void)setupArray {
[PubNub requestHistoryForChannel:my_channel from:nil to:nil limit:100 reverseHistory:NO withCompletionBlock:^(NSArray *contentArray, PNChannel *channel, PNDate *fromDate, PNDate *toDate, PNError *error) {
MessageHistoryData *data = [MessageHistoryData getInstance];
data.yourData = contentArray;
NSLog(#"Dev log2 %#", data.yourData);
}];
}
I set up a sample project to verify that this works.
In the AppDelegate.h file, publicly declare the message property and -getMessage method:
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (readonly, nonatomic) NSString *message;
- (void)getMessage;
#end
In the AppDelegate.m file, implement your methods as you normally would (I explicitly set the property for the sake of example):
#import "AppDelegate.h"
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
return YES;
}
- (void)getMessage {
self.message = #"This is a message";
}
#end
In your ViewController.m file, you should import the AppDelegate header, and you should be free to access the properties:
#import "AppDelegate.h"
#import "ViewController.h"
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
AppDelegate *delegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
NSLog(#"The delegate's message is: %#", delegate.message); // Logs "The delegate's message is: (null)"
[delegate getMessage];
NSLog(#"The delegate's message is: %#", delegate.message); // Logs "The delegate's message is: This is a message"
}
#end
If the above doesn't work, you should test your PubNub class and ensure it's behavior is predictable.
I don't recommend EVER storing information in your AppDelegate, as that makes the class responsible for doing more than just being your application's delegate with the system. Information like this should be stored in a dedicated store, or made available through a custom PubNub subclass that is accessed as a singleton (if there's no global state to be managed!) or an instance by instance basis.
Let me know if you need any clarification or if the solution above doesn't work for you.
EDIT: Singleton Suggestion
As per my comment, here is one way to handle sharing network data across view controllers
#interface NetworkClient : PubNub
#property (readonly, nonatomic) NSString *message;
/**
* Returns a shared network client to be used throughout the app
*/
+ (instancetype)sharedClient;
- (void)configureWithChannel:(PNChannel*)channel;
- (void)clearChannel;
- (void)getMessagesWithCompletionHandler:(void (^)(NSArray *, PNChannel *, PNDate *, PNDate *, PNError *))
#end
Where sharedInstance uses the technique described here to setup your instance. From there, you can access the client using [NetworkClient sharedClient] and retrieve any data through the instance methods or properties on the client.
I'm also guessing you are new to singletons or iOS in general, so I'm going to recommend you read this article about using singletons, and the blog objc.io to familiarize yourself with some best practices that will absolutely make your life easier.
First there is no need to declare the variable static since [UIApplication sharedAppliction] delegate] will always be the same instance. So just declare a property in the AppDelegate.h file and use that.
in AppDelegat.h
#property(nonatomic, strong) NSArray *message;
in AppDelegate.m use it like this:
self.message
And in your view controller import the .h and do:
AppDelegate *appDelegate =(AppDelegate *)[[UIApplication sharedApplication] delegate];
NSArray *arr = appDelegate.message;
You have to put public variables into your header file.
Your getMessage method uses an async call to get the messages. If you can't retrieve it in a sync way maybe you should call getMessage as soon as possible.
Better yet you could also use blocks to return the messages async:
+ (void)asyncMessage:(void(^)(NSArray * message))callbackBlock
{
if (_message)
{
callbackBlock(_message);
return;
}
[PubNub requestFullHistoryForChannel:self.myChannel withCompletionBlock:^(NSArray *contentArray, PNChannel *channel, PNDate *fromDate, PNDate *toDate, PNError *error) {
_message = contentArray;
callbackBlock(_message);
NSLog(#"test log %#", _message);
}];
}
never import .m class in xcode because this throws cling: error.
if u want to NSArray defined in appdelegate to use later in your any view controller,there may be many approaches.some of them are-
initilise your array in appdelegate.h like this
#property(nonatmoic,retain)nsarray *message;
then in your appdelegate.m class in didfinishlaunchingwithOptions method allocate memory to this array-
message=[[nsarray alloc]initwithobjects:#"abc"];
then in your view controller make object of app delegate and access this property like this-
NSLog(#"array is %#",appdelegateobject.message);
In your first question you trying to return this array by class method,but in appdelegate you returning nil,so how will u get this message array,
Take the message variable and paste it into the .h then delete it from the .m
You can not import a implement file in your implement file like this.
AppDelegate.m
#import "AppDelegate.h"
#import "ViewController.m" // This is the reason causes error.
I made this errors before....
Modify like this easily fix this problem.
AppDelegate.m
#import "AppDelegate.h"
#import "ViewController.h"
you need to properties the message array to make public
AppDelegate.h
#property (strong, nonatomic) NSArray *message;
Hope it helps you..
Im new to Objective-C and CoreData and want to learn it and im trying in Xcode 5, im trying to make this tutorial.
I have followed it with some other CoreData table name, but i get some errors with my "ViewController.m" and dont know what to changes, i can see it recomment to changes "NSEntityDescription" to "kSetAttrDescription" but dont know if thats right or wrong to do, hope someone can tell mewhat to do - so i know it next time.
Error issues
Error Descriptions
My ViewController.m code.
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
//Save data as CoreData, to CoreData Table "Kunder" field "navn", "adresse", "alder" from textfield _name.text, _adress.text, _age.text.
- (IBAction)saveData:(id)sender {
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSManagedObject *newContact;
newContact = [NSEntityDescription insertNewObjectForEntityForName:#"Kunder" inManagedObjectContext:context];
[newContact setValue: _name.text forKey:#"navn"];
[newContact setValue: _adress.text forKey:#"adresse"];
[newContact setValue: _age.text forKey:#"alder"];
//if textfield empty, then error else save and show label message "Kunde Gemt".
_name.text = #"";
_adress.text = #"";
_age.text = #"";
NSError *error;
[context save:&error];
_status.text = #"Kunde Gemt";
}
//Find-search for user by name.
- (IBAction)findKunde:(id)sender {
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSEntityDescription *entityDesc = [NSEntityDescription entityForName:#"Kunder" inManagedObjectContext:context];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entityDesc];
NSPredicate *pred =
[NSPredicate predicateWithFormat:#"(navn = %#)", _name.text];
[request setPredicate:pred];
NSManagedObject *matches = nil;
//if no user then error, else take name match and get "adresse" and "alder" from CoreData and show it in the text fields _adress.text and _age.text and show matche count in status label.
NSError *error;
NSArray *objects = [context executeFetchRequest:request error:&error];
if ([objects count] == 0) {
_status.text = #"Ingen fundet";
} else {
matches = objects[0];
_adress.text = [matches valueForKey:#"adresse"];
_age.text = [matches valueForKey:#"alder"];
_status.text = [NSString stringWithFormat: #"%lu antal fundet", (unsigned long)[objects count]];
}
}
#end
My ViewController.h page (no error)
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#interface ViewController : UIViewController
#property (strong, nonatomic) IBOutlet UITextField *name;
#property (strong, nonatomic) IBOutlet UITextField *adress;
#property (strong, nonatomic) IBOutlet UITextField *age;
#property (strong, nonatomic) IBOutlet UILabel *status;
- (IBAction)saveData:(id)sender;
- (IBAction)findKunde:(id)sender;
#end
My AppDelegate.m file
#import "AppDelegate.h"
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
return YES;
}
....
#end
UPDATE
When adding text to the fields and hit save, i don get a "Save ok" message it jump to xcode and show me this.
Is seems that you forgot to import <CoreData/CoreData.h>.
You can add the import to your precompiled header (...-Prefix.pch) file
which would look similar to this:
#import <Availability.h>
#ifndef __IPHONE_5_0
#warning "This project uses features only available in iOS SDK 5.0 and later."
#endif
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h> // <-- Add this !!
#endif
You might also have to add the "CoreData.framework" to the "Link Binary With Libraries"
section of the targets "Build Phases".