Cannot access property from class - ios

//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

Related

Cannot find the Referencing Outlets declared in Objective-C File

I declared a UIView in the objective-C Class File (Test.m)
#property (nonatomic,strong) UIView *Scene1;
In the StoryBoard, when I am trying to make a reference outlet pointing to the view I set in the objective-C file, Scene 1 is not displayed in the list.
Note: 1. I have already pointed the view to the correct class file.
2. They are all UIView type
Here's the code of the header file (Test.h)
#import "JSMessagesViewController.h"
#interface Test : JSMessagesViewController
#end
Here's the code for the Class File Test.m
#import "Test.h"
#import "MessageData.h"
#interface DeerView () <JSMessagesViewDelegate, JSMessagesViewDataSource, UIImagePickerControllerDelegate, UINavigationControllerDelegate,UIActionSheetDelegate>
#property (strong, nonatomic) NSMutableArray *messageArray;
#property (nonatomic,strong) UIImage *willSendImage;
#property (nonatomic,strong) UIView *Scene1;
#end
#implementation DeerView
#synthesize messageArray, NameInput, Scene1, Scene2, Scene3, Scene4, Name;
...
#end
I am a high school student and a young developer who is still learning more. Hope you can help with my question.
Change your declaration of outlet and mark it as outlet
#property (nonatomic, weak) IBOutlet UIView *Scene1;
And you don't need to declare it as a strong property if you won't remove it from subview.

Objective C - cannot set delegate error - Cannot find protocol declaration for 'myNSObjectClassDelegate'

I just got started working with delegates.
from some reason I cannot do it, and I see errors.
I tried to do the next code on a new project and it was OK, but when i'm moving this code to my main project I have a few issues.
my NSObject class .h:
#protocol myNSObjectClassDelegate <NSObject>
#required
-(void)doSomething;
#end
#interface GeneralMethods : NSObject
#property (nonatomic,strong) id<myNSObjectClassDelegate> delegate;
#end
my NSObject class .m:
#synthesize delegate;
-(void)SomeMethod {
if ([delegate respondsToSelector:#selector(doSomething)]) {
[delegate doSomething];
}
}
my UIViewController .h
#import "GeneralMethods.h"
#interface view : UIViewController<UIGestureRecognizerDelegate,
UINavigationControllerDelegate,
 UIImagePickerControllerDelegate,
myNSObjectClassDelegate>
The error is here at .h - Cannot find protocol declaration for 'myNSObjectClassDelegate'
my UIViewController .m
-(void)doSomething{
}
What am I doing wrong?
EDIT : I figure it out:
For some reason, at my NSObject class, if I'm moving the #import myUIViewcontroller after this:
#protocol myNSObjectClassDelegate <NSObject>
#required
-(void)doSomething;
#end
the problem solved.
We can't see all the code but after reading some more of the exchanges it looks like dependencies are maybe added out of order. I recommend moving the protocol into its own file and #import'ing it to all the places that use it. This way you definitely will be importing things in the order you expect.
In addition to that, the following property declaration:
#property (nonatomic,strong) id<myNSObjectClassDelegate> delegate;
Delegates should be declared as weak, not strong.
#property (nonatomic,weak) id<myNSObjectClassDelegate> delegate;
The reason is to avoid retain cycles/memory leaks. Typically, though not always the relationship looks like this:
Parent Object (usually Controller) -----STRONG-----> Child (View often)
View Thing ----WEAK--------> delegate (actually the Parent Object)
Now if the relationship is STRONG both ways, releasing the parent from all who own it will not be sufficient to release it since its child also holds an owning relationship to it.
Also you can omit the:
#synthesize delegate;
Auto property synthesis renders this obsolete.
Make sure to import your NSObject class .h. file into your UIViewController's .h file (or wherever you declare the protocol). As it stands, you haven't imported the header that declares the protocol so your view controller has no way of knowing that it exists.
Ex:
#import "FileWithProtocol.h"
#interface MyClass <MyProtocol>
...
#end
In the view controller .h file, try adding this line:
#protocol MyNSObjectClassDelegate;
before
#interface ...

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.)

Cannot create instance of View Controller

I have a UIViewsubclass. I am not able to create an instance of another View Controller in this UIView class, so that i can access the variables set in my UIView subclass in this View Controller? Can anyone guide me on this
#import <UIKit/UIKit.h>
#import "DirectoryFormViewController.h"
#class NIDropDown;
#protocol NIDropDownDelegate
- (void) niDropDownDelegateMethod: (NIDropDown *) sender;
#end
#interface NIDropDown : UIView <UITableViewDelegate, UITableViewDataSource>
{
NSString *animationDirection;
UIImageView *imgView;
DirectoryFormViewController *dict; // i am not able to create this
}
#property (nonatomic, retain) id <NIDropDownDelegate> delegate;
#property (nonatomic, retain) NSString *animationDirection;
-(void)hideDropDown:(UIButton *)b;
- (id)showDropDown:(UIButton *)b:(CGFloat *)height:(NSArray *)arr:(NSArray *)imgArr: (NSString *)direction;
#property(nonatomic)int countryID;
#end
My DirectoyFormViewController:
#import <UIKit/UIKit.h>
#import "NIDropDown.h"
#interface DirectoryFormViewController : UIViewController<DropDownListDelegate,CLLocationManagerDelegate,UISearchBarDelegate,UITextFieldDelegate,NIDropDownDelegate>
#property(nonatomic)NSMutableDictionary *countryName;
#property(nonatomic,copy)NSMutableDictionary *sortName;
#property(nonatomic,copy)NSMutableDictionary *resultName;
#end
I want to set countryName,sortName and resultName in my NIDropDown
Thanks
Here's the short answer: you should never, ever, not for any reason create an instance of a view controller inside of a UIView. So the fact that you have not been successful so far is a good thing.
The Apple way of development on iOS is to use the Model, View, Controller design pattern. In MVC, the controller controls the models and the views and mediates communication between the two... not the other way around.
My suggestion is that you read the link and fully understand it before moving forward with development. With an understanding of the topics covered you'll never do things like have a UIView that's a table view delegate / datasource (because by doing that, your view is aware of the model, and that breaks MVC), and you'll hopefully never try to do things like create a UIViewController in a UIView.

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.

Resources