property as NSManagedObject in view controller for a "current NSManagedObject" - objective-c

I am interested in setting a property as a subclass, say Person, of NSManagedObject in a view controller that will specify an instance of person so that I will be able to update with methods in the controller. can I do it like this?
// Viewcontroller.h
#implementation
#property (nonatomic, retain) Person* currentPerson;
#end
// ViewController.m
#implementation
#dynamic currentPerson;
-(void) doSomethingToCurrentPerson {
currentPerson.SomeAtrribute=somevalue;
}
#end
It seems like if this were not a valid way to go, it would also be possible to set a unique identifier and then store CurrentPersonUniqueID as a property and use KVC. Is there a way to get something along the lines of what I posted to work, or am I better off with something closer to the KVC approach, or something totally different?

This code won't work until you replace #dynamic by #synthesize. #dynamic tells the compiler that -setCurrentPerson: and -currentPerson are implemented somewhere else, which is not the case.
So #synthesize currentPerson will create the currentPerson's getter/setter automatically. It won't have anything to do with the fact that Person is a NSManagedObject.
Also, either you can't access to currentPerson directly with this name, you have to use its getter:
self.currentPerson.attribute = something;
// or
[self currentPerson].attribute = something;
Correct code:
// Viewcontroller.h
#implementation
#property (nonatomic, retain) Person* currentPerson;
#end
// ViewController.m
#implementation
#synthesize currentPerson;
-(void) doSomethingToCurrentPerson {
self.currentPerson.SomeAtrribute = somevalue;
}
#end

Related

Can a category access instance variables defined in the class it extends?

I know it's not a great idea to try and place properties in a category. Can I access a class' instance variables from within a category that extends it? Or is it necessary to expose an accessor on the class being extended?
For example, let's say I have a class called "Person" and its implementation looks like this:
#import "Person.h"
#interface Person()
{
NSMutableArray *_friends;
}
#end
#implementation Person
- (instancetype)init
{
self = [super init];
if (self) {
_friends = [NSMutableArray array];
}
return self;
}
-(instancetype)initWithFirstname:(NSString *)firstName lastname:(NSString *)lastName
{
self = [self init];
if (self) {
_firstName = firstName;
_lastName = lastName;
}
return self;
}
-(NSString *)getFullName{
return [NSString stringWithFormat:#"%# %#", _firstName, _lastName];
}
#end
Notice the ivar _friends. Let's say (for some reason or other) I wanted to segregate all operations dealing with a person's friends into a category, like so:
#import "Person.h"
#interface Person (Friends)
-(NSArray *)getFriends;
-(void)addFriend:(Person *)person;
-(void)removeFriend:(Person *)person;
#end
In the category, Person(Friends), the compiler will not know about Person's ivar _friends.
i.e.
//Person.h
#interface Person
#property(nonatomic, strong) NSMutableArray *friends;
...
#end
It would be preferable to not expose this.
In general, categories can't access ivars; synthesized ivars and ivars from class extensions are private and invisible outside the main implementation.
You can, however, do what you want by declaring the ivar in an extension which is in its own private header, and importing that header into the category's implmentation file. Be sure to also import the private header into the class's main implementation file.
Who have told you that the compiler will not know about Person's _friends?
It knows. Just declare _friends in the class #interface, not in an extension.
#interface Person : NSObject
{
#protected
NSMutableArray *_friends;
}
#end
With #protected _friends will not be accessible for other objects.
If you've got a lot of protocols, delegates, dataSources etc. on your e.g. MainViewController and you wanna outsource their callbacks to separate files (categories) like
"MainViewController+DelegateCallbacks.h"
"MainViewController+DelegateCallbacks.m"
but at the same time still wanna be able to access all the controller's private #properties from these categories without having to expose them in the public interface
"MainViewController.h"
the most elegant solution is still to create a private interface (extension) in a separate header file like
"MainViewController_PrivateInterface.h"
BUT - instead of the ivars - like Josh Caswell's already explained above, put all the #properties (that these outsourced delegates need to access) in that extension, too. That way you keep them all quasi-private hidden and nobody else gets to see them. Above all not in your public interface! And you do even have the choice to access your #properties' backing store ivars directly in code (instead of the convenience dot notation) just by manually creating the corresponding backing store ivars in this private external interface file. Just don't forget to import your private's interface header everywhere you wanna access these ivars (including your MainViewController ;-)
//
// MainViewController.m
//
#import "MainViewController.h"
#import "MainViewController+DelegateCallbacks.h"
#import "MainViewController_PrivateInterface.h"
#interface MainViewController () <UICollectionViewDelegate,
UICollectionViewDataSource,
UICollectionViewDelegateFlowLayout,
UIGestureRecognizerDelegate>
#pragma mark - <UIGestureRecognizerDelegate>
#pragma mark - <UIContentContainer>
#pragma mark - <UITraitEnvironment>
// etc.
#end
------------------------------------------------------------------------
//
// MainViewController+DelegateCallbacks.h
//
#import "MainViewController.h"
#interface MainViewController (DelegateCallbacks)
#end
------------------------------------------------------------------------
//
// MainViewController+DelegateCallbacks.m
//
#import "MainViewController+DelegateCallbacks.h"
#import "MainViewController_PrivateInterface.h"
#implementation MainViewController (DelegateCallbacks)
#pragma mark <UICollectionViewDataSource>
#pragma mark <UICollectionViewDelegate>
#pragma mark <UICollectionViewDelegateFlowLayout>
// etc.
#end
------------------------------------------------------------------------
//
// MainViewController_PrivateInterface.h
//
#import "MainViewController.h"
#interface MainViewController () {
// NSMutableArray <NSArray *> *_myArray_1;
// NSMutableArray <UIBezierPath *> *_myArray_2;
}
#property (strong, nonatomic) NSMutableArray <NSArray *> *myArray_1;
#property (strong, nonatomic) NSMutableArray <UIBezierPath *> *myArray_2;
#property (weak, nonatomic) IBOutlet MyView *myView;
#property (weak, nonatomic) IBOutlet MyCollectionView *myCollectionView;
#property (nonatomic) CGFloat myFloat;
// etc.
#end

Subclassing PFObject And Overriding Dynamically Added Accessors

I understand how to subclass PFObject, but I am not certain how to perform additional custom code in an accessor, while still calling the generic implementation of that accessor as defined and #dynamic-ally added by Parse (which does the proper thing depending on the property's type, e.g. PFRelation, and so forth).
For instance...
// MyPFObjectSubclass.h
#import <Parse/Parse.h>
#interface MyPFObjectSubclass.h : PFObject<PFSubclassing>
#property (retain, nonatomic) id myProperty;
+ (NSString *)parseClassName;
#end
// MyPFObjectSubclass.m
#import "MyPFObjectSubclass.h"
#import <Parse/PFObject+Subclass.h>
#implementation MyPFObjectSubclass
#dynamic myProperty;
+ (NSString *)parseClassName {
return #"MyPFObjectSubclass";
}
- (void)setMyProperty:(id)someProperty {
// insert some custom code here, e.g. for validation...
// call the generic, dynamic implementation of setMyProperty, but how?
// obviously, you cannot call [super setMyProperty:someProperty];
}
#end
Any help is appreciated.
All you need to do is implement your own accessors and skip #dynamic

is this "property not found" error an XCode bug or a coding mistake on the part of a newbie? [duplicate]

Right before my model class sends the variable stringToDisplay, NSLog shows me that it has a value. But when I try to use it in my ViewController, I just get (null). Any thoughts about what I'm doing wrong?
(The good news is that, while working on this, I had sort of a breakthrough in understanding how models and controllers relate to each other. I'm still a complete newbie, but I don't feel quite as lost as I did.)
Here's what I think is the relevant code:
CalculatorBrain.h
#import <Foundation/Foundation.h>
#interface CalculatorBrain : NSObject
#property (nonatomic) NSMutableString *stringToAdd;
#property (nonatomic,strong) NSString *stringForDisplay;
- (double)performOperation:(NSString *)operation withArray:(NSMutableArray *)particularStackYouNeedToPopOff;
CalculatorBrain.m
#implementation CalculatorBrain
#synthesize stringToAdd = _stringToAdd;
#synthesize stringForDisplay = _stringForDisplay;
#synthesize whatHappenedSinceLastClear = _whatHappenedSinceLastClear;
- (double)performOperation:(NSString *)operation withArray:(NSMutableArray *)particularStackYouNeedToPopOff
{
<long code that I think doesn't matter because this NSLog produces exactly what I want it to:>
NSLog(#"%#",stringForDisplay);
return result;
}
CalculatorViewController.h
#import <UIKit/UIKit.h>
#interface CalculatorViewController : UIViewController
#property (nonatomic) NSArray *arrayOfDictionaries;
#property (nonatomic) NSDictionary *dictionary;
#property (weak, nonatomic) IBOutlet UILabel *variablesUsed;
#property (nonatomic, strong) NSString *operation;
#end
CalculatorViewController.m
#import "CalculatorViewController.h"
#import "CalculatorBrain.h"
#interface CalculatorViewController ()
#property (nonatomic,strong) CalculatorBrain *brain;
#end
#implementation CalculatorViewController
#synthesize display = _display;
#synthesize history = _history;
#synthesize brain = _brain;
#synthesize operation = _operation;
- (IBAction)operationPressed:(UIButton *)sender
{
NSString *otherString=[self.brain stringForDisplay];
if (self.userIsEnteringNumber) [self enterPressed];
NSString *operation = sender.currentTitle;
double result = [self.brain performOperation:operation withArray:[self.brain whatHappenedSinceLastClear]];
self.display.text = [NSString stringWithFormat:#"%g",result];
self.history.text = otherString;
NSLog(#"%#",otherString);
}
And the NSLog in that last line of code give me (null).
Any thoughts?
Maybe I'm missing something but your property is declared in the class extension of CalculatorBrain so nobody outside CalculatorBrain.m knows about this property.
So if you want to expose this property to other objects, you will have to declare it in CalculatorBrain.h instead.
Oh - your declaration of the property whatHappenedSinceLastClear isn't exposed to other classes that import CalculatorBrain.h because you put the property declaration in an interface extension in the .m file, which other classes will not see.
To make it publicly accessible move the #property line for whatHappenedSinceLastClear to CalculatorBrain.h, not the .m file.
I can guess that problem lies in the way you assign your stringForDisplay, eg.:
if you use something like
stringForDisplay_ = anotherString;
setter for property doesn't fire, so you have to retain your variable yourself otherwise it'll live just until your method finishes;
If so - use property setters, eg.:
self.stringForDisplay = anotherString;
that way ARC will do all the memory management.
It really depends how you set stringForDisplay inside the performOperation:withArray: method.
for a blind guess, try using
NSString *otherString = self.brain.stringForDisplay;
after this line
double result = [self.brain performOperation:operation withArray:[self.brain whatHappenedSinceLastClear]];

Can't assign value to instance variable

Here is a case where I am passing some parameters to a method, and then assigning the parameter values to local ivars and properties:
- (void) assignOwnerView:(UIView*)oView andPosition:(menuPosition)position withTopView:(UIView*)topView {
self.topView = topView;
self.ownerView = oView;
self.position = position;
<< --- other code --- >>
}
The interface for these properties is this (UPDATED with SYNTHESIS)
#interface MenuVC (){
UIView *ownerView_;
UIView *topView_;
menuPosition position_;
}
#property (nonatomic, retain) UIView *ownerView;
#property (nonatomic, retain) UIView *topView;
#property (assign) menuPosition position;
#end
#implementation MenuVC
#synthesize list, menuDelegate;
#synthesize ownerView = ownerView_;
#synthesize topView = topView_;
#synthesize position = position_;
- (id)initWithFrame:(CGRect)frame style:(UITableViewStyle)style
{...
The enum is defined here:
typedef enum {
above,
below,
centered
} menuPosition;
After executing the three assignments, at a breakpoint in the debugger, the values are as shown below:
The received parameter values look okay, but the assigned values of the ivars ownerView_ and position_ are not right. On the other hand, topView is okay.
The same thing happened when I assigned directly to ivars rather than properties.
I started seeing this problem when I upgraded to Lion (10.7.3) and XCode 4.3.1. It was working okay before then. I see this at other spots in my app, and I don't see any pattern to it yet.
ARC is not being used.
I reported this problem before, but didn't get an answer. In this case, the problem description is a simpler. That might make it easier to see what the problem is.
UPDATE -- header file added
#import <UIKit/UIKit.h>
#class MenuVC;
#protocol menuDelegateProtocol
typedef enum {
above,
below,
centered
} menuPosition;
- (void) didSelectItemFromMenu:(MenuVC *)menu atIndex:(NSUInteger) index;
#end
#interface MenuVC : UITableViewController {
NSArray *list;
float extendedHeight;
id<menuDelegateProtocol> menuDelegate;
}
#property (nonatomic, retain) NSArray *list;
#property (nonatomic, assign) id<menuDelegateProtocol> menuDelegate;
- (id) initWithFrame:(CGRect)frame style:(UITableViewStyle)style;
- (void) hide;
- (void) unhide;
- (void) assignOwnerView:(UIView*)oView andPosition:(menuPosition)position withTopView:(UIView*)topView;
#end
You didn't synthesized the properties.
Put:
#synthetize ownerView = ownerView_;
#synthetize topView = topView_;
#synthetize position = position_;
After "#implementation MenuVC".
I changed the debugger to GDB from LLDB. This seems to be a problem with LLDB. I'm not seeing this now.

Objective C - Get a class to return a value

I rarely ask questions, but this one is frustrating me as I can not find an answer anywhere!
I just need to call the function in GameChallenges.m and return the value to the view controller. GameChallenges.m will be called by different view controllers, thats why its separate. Please help!
I have a separate class file called GameChallenges.
This has a function/method in it:
in the .h
#class StatsViewController;
#interface GameChallenges : NSObject {
StatsViewController* statsController;
NSString* challengeTitle;
}
#property (nonatomic, retain) IBOutlet StatsViewController* statsController;
#property (assign) NSString* challengeTitle;
-(NSString*)checkChallenge:(int)challegeID;
#end
in the .m
#import "GameChallenges.h"
#import "StatsViewController.h"
#implementation GameChallenges
#synthesize challengeTitle,statsController;
-(NSString*)checkChallenge:(int)challegeID{
if(challegeID==1){
self.challengeTitle = #"Some Text.";
return challengeTitle;
}else if(challegeID==2){
self.challengeTitle = #"Some Other Text.";
return challengeTitle;
}
}
From a view controller called StatsViewController I am calling this method
in the .h
#class GameChallenges;
#interface StatsViewController : UIViewController {
UILabel* challengeIDDescText;
}
#property (nonatomic, retain) IBOutlet UILabel* challengeIDDescText;
#property (nonatomic, retain) IBOutlet GameChallenges* challenges;
#end
in the .m
[challenges checkChallenge:tempString];
challengeIDDescText.text = challenges.challengeTitle;
Your code is quite weird, I'd say this is what's happening:
-[GameChallenges checkChallenge] seems to expect an int and you call it with a variable called tempString that I guess is an NSString *. More likely than not, your method is ending without assigning challengeTitle and without a valid return value. Fix it with return nil as last statement and passing an int.
This kind of problems are very easy to solve using the debugger.
Also, have a look to Apple samples.
I'm beginner in objective-C, however, code in the GameChallenges.m looks weird to me... Wouldn't this be better?
challengeIDDescText.text = [challenges checkChallenge:challengeId];