How do you past values between classes in objective-c - objective-c

How do you past values between classes in objective-c?

I'm going to assume the question involves a class, ClassOne, with an instance variable int integerOne, which you'd like to access from another class, ClassTwo. The best way to handle this is to create a property in ClassOne. In ClassOne.h:
#property (assign) int integerOne;
This declares a property (basically, two methods, - (int)integerOne, and - (void)setIntegerOne:(int)newInteger). Then, in ClassOne.m:
#synthesize integerOne;
This "synthesizes" the two methods for you. This is basically equivalent to:
- (int)integerOne
{
return integerOne;
}
- (void)setIntegerOne:(int)newInteger
{
integerOne = newInteger;
}
At this point, you can now call these methods from ClassTwo. In ClassTwo.m:
#import "ClassOne.h"
//Importing ClassOne.h will tell the compiler about the methods you declared, preventing warnings at compilation
- (void)someMethodRequiringTheInteger
{
//First, we'll create an example ClassOne instance
ClassOne* exampleObject = [[ClassOne alloc] init];
//Now, using our newly written property, we can access integerOne.
NSLog(#"Here's integerOne: %i",[exampleObject integerOne]);
//We can even change it.
[exampleObject setIntegerOne:5];
NSLog(#"Here's our changed value: %i",[exampleObject integerOne]);
}
It sounds like you should walk through a few tutorials to learn these Objective-C concepts. I suggest these.

Related

extend class in objective-c with variable based property [duplicate]

This question already has answers here:
Objective-C: Property / instance variable in category
(6 answers)
Closed 2 years ago.
I've got a form implementation in objective-c and I'd like to extend my widgets (NSButton, NSTextField, etc..) to contain additional string representing their unique identifier string to be used after submit event occur, which trigger generation of json contain all widget id/value pairs.
I've tried using categories to extend NSControl which is the common parent of all those widgets in the following way.
NSControl+formItemSupport.h
-------------------------------
#interface NSControl (formItemSupport)
#property NSString * formItemId;
#end
NSControl+formItemSupport.m
-------------------------------
#implementation NSControl (formItemSupport)
-(NSString *)formItemId {
return self.formItemId;
}
-(void)setFormItemId:(NSString *)formItemId {
self.formItemId = formItemId;
}
in the form.m file I import from NSControl+formItemSupport.m but when I try to set this field in NSButton : NSControl object. However, when I try to set the property formItemId, I get into infinite loop. Perhaps there's another way for extending objc class with variable based property without using inheritance ?
you can
#synthesize formItemId = _formItemId;
//synthesize needs local declaration of _formItemId;
#implementation ExtraWurst {
NSString *_formItemId;
}
but this is done behind the scene for you from Xcode without #synthesize.
Sometime it is still easier to define the use of an internal variable for a property in this way.
apart from that you can and have to change your setter and getter methods in the following way.
-(NSString *)formItemId {
return _formItemId;
}
-(void)setFormItemId:(NSString *)formItemId {
_formItemId = formItemId;
}
this will prevent you from ending up in a loop.
Why?
Because self.formItemId = refers to -(void)setFormItemId:
So you would call the setter inside the setter that will set with the same again and again aka an endless loop.
You can take care of the getter the same way as shown above.
Where to use self.yourProperty then?
You can use self.formItemId anywhere in the class but not inside getter and setter of formItemId.
Correctly mentioned, Instance variables may not be placed in categories.
Meaning if you need such you have to subclass UIControl but that breaks the inheritance of your used UIControls. You would have to subclass all your SpecialUIControls you are using later.
Another solution, you could define a constant in your implementation and go with objective-C runtime functions and associate this constant yourself. Beware because you transform the ObjectModel for all UIControl classes then..
#import "NSControl+formItemSupport.h"
#import <objc/runtime.h>
#implementation UIControl (formItemSupport)
NSString const *key = #"formItemSupport.forItemKey";
-(void)setFormItemId:(NSString *)formItemId {
objc_setAssociatedObject(self, &key, formItemId, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(NSString *)formItemId {
return objc_getAssociatedObject(self, &key);
}
#end
still, its much easier and safer and flexible to subclass your own UIControl instead to extent all subclasses inherited from UIControl.
Why is subclassing easier here?
As you mentioned you want to json later on with the given formItemId per Control you can make use of an archiver / unarchiver design pattern of your subclasses which are nice to jsonify later.

Accessing an Objective C ivar without a #property or a getter method?

Is there any way to access an instance variable on an Objective C object without using #property or a getter method?
I've got a class here that needs to be able to "merge" itself with another object of the same class. The problem is that I need to be able to access the ivars of the "other" object in order to merge it with the current object, but I don't want to declare those ivars as a property or implement some other getter method, because I don't want anybody thinking that they should be fiddling with those ivars in any way.
Once again, I don't need to access the ivars from any other class other then that class itself. As an example, here's what I'm looking to do:
#interface MySillyObject : NSObject
{
double _someCounter;
}
#implementation
+ (MySillyObject *)sillyObjectWithCounter:(double)counter
{
return [[[MySillyObject alloc] initWithCounter:counter] autorelease];
}
- (id)initWithCounter:(double)counter
{
if (self = [super init]) {
_someCounter = counter;
}
}
- (MySillyObject *)mergeWithOtherObject:(MySillyObject *)otherObject
{
// What do I do here?
// I need to return _someCounter + otherObject's _someCounter...
return [MySillyObject sillyObjectWithCounter:???];
}
You can actually sidestep ivar access policy for pretty much any Cocoa object with valueForKey:; if you know the name of the property or the ivar, KVC will root around in the class's internals and retrieve the value for you.
But in this case, you don't even need to do that. Since otherObject is a member of the same class, you can access it directly: otherObject->_someCounter. You can in fact access it within the same class for any level of visibility, even if you declare it in the recommended "very private" #implementation block.

Setting default values for inherited property without using accessor

I always see people debating whether or not to use a property's setter in the -init method. My problem is how to create a default value in a subclass for an inherited property. Say we have a class called NSLawyer -- a framework class, that I can't change -- with an interface that looks like this:
#interface NSLawyer : NSObject {
#private
NSUInteger _numberOfClients;
}
#property (nonatomic, assign) NSUInteger numberOfClients;
#end
And an implementation that looks like this:
#implementation NSLawyer
- (instancetype)init
{
self = [super init];
if (self) {
_numberOfClients = 0;
}
return self;
}
#end
Now let's say I want to extend NSLawyer. My subclass will be called SeniorPartner. And since a senior partner should have lots of clients, when SeniorPartner gets initialized, I don't want the instance to start with 0; I want it to have 10. Here's SeniorPartner.m:
#implementation SeniorPartner
- (instancetype)init
{
self = [super init];
if (self) {
// Attempting to set the ivar directly will result in the compiler saying,
// "Instance variable _numberOfClients is private."
// _numberOfClients = 10; <- Can't do this.
// Thus, the only way to set it is with the mutator:
self.numberOfClients = 10;
// Or: [self setNumberOfClients:10];
}
return self;
}
#end
So what's a Objective-C newcomer to do? Well, I mean, there's only one thing I can do, and that's set the property. Unless there's something I'm missing. Any ideas, suggestions, tips, or tricks?
You should do exactly has you have; call the accessor. The declaring class typically avoids calling its own accessors in init to avoid accidentally calling an overridden accessor in a subclass that might rely on the consistency of data you haven't initialized yet. Your superclass on the other hand should be completely consistent by the time the subclass's init is run, so there is no problem using superclass accessors at that time.
Consider the common and general case: you want to set your transform in a UIView subclass. How would you solve that other than call setTransform:? Subclassing non-Apple code is no different.
Make it #protected. It is very rare to make an ivar or property private these days. Private ivars and/or properties are better declared in the implementation. For that matter #protected ivars/properties are rarely seen in Objective-C but perfectly fine.
Using a setter either as a method or with dot notation is just wrong (yes it works but is really bad form), if you want use setters/getters declare a property.

How Exactly To Use a Global Variable?

I'm a beginner with Objective-C, and am trying to use a global variable. I know that this question has been asked a hundred times, but none of the answers have worked for me. I'm trying to declare a BOOL variable in one class, and check its value in another. This is what I'm working with:
SController.h:
#interface SController : UIViewController {
BOOL leftSide;
BOOL rightSide;
}
SController.m:
- (void)viewDidLoad {
leftSide = YES;
rightSide = YES;
}
Now, for the class I'm trying to access the value of the BOOLs in:
#import "SController.h"
#interface VViewController : UIViewController
{
}
And VViewController's .m:
- (void)viewDidLoad {
// See what the BOOL values from SController are.
}
What I've tried:
Going off of the previous related questions on here, I've tried putting "extern" in front of the BOOLs declaration in SController.h, but that did not work. I tried simply importing the SControllers header file into VViewController, and that did not work either. I'm very new to Objective-C and programming in general, so I'm having a tough time wrapping my head around basic concepts like this. I understand the potential issues surrounding using a global variable, but this program is very small and for personal use. If anyone can show me what to change to make this happen, that would be great.
Like the others said, don't use a global variable for that (and most other) purpose.
You created iVars and in order to access them, you need to expose them to other objects.
You generally do that by defining #properties in your SControllers header file. When doing that, you don't need to create iVars yourself, they are created implicitly. And methods to access the iVars are also automagically created (getters and setters).
Your SControllers header could look something like this:
#interface SController: UIViewController
//no need to declare the iVars here, they are created by the #property definitions
#property (nonatomic, assign) BOOL leftSide;
#property (nonatomic, assign) BOOL rightSide;
#end
In your other viewController you need a reference to the instance of SController you previously created and want to "talk" to (it is important you understand this), then you could access the instance variable through the generated getter/setter methods like so:
//this is "dot notation", the first line would be equivalent
//to writing: [sControllerInstance setLeftSide: YES]
sControllerInstance.leftSide = YES;
BOOL valueRightSide = sControllerInstance.rightSide;
Please read up on: objective-c properties, getters/setters and dot notation.
You will find plenty of information on google and SO
I know this is not the answer you're looking for, but try rethinking your app. Global variables is not the best way to go for Object oriented programming.
Create GlobalVariable.h header class file and defined following externs as follows
extern NSString * googleURL;
And then in your implementation GlobalVariable.m file
#import "GlobalVariable.h"
NSString * googleURL = #"www.google.co.uk";
And then import the class wherever you want to use it across.
By default the variables (as defined in your code) are protected. You can add the #public keyword before the 2 variables to make them public but it's not recommended. Generally you want to expose those as properties using the #property keyword
Example:
#interface SController : UIViewController {
#public
BOOL leftSide;
BOOL rightSide;
#protected
//other protected variables here
}

Custom property attributes in Objective-c

Can custom property attributes be created in Objective-C just like in VB.NET? For example, in VB.NET you can create the "Browsable" attribute and read it at runtime to determine whether you should display a property or not.
Public Class Employee
<Browsable(True)> _
Public Property Property1() As String
Get
End Get
Set(ByVal Value As String)
End Set
End Property
<Browsable(False)> _
Public Property Property2() As String
Get
End Get
Set(ByVal Value As String)
End Set
End Property
End Class
I would like to do the same in Objective-C, even if it is a fixed attribute that can only be set at compile time and cannot be changed at all.
What I'm trying to do is to add an attribute to properties of my class to determine whether the properties should be serialized or not.
I know the standard Objective-C attributes (readonly, nonatomic, etc.), but those don't help me... unless you have a creative way of using them. I also looked into using C attributes with the __attribute__(("Insert attribute here")) keyword, but C has specific attributes that serve specific purposes, and I'm not even sure you can read them at runtime. If I missed one that can help me, let me know.
I tried using typdef. For example:
typdef int serializableInt;
serializableInt myInt;
and use the property_getAttributes() Objective-C runtime function, but all it tells me is that myInt is an int. I guess typedef is pretty much like a macro in this case... unless I can create a variable of type serializableInt at runtime. Anyhow, here's Apple's documentation on the values you get from property_getAttributes().
The other requirement is that this attribute has to work with NSObject sub-classes as well as primitive data types. I thought about the idea of adding to the class a black lists or white lists as an ivar that would tell me which properties to skip or serialize, which is basically the same idea. I'm just trying to move that black/white list to attributes so it's easy to understand when you see the header file of a class, it's consistent across any class I create and it's less error prone.
Also, this is something to consider. I don't really need the attribue to have a value (TRUE or FALSE; 1, 2, 3; or whatever) because the attribute itself is the value. If the attribute exists, then serialize; otherwise, skip.
Any help is appreciated. If you know for sure that this is not possible on Objective-C, then let me know. Thanks.
If you want to add attribute to property, class, method or ivar, you can try to use github.com/libObjCAttr. It's really easy to use, add it via cocoapods, and then you can add attribute like that:
#interface Foo
RF_ATTRIBUTE(YourAttributeClass, property1 = value1)
#property id bar;
#end
And in the code:
YourAttributeClass *attribute = [NSDate RF_attributeForProperty:#"bar" withAttributeType:[YourAttributeClass class]];
// Do whatever you want with attribute, nil if no attribute with specified class
NSLog(#"%#", attribute.property1)
unless i've missed your point…
i'd recommend declaring a protocol. then using instances of objc objects as variables in your objc classes which adopt the protocol.
#interface MONProtocol
- (BOOL)isSerializable;
- (BOOL)isBrowsable;
/* ... */
#end
#interface MONInteger : NSObject <MONProtocol>
{
int value;
}
- (id)initWithInt:(int)anInt;
#end
#interface MONIntegerWithDynamicProperties : NSObject <MONProtocol>
{
int value;
BOOL isSerializable;
BOOL isBrowsable;
}
- (id)initWithInt:(int)anInt isSerializable:(BOOL)isSerializable isBrowsable:(BOOL)isBrowsable;
#end
// finally, a usage
#interface MONObjectWithProperties : NSObject
{
MONInteger * ivarOne;
MONIntegerWithDynamicProperties * ivarTwo;
}
#end
if you want to share some implementation, then just subclass NSObject and extend the base class.
you'd then have a few variants to write for the types/structures you want to represent.
The deficiency with the other answers I've seen so far is that they are implemented as instance methods, i.e., you need to have an instance already before you can query this metadata. There are probably edge cases where that's appropriate, but metadata about classes should be implemented as class methods, just as Apple does, e.g.:
+ (BOOL)automaticallyNotifiesObserversForKey:(NSString*)key { }
We could imagine our own along similar lines:
+ (BOOL)keyIsBrowsable:(NSString*)key { }
or
+ (NSArray*)serializableProperties { }
Let's imagine our class is called FOOBar, and we want to know whether the baz key is browsable. Without having to create a FOOBar we can just say:
if ([FOOBar keyIsBrowsable:#"baz"]} { ... }
You can do pretty much anything with this technique that can be done with custom attributes. (Except for things like the Serializable attribute which require cooperation from the compiler, IIRC.) The nice thing about custom attributes, though, is that it is easy to distinguish at a glance what is metadata and what is intrinsic to that class's actual functionality, but I think that's a minor gain.
(Of course, you may have to check for the existence of the keyIsBrowsable: selector, just as you'd have to check for the existence of a specific custom attribute. Again, custom attributes have a slight leg up here, since we can tell the .NET runtime to give them all to us.)
I've come across a similar issue whe serializing objects. My solution is to add a #property (nonatomic, readonly) NSArray *serialProperties; which has a custom getter that returns the names (as NSString*) of the properties of this (sub-)class that should be serialized.
For example:
- (NSArray *)serialProperties {
return #[#"id", #"lastModified", #"version", #"uid"];
}
Or in a subclass:
- (NSArray *)serialProperties {
NSMutableArray *sp = [super serialProperties].mutableCopy;
[sp addObject:#"visibleName"];
return sp;
}
You can then easily get all properties and their values via [self dictionaryWithValuesForKeys:self.serialProperties].
You can't add custom properties other than what sdk has provided..
.
But there is a work around to attain your objective...
#interface classTest:NSObject
#property(strong,nonatomic)NSString *firstName;
#property(strong,nonatomic)NSString *lastName;
#property(strong,nonatomic)NSMutableDictionary *metaData;
#end
#implementation classTest
- (id) init
{
self = [super init];
//Add meta data
metaData=[[NSmutableDictionary alloc]init];
//
if( !self ) return nil;
return self;
}
#end
so use the dictionary to add and retrieve meta data...
i hope it helps....