Rookie Question:
I have my ViewController.m that is getting rather big. What is the way to "off-load" some (general purpose) code to another dot-something file (let's call it myStuff.m)?
Or to rephrase the question:
How I call a method from another .m file,
How I can access a variable and
How I can access an element (UIView) of another .m file.
Example:
In myStuff.m I want to do the following:
[ViewController ViewController_Method:#"bla"];
yLocal = ViewController.xRemote;
[ViewController.myText setText:#"bla-bla"];
What code do I have to add to my ViewController.m and how should the myStuff.m be set-up to do it?
What is the (easiest) way of doing it?
Variables
Declare public variables
#property(nonatomic,strong) VariabledatType *myVariablename;
Methods
Declare public methods
-(void)myPublicMethod:(NSString *)perameterString;
Access from another class
Let consider the variables and methods are the part of Class1
Class1Obj.myVariablename //Accessing variables;
Class1Obj.myVariablename = someValuel; //setting values to variables;
[Class1Obj myPublicMethod:#"myString"]; //calling Methods;
Sounds to me like you need to do some reading up on Objective-C, Object design and Model View Controller (MVC).
Here's some links
Objective-C tutorial
MVC
Design Fundamentals
Check out the Stanford University lectures on iOS development (Paul Hegarty) as well - they are excellent.
Related
This question already has answers here:
What is the Objective-C equivalent of a public get/protected set property in C#
(3 answers)
Closed 9 years ago.
I have got two classes, Class1 and Class2, the second one inherited from the first one. I need to override -update method of Class1 to achieve my goals. The changes of -update method in inherited method are performed in the middle of code, so I can not use [super update]. Thats why I need to copy-paste original method from parent to inherited class. This method is using private methods of parent, so when I am trying to do overriding, I got warnings about absence of private methods because Class2 imports only Class1.h. To clarify, here is the code:
Class1.h:
#interface Class1 : NSObject
-(void) update;
#end
Class1.m:
#interface Class1 (Private)
-(void) private1;
-(void) private2;
#end
#implementation Class1
-(void) update
{
[self private1];
[self private2];
}
-(void) private1
{
// some code
}
-(void) private2
{
// another code
}
#end
Class2.h:
#interface Class2 : Class1
-(void) update;
#end
Class2.m:
#implementation Class2
-(void) update
{
[self private1]; // warning here
// do my own stuff between private methods, that is the reason of inheritance
[self private2]; // warning too
}
#end
Also, Class1 is not in my ownership, it is the one from open-source library (Cocos3D, to be precise), so I could not change it (and that is why I do inheritance).
The question is: how can I remove warnings? The only solution I can see is to copy private methods' signatures to Class2, but it seems to be a dirty trick. Or, it would be perfect if somebody points not how to remove warnings, but how to achieve my goal in changing method more nicely.
No need for swizzling, performSelector: or any other runtime buggery.
Just move or copy this:
#interface Class1 (Private)
-(void) private1;
-(void) private2;
#end
To the beginning of your subclass's .m file.
Normally, when trying to achieve something like an #protected scope for methods, the declaration of such would be in a header file like Class1_Private.h and that header would be set to the private role in Xcode.
As others have noted, exposing a private method via this mechanism is a bit dangerous. Given that Cocos2D is open source, that danger is mitigated somewhat or you could always just modify it directly. Of course, doing so means you effectively have a branch, which is costly to maintain.
If this is something that other developers are likely to do, I'd suggest filing a bug with Cocos2D requesting that the methods be exposed for subclassing purposes.
The way Apple does this is to make any methods that can be overridden in a subclass public, but document the fact that they shouldn't be called directly and are only there to be overridden. Documentation for Apple's code is (usually) comprehensive, and often referred to, so this works. Of course, typical third party code isn't as well documented, nor is documentation as likely to be read...
Another solution: I often create a second header called "MyClass+SubclassMethods.h", and publicly declare subclass-overrideable, but otherwise private methods in a category there. In source files for users of the base class and subclasses, this isn't imported, so the methods stay (effectively) private. In subclasses of the base class, I import "MyClass+SubclassMethods.h" to allow me to override/call these methods. It's not a perfect solution, but without the notion of 'protected' methods in Objective-C, I'm not sure there's a much better one.
A category, as suggested in another response is a good solution given that Class1 cannot be modified. If it were possible to make adjustments to source, a class extension declared in a separate header file and #imported in both the Class1 implementation, and the Class2 implementation file would be the way because then you can share not only private methods but also instance variables marked #public or #protected this way. Find out more about class extensions from here:
http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/ProgrammingWithObjectiveC/CustomizingExistingClasses/CustomizingExistingClasses.html
Briefly, a class extension is a bit like a category (sometimes called a private category) but it can only be declared in the same compilation unit where the class it extends is implemented, and it can declare (and auto-synthesize) properties and instance variables. There's a source code template included in Xcode for creating class extensions (see below.)
You should be able to solve this problem using categories to extend your original class and try method swizzling to achieve your desired behavior.
So I noticed that in my new Xcode projects, by default there was a category for my class in my .m file. For example, I'll have this in the .m file:
#interface ViewController ()
#end
#implementation
//Some code
#end
I was wondering is it okay to declare my variables and functions in the category in the .m file, or should I do that in the .h file like before. Basically, what are the best practices in respect to categories.
By the way, my question is sort of related to the below link, but that link does not completely answer my question.
This is not a category, it is a class extension (notice the empty parentheses). You can keep private implementation details, including private ivars, in the extension to limit the declarations in the .h file to the interface of your class. Note that you can add ivars only in the extensions, not in categories.
One very important consequence of this approach is that if you need ivars of types that require additional headers needed only for implementation, you can avoid including that header in the header of your interface, hiding implementation dependencies from users of your class.
Its kinda general question. What difference it make if we create instance of UIViewController in interface (.h) file and declare it as property and use it in implementation (.m) file to push it on current view than that of creating instance in implmentation file itself and push it on current view in UINavigationcontroller ?
Regards,
Sumit
In Interface i.e. .h file we are just having declaration of the variables and that are only the references to the class and NOT the INSTANCE... Please understand the difference between reference and instance both are different. When declaring in .h file we are agreeing that we are going to use that variable in our .m file. And we can instanciate it... Also other 2 answers are also having its own points....
Usually you define your UIViewController in .h as a field of your #interface because you may need to access it in more than one point or it can be useful, for you, to keep a pointer to that controller. If you don't need this you can simply define it in .m, use it and then release (or autorelease) it.
There are a few differences. By making it a property the code generated will have some retain/release logic built in.
Also, by declaring the field and property in your .H file, the member is effectively "public" and visible now from other classes. If you only have the member defined in your .M file, it is only accessible within your own class.
I'm looking through the PageControl example from Apple. They have a class called ContentController. In a subclass of the class, PhoneContentController.m, they have this:
#interface ContentController (PrivateMethods)
- (void)loadScrollViewWithPage:(int)page;
- (void)scrollViewDidScroll:(UIScrollView *)sender;
#end
Is this adding a category to the class ContentController?
Why would they put it in this file, versus the original file they created?
By declaring it in the PhoneContentController.m file, does it give this class access without having any additional directives for the compiler?
(I'm trying to understand the OOAD principles and why Apple does certain things in their example code, hierarchies, etc). Thanks!
Is this adding a category to the class ContentController?
Yes, they are adding a category.
Why would they put it in this file, versus the original file they created?
If I recall correctly, this is done because there are two UIs, (one for iPad and one for iPhone,) so that they can write the code only once and use the same handlers in the different view controllers.
By declaring it in the PhoneContentController.m file, does it give this class access without having any additional directives for the compiler?
Well, yes. It's a small matter to compile an additional 4 line file, and I think this is a template related decision rather than a compiler related one. It's simpler to distribute, say, 3 sample files instead of 4, for example.
I have two views with their own .h and .m files of course. How can I declare a bool (or any variable for that matter) in one view and be bale to access it in another view?
Thanks.
Objective C is a superset of plain ANSI C, so you would create and use global variables exactly the same way as in old-fashioned C.
In exactly one .m or .c file, put:
BOOL gMyGlobalBoolVar = NO; // or YES, depending on whatever initial state is needed
I might place these in a centralized singleton class, such as your appdelegate .m file, or in a separate .c file, such as myGlobals.c. I usually place these after the #imports/includes but before any class, method, or function definitions to clarify that they can be accessed outside of any object or function.
In the .h files for all classes where you want to access gMyGlobalBoolVar, put:
extern BOOL gMyGlobalBoolVar;
Then just use them anywhere in the class:
if ( [ self dogHasFleas ] ) {
gMyGlobalBoolVar = YES;
}
The use of global variables is currently not "politically correct", but for quick code that you will never try to publish, reuse, extend, or hunt for gnarly bugs, they work just fine like they did in almost every computer and programming language from 50+ years ago.
You can just take a reference to the view containing the bool and get the variable using a getter.
If you want app wide variables, you could put them in the AppDelegate, but I highly recommend against that since it tightly couples classes.
Create a data model class. Instantiate it in your app delegate, and pass it along to your view controllers. Use Key-Value Observing to track changes to the model in your view controllers. See my answer here: How do I display and calculate numbers from a database on iPhone?
"Why shouldn't I use globals? It can't hurt just this once." This is a bad habit to get into. Avoiding global variables makes your code easier to read and reuse, easier to extend, and easier to debug.