Properties across classes in Objective C - ios

I am new to Objective C, so please forgive the simplicity of my question.
I have a class, lets call it Class A and it looks like this
#interface A()
#property (weak, nonatomic) IBOutlet UISegmentedControl *segment;
#end
#implementation A
...
Now what I want to do, is "get" the segment in class B. I have tried doing this by doing this
#interface B()
#property (nonatomic) B *cardy;
#end
#implementation B
...
I then want to do cardy.segment, but I cannot seem to access it. I tried using #synthesize in A but need to ensure exactly how to implement the "get" properly. Any advice would be greatly appreciated.

Declare the property in the .h file, not the .m file. Also, make sure A.h is imported in B.m

Related

Cannot access property from class

//MigrationVC.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#interface MigrationVC : UIViewController
#end
//MigrationVC.m
#import "MigrationVC.h"
#interface MigrationVC()
#property (strong, nonatomic) IBOutlet UILabel *label;
#property (strong, nonatomic) IBOutlet UIProgressView *progressView;
#end
#implementation MigrationVC
#end
//CoreData
#import "CoreData.h"
#import "MigrationVC.h"
#interface CoreData()
#property (nonatomic,retain) MigrationVC *migrationVC;
#end
-(void)obsererForKeyPath:(NSString*)keyPath object:(id)object change:(NSDictionary*)change context:(void*)context
{
if([keyPath isEqualToString:#"migrationProgress"])
{
dispatch_async(dispatch_get_main_queue(),^{
float progress=[[change objectForKey:NSKeyValueChangeNewKey] floatValue];
self.migrationVC.progress=progress;
});
}
}
I am trying to learn CoreData and migration right now but this is giving me a quite a headache.
I am trying to access the outlet properties from another classes but always gives red warning (Property 'label' not found on object of type MigrationVC*).
I tried adding a NSString property in .h file which was accessible but when i tried to change the outlet from .m to .h file i couldn't ctrl+drag the view in the .h file.
I never had this problem. I have accessed outlet from .m file many times in the past but it just gives me warning now.
How can i access the properties while outlet in .m file?
I cannot outlet the properties in .h file.
You have to transfer you outlet properties from .m file to .h file (copy and paste). If you want your properties to be public so they have to be declared in header file. If you want them to be private - declare them in implementation file.
//MigrationVC.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#interface MigrationVC : UIViewController
#property (strong, nonatomic) IBOutlet UILabel *label;
#property (strong, nonatomic) IBOutlet UIProgressView *progressView;
#end
//MigrationVC.m
#import "MigrationVC.h"
#interface MigrationVC()
#end
#implementation MigrationVC
#end
As others have pointed out, you need to declare your properties in your header file if you want them to be accessible from other classes. You can, and you should. If you think you can't do that, explain why.
More important, though, is that you should not do what you are trying to do. You should not try to access a view controller's view objects from outside the view controller. That violates the principle of encapsulation, an important principle of object-oriented design. (It means that code outside of your view controller is dependent on the appearance of your view controller. If you later decide to make internal changes to your view controller, you are very likely to break outside code.) In addition to the somewhat abstract "It's bad design" reason for not doing it, it often doesn't work, because at the time to try to modify a view controller's views, they don't exist yet.
Instead, you should create DATA properties (like strings, or floating point progress values) in your view controller and expose those. Then have your view controller's viewWillAppear method install the data into it's views as appropriate. That way the data properties become part of the view controller's public contract without being tied to the internal details of the view controller.
You properties are declared in the private category so they are not visible for other classes. Only properties declared in a header file are visible.
In CoreData.m your MigrationVC is set as retain. I don't know if you can use it since with ARC.
#property (nonatomic,retain) MigrationVC *migrationVC;
It should be
#property (nonatomic,strong) MigrationVC *migrationVC;
And in MigrationVC your outlets should be weak not strong and in .h to be accesible from CoreData.m

What is the standard format for a .h file? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
I am wondering what the standard layout/format is for an Objective-C interface (.h) file. I know what components are present within this file, but I have seen them laid out in many different ways.
A lot of the components of an interface file are pretty obvious like the #import, #class, etc. But for something like the #protocol and #interface declarations it can be different. I have seen people declare a new protocol above the interface declaration with its implementation of methods below:
#protocol MyNewClassDelegate;
#interface MyNewClass : UIViewController
// Properties and Methods
#end
#protocol MyNewClassDelegate <NSObject>
- (void)method
#end
The other way that I've seen it is by just having the entire #protocol declaration and implementation above the #interface statement. So it'd be something like this:
#protocol MyNewClassDelegate <NSObject>
- (void)method
#end
#interface MyNewClass : UIViewController
//Properties and Methods
#end
I have also seen it setup where one protocol is declared and implemented above the interface while another one is also declared and implemented below.
My question is which one is preferred or is a standard in the industry? Is there some kind of way you organize it based around what its functionality accomplishes?
I don't see how my answer is more right than others, but this is what i do in most of my applications.
#import
#import
#define
#define
typedef
typedef
#class ClassName
#class ClassName
#protocol ProtocolName;
#interface Name : inheritedObject <FirstProtocolSupported, SecondProtocolSupported, etc>
#property (noantomic, strong) IBOutlet Object* name;
#property (noantomic, strong) IBOutlet Object* name;
#property (noantomic, strong) IBOutlet Object* name;
#property (nonatomic, strong) Object* name;
#property (nonatomic, strong) Object* name;
#property (nonatomic, strong) Object* name;
- (IBAction)actionName:(SenderObject*)sender;
- (IBAction)actionName:(SenderObject*)sender;
- (IBAction)actionName:(SenderObject*)sender;
- (type)methodName:(Parameter*)argument;
- (type)methodName:(Parameter*)argument;
- (type)methodName:(Parameter*)argument;
#end
#protocol ProtocolName <ProtocolThatIsImplmented>
- (type)protocolMethod:(Param*)parameter;
#end
in essence it's, import statements then, #define statements then, typedef statements, #class statements then, any protocols, then class declaration, then iboutlet properties, then normal properties, then inaction methods, then normal actions, then the protocol declaration.
All in all there is no correct way to order the code in the .h file, it's all a matter of preference, as long as everything is declared accurately
As far as I know, there isn't any correct (or even preferred) convention for writing your .h files. Header files are typically very short, unless you have scores of properties and methods (as is the case with many of Apple's Foundation and UIKit classes). Even the most unwieldy header files generally don't exceed several hundred lines of code, so there's not much to worry about.
However, sometimes your protocol and its class will be codependent. In other words, the protocol needs to be aware of the class, and the class needs to be aware of the protocol.
For instance, UITableView needs to know about the protocols UITableViewDelegate and UITableViewDataSource, since it defines properties which must conform to those protocols (namely, delegate and dataSource). However, each of those protocols also need to know about UITableView since they both require a UITableView as a parameter for many of their methods (such as numberOfSectionsInTableView:).
In this scenario, your second example (declaring the protocol in its entirety before the class) wouldn't suffice unless you used a forward #class declaration ahead of the #protocol definition. Your first example would work, because you are using a forward #protocol declaration ahead of the class.
I prefer my protocols to be in their own .h file. That way they can easily be reused.
You also wouldn't have to worry about the 'order' of things when you #import it.
//Copyright & license
#import
#import "AProtocol.h"
#import "Typedefs.h"
#import "NeededConsts.h"
#class ClassName;
#class ClassName;
#interface Name : inheritedObject
#property (strong, nonatomic) Object* name;
- (type)methodName:(Parameter*)argument;
- (void)setDelegate:(id <AProtocol>)argument;
#end
Inside the Name.m file (I try to keep as much info as possible out of the .h file)
//Copyright & license
#import ...
#import "ProtocolName.h"
file wide typedef
file wide typedef
#class ClassName;
#class ClassName;
static const NSInteger cFileWideInt = 404;
#interface Name () <FirstProtocolSupported, SecondProtocolSupported, etc>
#property (strong, nonatomic) IBOutlet Object* name;
#property (strong, nonatomic) IBOutlet Object* name;
#property (weak, nonatomic) id<AProtocol> delegate;
#end
#implementation
#end
The benefit of having most of your properties and declarations inside of your .m file is that it provides 'encapsulation' for information that your other classes don't need to know. This point leads into code architecture which would turn this into a long and complex answer ;P

Properties don't get initialized in iOS 7

I'm developing for iOS 7 but I still have to manually write getters otherwise my properties just don't get initialized. I tried to manually synthesize those properties, even though that shouldn't be needed anymore, but that doesn't do it.
In my view controller below, I use the property motionTracker, which never gets initialized. I have the same issue with all my projects, so I know it's a misunderstanding on my part.
#import "ViewController.h"
#import "TracksMotion.h"
#interface ViewController ()
#property (weak, nonatomic) IBOutlet UIButton *startRecording;
#property (weak, nonatomic) IBOutlet UIButton *stopRecording;
#property (strong, nonatomic) TracksMotion *motionTracker;
#end
#implementation ViewController
#synthesize motionTracker = _motionTracker;
- (void)startMyMotionDetect
{
[self.motionTracker startsTrackingMotion];
}
#end
The motionTracker has a public API for the method startsTrackingMotion so I don't know why this doesn't work.
#import <Foundation/Foundation.h>
#import <CoreMotion/CoreMotion.h>
#interface TracksMotion : NSObject
- (void)startsTrackingMotion;
- (void)stopTrackingMotion;
#property (strong, nonatomic) CMMotionManager *motionManager;
#end
Properties / instance variables are not magically initialized for you. When you say:
#property (strong, nonatomic) TracksMotion *motionTracker;
... you are just reserving memory space for an instance variable (and generating a getter and a setter method through #synthesize or autosynthesis). There is no actual TracksMotion object there until you put one there. You must write code to do that. You must create or obtain a TracksMotion instance and assign it to self.motionTracker at some point, presumably early in the life of self (in this case, that's a ViewController instance). Until you run code that does that, self.motionTracker is nil.
(It is possible that you are being confused because it looks like outlets are automatically initialized. For example, you've got #property (weak, nonatomic) IBOutlet UIButton *startRecording; And sure enough, self.startRecording is a button. But that's because the nib-loading process does for you the very thing I'm saying you must do: it makes a button from the storyboard or .xib file, and assigns it to this instance variable.)

Can we put IBOutlets in a category?

Since the ViewController's code is getting too large, I was wondering how to split the code into multiple files. Here's the problem I ran into:
// In the original .m file, there are bunch of outlets in the interface extension.
#interface aViewController()
#property (weak, nonatomic) IBOutlet UIView *contentView1;
#property (weak, nonatomic) IBOutlet UIView *contentView2;
#property (weak, nonatomic) IBOutlet UIView *contentView3;
#end
I want to split the file into 3 categories, according to three different views.
// In category aViewController+contentView1.m file
#interface aViewController()
#property (weak, nonatomic) IBOutlet UIView *contentView1;
#end
If I delete the original contentView1 outlet, however, it doesn't work.
Question
Why do I have to keep the contentView1 outlet in the original .m file?
An Objective-C category doesn't allow you to add additional properties to a class, only methods. Thereby, you aren't allowed to add additional IBOutlets within a category. A category is denoted similar to #interface aViewController (MyCategoryName) (note the name given inside the parentheses).
You can, however, add additional properties within a class extension. A class extension is denoted with the same name as the original class followed by (). In your code example, both lines referring to #interface aViewController() actually declare a class extension (not a category), regardless of which header file they're actually in.
Furthermore, you are allowed to create multiple class extensions across several different headers. The trick is that you need to import these correctly.
In example, let's consider a class called ViewController. We want to create ViewController+Private.h and ViewController+Private2.h that have additional privateView outlets, which will still be accessible within ViewController.m.
Here's how we can do it:
ViewController.h
// Nothing special here
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
// some public properties go here
#end
ViewController+Private.h
// Note that we import the public header file
#import "ViewController.h"
#interface ViewController()
#property (nonatomic, weak) IBOutlet UIView *privateView;
#end
ViewController+Private2.h
// Note again we import the public header file
#import "ViewController.h"
#interface ViewController()
#property (nonatomic, weak) IBOutlet UIView *privateView2;
#end
ViewController.m
// Here's where the magic is
// We import each of the class extensions in the implementation file
#import "ViewController.h"
#import "ViewController+Private.h"
#import "ViewController+Private2.h"
#implementation ViewController
// We can also setup a basic test to make sure it's working.
// Just also make sure your IBOutlets are actually hooked up in Interface Builder
- (void)viewDidLoad
{
[super viewDidLoad];
self.privateView.backgroundColor = [UIColor redColor];
self.privateView2.backgroundColor = [UIColor greenColor];
}
#end
And that's how we can do it.
Why Your Code Wasn't Working
Most likely, you've probably mixed up the #import statements. To fix this,
1) Make sure that each class extension file imports the original class header (i.e. ViewController.h)
2) Make sure that the class implementation (i.e. ViewController.m) file imports each of the class extension headers.
3) Make sure the class header (i.e. ViewController.h) file doesn't import any of the class extension headers.
For reference, you can also checkout the Apple docs on Customizing Existing Classes.

Properties just getters but not setters

I am create a Class which have a UIWebView property. I want to set the properties in its main file, but want to make sure the other developers if use this properties can just get the properties but not rather set it again.
I have looked in #private iVar's but apparently it only regulates dot function not to get set yet if I call [WebView LoadRequest:[NSURLRequest]], the function can still be called from outside of the class.
It be nice to know if there is any work through for this?
Thanks.
Foo.h
#interface Foo
#property (retain,readonly) NSString *bar;
#end
Foo.m
#import "Foo.h"
#interface Foo ()
#property (retain,readwrite) NSString *bar;
#end
#implementation Foo
#synthesize bar;
#end

Resources