Passing variable - objective-c

Hi I've got an question about passing variables via NSobject into the rootviewcontroller.
I've got 2 .h and .m files ( called viewcontroller.m/h and secondviewcontroller.m/h ).
Underneath a little example for what I'm trying to do.
secondviewcontroller.m
-(NSString *) mystring{
return #"this is a string";
}
secondviewcontroller.h
#interface SecondviewController : NSObject
-(NSString *) mystring;
#end
How am I be able to pass this variable into viewcontroller.m ?
I've read a lot on google but most of the implementations where wrong or my research is just bad xD

How am I be able to pass this variable into viewcontroller.m ?
You actually haven't shown us any variables; -myString returns a constant string. Also, remember that viewcontroller.m is just an implementation file. It's probably better to think about the objects communicating with each other than one piece of source code communicating with another. I communicate with you, but my DNA doesn't communicate with your DNA.
Anyway, it sounds like you're asking about how one object can communicate with another, and the answer is simply that at least one of the objects in the conversation needs to know about the other. So, an instance of your viewcontroller class might get a pointer to an instance of secondviewcontroller from some other object, or it might create a new instance itself. Some part of the code in viewcontroller.m might look like:
secondviewcontroller *svc = [[secondviewcontroller alloc] initWithNibName:nil bundle:nil];
NSString *someString = [svc myString];
That's not a particularly realistic example, but neither is the sample you provided. The lesson is the same, though -- objects communicate by sending messages to each other, and an object needs a reference to another object in order to send that message. Figuring out which objects should know about which others, how they find out about each other, and what messages they send to each other is exactly the business of object oriented programming. In OOP, the truly important thing isn't so much the objects themselves but how they relate to each other. It's all about the structure that you create using objects as building blocks.

Related

Objective-C : Accessing fields in implementation

Is it possible to fields defined only in implementation but not in interface definition ?
#interface MyInterface .... #end --> dict not defined here!!!
#implementation MyInterface
...
NSDictionary *dict;
...
#end
In this case if somewhere I somehow accessed to this class, can I access to the dict or should I create a getter just like in Java ?
Edit after #Rob's answer
Thanks for the answer Rob, I wish I have the implementation of these interface and classes. Instead I am trying to bind two different libraries ( I know it is reallllly bad as architectural point of view but this is where I end up).
Basically, I am in react-native world. And we are using react-native-video as our player layer. But since AVPlayer does not support some subtitle types our head company sent us a library that needs a player instance and a view instance to draw subtitle on the view. I believe they will bind to events of the player and draw sub titles based on player states.
So react-native-video is in this github repo with the interface and implementation.
I find the UIView that includes the properties and casted it to the object itself RTCVideo in this case). But now I am stuck. I can go and change some stuff as per your suggestion in the "Development Pods" to be able to access but this is my last bullet :) I prefer to convince these two libraries in a friendly way :)
Yes, but the above syntax isn't what you want. The modern way to do this is with a class extension.
Your header file is the same:
#interface MyInterface
#end
But in your .m file, you create an extension by appending ():
#interface MyInterface ()
#property (nonatomic, readwrite) NSDictionary *dict;
#end
Now, inside your .m file, you can access self.dict normally, but outside of your .m file it won't appear available.
For full details, see Programming with Objective-C: Class Extensions Extend the Internal Implementation.
The syntax you've written actually creates a static (global) variable called dict that isn't tied to any instance.
It is possible to create raw instance variables using a {...} syntax, either on the extension or on the implementation, but this isn't used that often today, except for managing raw buffers that you don't want accessors for. The syntax is either:
#interface MyInterface () {
NSDictionary *_dict;
}
...
#end
or on the implementation:
#implementation MyInterface {
NSDictionary *_dict;
}
...
#end
But I recommend simple extensions with properties any time you can. And if you are considering creating an accessor for it, you definitely want to use #property and let the system do it for you.
If I understand your edits correctly, you're trying to read the internal ivars of an object that doesn't expose them with an accessor, correct? I believe specifically you want to access _player.
There's several common ways to do that. The key feature you want is Key-Value Coding.
The simplest approach for this problem is -valueForKey:
AVPlayer *player = [view valueForKey:#"player"];
The first thing -valueForKey: looks for is _<key>, and if it's just an object pointer (as in this case), it just returns it.
(This can be broken if a class return false for +accessInstanceVariablesDirectly, but the default is true, and it's unusual to override this.)
Another very common approach is to just declare any methods you know exist as a category. (This won't work for _player, since it's not a method, but in case you need similar things.) Imagine you wanted to call the "private" method -removePlayerTimeObserver. In your .m file, just say you know about it using a category:
#interface RCTVideo (PrivateMethods)
- (void)removePlayerTimeObserver;
#end
And since you know about it, you can call it:
[video removePlayerTimeObserver];
If you're wrong, and that method doesn't really exist, then the program will crash. In Objective-C, almost all rules are advisory. You can break them if you want to. ObjC programmers tend to be big rule-followers because otherwise the program crashes and ObjC has very clear rules that are pretty easy to follow. It's not because the system forces us to.

Difference of private variable and property declared in class extension [duplicate]

This question already has answers here:
Is there any reason to declare ivars if you're using properties exclusively in Objective-C?
(4 answers)
Closed 8 years ago.
I'm new to Objective-C, and I saw some open sourced code like below:
DetailedViewController.m:
#interface DetailedViewController()
#property(nonatomic, strong) UITableView *dynamicTable;
#end
#implementation DetailedViewControll
-(void)viewDidLoad
{
[super viewDidLoad];
self.dynamicTable=[[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
//configure dynamicTable
}
#end
if I declare the dynamicTable variable and use it as below:
#interface DetailedViewController()
{
// private tableview variable
UITableView *dynamicTable;
}
#end
#implementation DetailedViewControll
-(void)viewDidLoad
{
[super viewDidLoad];
dynamicTable=[[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
//configure dynamicTable
}
#end
I think the the above two ways of using dynamicTable variable are equal, Am I right?
if not, Does using property is better than using private variable?
Quote from Apple docs, explaining properties:
Practically speaking, properties reduce the amount of redundant code you have to write. Because most accessor methods are implemented in similar ways, properties eliminate the need to implement a getter and setter method for each property exposed in the class. Instead, you specify the behavior you want using the property declaration and then synthesize actual getter and setter methods based on that declaration at compile time.
In your case above two ways are equal. But if you want to use some advanced technics, such as Lazy Instantiation or Key-Value Observing, you'll definitely need properties.
Accessing a variable is faster than accessing a property. However, a property gives you some advantages like key-value observing (another object or your object can register to be notified once someone changes the value of the property). Which one to use is a matter of taste and use-case.
If you declare a property in your public .h file, other objects can access it. If you declare your variable in your public .h file, other objects can access it as well (object->variable) but this very, very bad, don't do that.
So strictly speaking, your two examples are not equal. They are, however, similar. Quite often it doesn't really matter which one you use. Use whichever suits you more. The fact that variable access is faster is not a good reason to chose one over the other except if you measured and know that a property is causing a performance problem (I have yet to see that, and I work on multimedia apps that need to be fast).

where to store "global" objects in iOS [duplicate]

This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
How or where should I store object instances that I require globally within my iOS app?
I have some global object (uses in almost all Application Screens) and mostly they are created right after application starts. I want to have access to this objects from all my ViewControllers (nothing else, only ViewControllers). Where to store it?
I think about #property in AppDelegate but i think (but I can be wrong) this is a ugly solution.
Objects can be quite complex, this is not a simple types.
You can make global objects accessible by placing them in a class with class methods for accessing global objects, implementing +(void)load to prepare these objects, and storing them in static variables.
Header:
#interface GlobalObjects
+(void)load;
+(MyObject1*)myObject1;
#end
Implementation:
#import "GlobalObjects.h"
static MyObject1* _myObject1 = nil;
#implementation GlobalObjects
+(void)load {
_myObject1 = [[MyObject1 alloc] init];
}
+(MyObject1*)myObject1 {
return myObject1;
}
#end
Usage:
MyObject1 *shared = [GlobalObjects myObject1];
You could also make the variable static inside its method for lazy initialization.
Yeah I use properties of the App Delegate, then access them by casting the sharedApplication delegate property.
__weak AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
Hope this helps,
Jonathan
#property in AppDelegate is a good solution. You could also use a singleton.
You app delegate is fine if you just have a bunch of objects.
Otherwise you might build a sort of "model object" containing all of your global data.
Or, you might store them with Core Data, if they have any structure at all.
But, as I said, if you have just a couple of objects, the app delegate will just do fine.
if it's only used among view controllers, you might consider storing it in the highest level view controller which actually needs access to the shared object (when creating/pushing new controllers, set that reference counted property).
in this way, you might think of the master view controller populating the detail view controllers with their content/models.
that's really stepping away from qualification as (and burdens of) a global.

viewDidLoad vs appDelegate methods

I persist to be a little confused about when to put something in a viewController and when to put it inside an AppDelegate, and if it is ok to reference viewController methods from the AppDelegate (i know you can but that doesn't mean it is encouraged).
Really, I wouldn't be confused if it weren't for all this multi-tasking stuff that seems to complicate the concepts for me. First, if anyone knows of a good, thorough and easy to read overview of how to deal with multitasking, I'd love to know.
Here's the deal: there are things I need my app to do when it loads, whether loading fresh or loading from the background. Stuff like perform a network reachability test, setup the interface based on data received from the internet, and this or that.
One of my main questions relates to how the viewcontroller's view interacts with background states. If the app resumes from the background and the view is immediately present without loading, then I assume it is still in memory and I have verified that viewDidLoad was not called with a basic NSLog. So, is it safe to say that any and all objects retained by my viewcontroller (like the data models and all subviews) are thus still in memory? If not, what's the best practice discovering which objects need to be re-loaded, what are still there, etc?
I think it's safe to assume that the standard memory management rules apply, even in a multi-tasking environment. That means that your controller, and anything you've got a reference to in your controller should still be valid until either:
You explicitly deallocate your controller/objects
Your app terminates
It seems like your assumption is that the system is going to mess with your objects behind your back, which (I hope) can't happen. Those methods are there in the app delegate in case you want to explicitly do anything when those particular events occur.
Regarding the viewDidLoad question, you could implement viewDidUnload or check the isViewLoaded method to make sure your view wasn't unloaded due to a low memory condition or otherwise. More on this in the UIViewController documentation.
One way to approach this problem is with lazily-loaded properties. In your .h file:
#interface YourViewController : NSObject
#property (nonatomic, retain) NSArray *exampleObject;
#end
And in your .m file:
#implementation YourViewController
#synthesize exampleObject = _exampleObject;
- (NSArray *)exampleObject {
// reload only if necessary
if (!_exampleObject) {
_exampleObject = [[NSArray alloc] init];
// do whatever other setup you need to
}
return _exampleObject;
}
#end

What are NSManagedObjectContext best practices?

I'm working with a Navigation Controller based iOS app. There are multiple tableView screens that pull and save data from a Core Data persistent store. Most of the data for the different table views comes from NSFetchedResultsController instances or NSFetchRequests.
The app works as intended but I have been getting a few random crashes and glitches that seem to be related to Core Data. For example sometimes when I save the context the app will crash but not always. Another thing I've been seeing is the very first tableView doesn't always update the reflect the data that was modified in it's detail view.
Currently I'm passing around a single Managed Object Context that was created in the app delegate to each of the different view controllers by setting the context property of the view controller just before I push it onto the navigation stack.
This seems like a clunky, hacky way of getting the job done. Is there a better design pattern to use?
I noticed in one of the WWDC sessions using delegation but I've never used creating my own delegates before and haven't been able to puzzle it out of the WWDC session.
Thanks.
=)
Use singleton NSManagedObjectContext for all Controllers isn't a best practice.
Each Controller should have your own Context to manage specific, sometimes atomic, operations at document store.
Think if you can edit a NSManagedObject attached to Controller that pass the same Context to other Controller that will select another instance to delete or edit.. you can lost the controll about modified states.
When you create a view controller, you pass it a context. You pass an
existing context, or (in a situation where you want the new controller
to manage a discrete set of edits) a new context that you create for
it. It’s typically the responsibility of the application delegate to
create a context to pass to the first view controller that’s
displayed.
http://developer.apple.com/library/ios/#documentation/DataManagement/Conceptual/CoreDataSnippets/Articles/stack.html
1)
Use a singleton for your CoreData setup (NSPesistentStoreCoordinator, NSManagedObjectModel & NSManagedObjectContext). You can use this singleton to execute the fetch requests you created in your Models and to add or delete Entities to your Context.
2)
Delegates are not that hard. Following is a sample:
#class SomeClass
#protocol SomeClassDelegate <NSObject> //Implements the NSObject protocol
- (void) someClassInstance:(SomeClass *)obj givesAStringObject:(NSString *)theString;
- (BOOL) someClassInstanceWantsToKnowABooleanValue:(SomeClass *)obj //Call to delegate to get a boolean value
#optional
- (NSString *) thisMethodIsOptional;
#end
#interface SomeClass : NSObject {
id<SomeClassDelegate> delegate;
//Other instance variables omitted.
}
#property (assign) id<SomeClassDelegate> delegate;
#end
#implementation SomeClass
#synthesize delegate;
- (void) someMethodThatShouldNotifyTheDelegate {
NSString *hello = #"Hello";
if (self.delegate != nil && [self.delegate respondsToSelector:#selector(someClassInstance:givesAStringObject:)]) {
[self.delegate someClassInstance:self givesAStringObject:hello];
}
}
#end
Option 1 could be something like this, you will have to setup the variables in the init of the object (and implement the singleton ofcourse):
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#interface CoreDataUtility : NSObject {
#private
NSManagedObjectModel *managedObjectModel;
NSManagedObjectContext *managedObjectContext;
NSPersistentStoreCoordinator *persistentStoreCoordinator;
}
+ (CoreDataUtility *)sharedCoreDataUtility;
- (NSEntityDescription *) entityDesctiptionForName:(NSString *)name;
- (NSMutableArray *) executeRequest:(NSFetchRequest *)request;
- (id) getInsertedObjectForEntity:(NSString *)entity;
- (void) deleteAllObjects:(NSString *) entityName;
- (void) deleteManagedObject:(NSManagedObject *)object;
- (void) saveContext;
#end
Currently I'm passing around a single Managed Object Context that was
created in the app delegate to each of the different view
controllers...This seems like a clunky, hacky way of getting the job
done. Is there a better design pattern to use?
There's nothing particularly special about a managed object context in this respect, it's just another object that your view controller may need to do its job. Whenever you're setting up an object to perform a task, there are at least three strategies that you can use:
Give the object everything it needs to get the job done.
Give the object a helper that it can use to make decisions or get additional information.
Build enough knowledge about other parts of the application into the object that it can go get the information it needs.
What you're doing right now sounds like the first strategy, and I'd argue that it's often the best because it makes your view controllers more flexible, less dependant on other parts of the app. By providing the MOC to your view controllers, you leave open the possibility that you might someday use that same view controller with a different context.
Jayallengator makes the helpful observation that every managed object has a reference to its context, and if you're passing around specific managed objects you don't also need to pass along the context. I'd take that a step further: if you're passing specific managed objects to your view controller, the view controller often won't need to know about the context at all. For example, you might keep Game objects in your data store, but a GameBoardViewController will probably only care about the one Game that's being played, and can use that object's interface to get any related objects (Player, Level, etc.). Perhaps these observations can help you streamline your code.
The second strategy is delegation. You'll usually use a protocol when you use delegation, so that your object knows what messages it can send its helper without knowing anything else about the helper. Delegation is a way to introduce a necessary dependency into your code in a limited, well-defined way. For example, UITableView knows that it can send any of the messages defined in the UITableViewDelegate protocol to its delegate, but it doesn't need to know anything else about the delegate. The delegate could be a view controller, or it could be some other kind of object; the table doesn't care. The table's delegate and data source are often the same object, but they don't have to be; again, the table doesn't care.
The third strategy is to use global variables or shared objects (which is what people usually mean when they talk about singletons). Having a shared object that you can access from anywhere in your code is certainly easy, and you don't have that "klunky" extra line of code that configures your object, but it generally means that you're locking your view controllers in to using that shared object and no other. It's a lot like gluing a hammer to your hand because you know for certain that that hammer is the tool you need. Works great for pounding nails, but it can be painful if you later discover that you'd like to use the same hand for driving screws or eating dinner.
The singleton approach seems to be best-practice, but another trick I found useful was that in cases where you're passing a NSManagedObject from one view controller to the next anyway (usually as an instance variable), you don't need to also pass the NSManagedObjectContext since you can get the context from the object you passed in by invoking [myManagedObject managedObjectContext]. This can be a handy shortcut when there's maybe only one or two methods where you need the context and you don't want the overhead of creating yet another NSManagedObjectContext ivar/property.