why does this code not work for referencing a const from a class? - iphone

why does this code not work for referencing a const from a class?
Background: I want to be able to reference a constant value from a class in a class variable type approach, as this is where it makes sense to source. Trying find the best way to effectively have the class offer up an exposed constant. I tried the below but it doesn't seem to work, I get "ERROR: property 'titleLablePrefix' not found on object of type 'DetailedAppointCell'"
#interface DetailedAppointCell : UITableViewCell {
}
extern NSString * const titleLablePrefix;
#end
#import "DetailedAppointCell.h"
#implementation DetailedAppointCell
NSString * const titleLablePrefix = #"TITLE: ";
#end
// usage from another class which imports
NSString *str = DetailedAppointCell.titleLablePrefix; // ERROR: property 'titleLablePrefix' not found on object of type 'DetailedAppointCell'

You can use directly as NSString *str = titleLablePrefix; if your external linkages are proper.

Objective C doesn't support class variables/constants, but it supports class methods. You can use the following solution:
#interface DetailedAppointCell : UITableViewCell {
}
+ (NSString*)titleLablePrefix;
#end
#import "DetailedAppointCell.h"
#implementation DetailedAppointCell
+ (NSString*)titleLablePrefix {
return #"TITLE: ";
}
#end
// usage from another class which imports
NSString *str = [DetailedAppointCell titleLablePrefix];
p.s. Dot syntax is used for instance properties. You can learn more about Objective C here: http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocObjectsClasses.html

Related

Access to custom Obj-C category from Swift

I'm trying to access this custom obj-C category in Swift file:
#import "NSString+UUID.h"
#implementation NSString (UUIDCategory)
+ (NSString*)stringWithUUID
{
CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault);
NSString *string = (NSString*)CFMakeCollectable(CFUUIDCreateString(kCFAllocatorDefault, uuid));
CFRelease(uuid);
return [string autorelease];
}
#end
So, I added :
#import "NSString+UUID.h"
in my bridging header, but can't find a solution to use it.
var string = NSString.stringWithUUID()
EDIT: the code seems to work now (the problem was I didn't include #import Foundation/Foundation.h in my bridging header before importing my categories.
This is a factory method and Swift will create an initializer for you automatically!
You should be able to use it like this:
let string = NSString(UUID:uuid)
Off topic, but you should really adopt ARC :]

Declaration/definition of variables locations in ObjectiveC?

Ever since starting to work on iOS apps and objective C I've been really puzzled by the different locations where one could be declaring and defining variables. On one hand we have the traditional C approach, on the other we have the new ObjectiveC directives that add OO on top of that. Could you folks helps me understand the best practice and situations where I'd want to use these locations for my variables and perhaps correct my present understanding?
Here's a sample class (.h and .m):
#import <Foundation/Foundation.h>
// 1) What do I declare here?
#interface SampleClass : NSObject
{
// 2) ivar declarations
// Pretty much never used?
}
// 3) class-specific method / property declarations
#end
and
#import "SampleClass.h"
// 4) what goes here?
#interface SampleClass()
// 5) private interface, can define private methods and properties here
#end
#implementation SampleClass
{
// 6) define ivars
}
// 7) define methods and synthesize properties from both public and private
// interfaces
#end
My understanding of 1 and 4 is that those are C-style file-based declarations and definitions that have no understanding whatsoever of the concept of class, and thus have to be used exactly how they would be used in C. I've seen them used for implementing static variable-based singletons before. Are there other convenient uses I'm missing?
My take from working with iOS is that ivars have been alost completely phased out outside of the #synthesize directive and thus can be mostly ignored. Is that the case?
Regarding 5: why would I ever want to declare methods in private interfaces? My private class methods seem to compile just fine without a declaration in the interface. Is it mostly for readability?
Thanks a bunch, folks!
I can understand your confusion. Especially since recent updates to Xcode and the new LLVM compiler changed the way ivars and properties can be declared.
Before "modern" Objective-C (in "old" Obj-C 2.0) you didn't have a lot of choices. Instance variables used to be declared in the header between the curly brackets { }:
// MyClass.h
#interface MyClass : NSObject {
int myVar;
}
#end
You were able to access these variables only in your implementation, but not from other classes. To do that, you had to declare accessor methods, that look something like this:
// MyClass.h
#interface MyClass : NSObject {
int myVar;
}
- (int)myVar;
- (void)setMyVar:(int)newVar;
#end
// MyClass.m
#implementation MyClass
- (int)myVar {
return myVar;
}
- (void)setMyVar:(int)newVar {
if (newVar != myVar) {
myVar = newVar;
}
}
#end
This way you were able to get and set this instance variable from other classes too, using the usual square bracket syntax to send messages (call methods):
// OtherClass.m
int v = [myClass myVar]; // assuming myClass is an object of type MyClass.
[myClass setMyVar:v+1];
Because manually declaring and implementing every accessor method was quite annoying, #property and #synthesize were introduced to automatically generate the accessor methods:
// MyClass.h
#interface MyClass : NSObject {
int myVar;
}
#property (nonatomic) int myVar;
#end
// MyClass.m
#implementation MyClass
#synthesize myVar;
#end
The result is much clearer and shorter code. The accessor methods will be implemented for you and you can still use the bracket syntax as before. But in addition, you can also use the dot syntax to access properties:
// OtherClass.m
int v = myClass.myVar; // assuming myClass is an object of type MyClass.
myClass.myVar = v+1;
Since Xcode 4.4 you don't have to declare an instance variable yourself anymore and you can skip #synthesize too. If you don't declare an ivar, the compiler will add it for you and it will also generate the accessor methods without you having to use #synthesize.
The default name for the automatically generated ivar is the name or your property starting with an underscore. You can change the generated ivar's name by using #synthesize myVar = iVarName;
// MyClass.h
#interface MyClass : NSObject
#property (nonatomic) int myVar;
#end
// MyClass.m
#implementation MyClass
#end
This will work exactly as the code above. For compatibility reasons you can still declare ivars in the header. But because the only reason why you would want to do that (and not declare a property) is to create a private variable, you can now do that in the implementation file as well and this is the preferred way.
An #interface block in the implementation file is actually an Extension and can be used to forward declare methods (not needed anymore) and to (re)declare properties. You could for instance declare a readonly property in your header.
#property (nonatomic, readonly) myReadOnlyVar;
and redeclare it in your implementation file as readwrite to be able to set it using the property syntax and not only via direct access to the ivar.
As for declaring variables completely outside of any #interface or #implementation block, yes those are plain C variables and work exactly the same.
First, read #DrummerB's answer. It a good overview of the whys and what you should generally do. With that in mind, to your specific questions:
#import <Foundation/Foundation.h>
// 1) What do I declare here?
No actual variable definitions go here (it's technically legal to do so if you know exactly what you're doing, but never do this). You may define several other kinds of things:
typdefs
enums
externs
Externs look like variable declarations, but they're just a promise to actually declare it somewhere else. In ObjC, they should only be used to declare constants, and generally only string constants. For instance:
extern NSString * const MYSomethingHappenedNotification;
You would then in your .m file declare the actual constant:
NSString * const MYSomethingHappenedNotification = #"MYSomethingHappenedNotification";
#interface SampleClass : NSObject
{
// 2) ivar declarations
// Pretty much never used?
}
As noted by DrummerB, this is legacy. Don't put anything here.
// 3) class-specific method / property declarations
#end
Yep.
#import "SampleClass.h"
// 4) what goes here?
External constants, as described above. Also file static variables can go here. These are the equivalent of class variables in other languages.
#interface SampleClass()
// 5) private interface, can define private methods and properties here
#end
Yep
#implementation SampleClass
{
// 6) define ivars
}
But very rarely. Almost always you should allow clang (Xcode) to create the variables for you. The exceptions are usually around non-ObjC ivars (like Core Foundation objects, and especially C++ objects if this is an ObjC++ class), or ivars that have weird storage semantics (like ivars that don't match with a property for some reason).
// 7) define methods and synthesize properties from both public and private
// interfaces
Generally you shouldn't #synthesize anymore. Clang (Xcode) will do it for you, and you should let it.
Over the last few years, things have gotten dramatically simpler. The side-effect is that there are now three different eras (Fragile ABI, Non-fragile ABI, Non-fragile ABI + auto-syntheisze). So when you see the older code, it can be a little confusing. Thus confusion arising from simplicity :D
I'm also pretty new, so hopefully I don't screw anything up.
1 & 4: C-style global variables: they have file wide scope. The difference between the two is that, since they're file wide, the first will be available to anyone importing the header while the second is not.
2: instance variables. Most instance variables are synthesized and retrieved/set through accessors using properties because it makes memory management nice and simple, as well as gives you easy-to-understand dot notation.
6: Implementation ivars are somewhat new. It's a good place to put private ivars, since you want to only expose what's needed in the public header, but subclasses don't inherit them AFAIK.
3 & 7: Public method and property declarations, then implementations.
5: Private interface. I always use private interfaces whenever I can to keep things clean and create a kind of black box effect. If they don't need to know about it, put it there. I also do it for readability, don't know if there are any other reasons.
This is an example of all kinds of variables declared in Objective-C. The variable name indicate its access.
File: Animal.h
#interface Animal : NSObject
{
NSObject *iProtected;
#package
NSObject *iPackage;
#private
NSObject *iPrivate;
#protected
NSObject *iProtected2; // default access. Only visible to subclasses.
#public
NSObject *iPublic;
}
#property (nonatomic,strong) NSObject *iPublic2;
#end
File: Animal.m
#import "Animal.h"
// Same behaviour for categories (x) than for class extensions ().
#interface Animal(){
#public
NSString *iNotVisible;
}
#property (nonatomic,strong) NSObject *iNotVisible2;
#end
#implementation Animal {
#public
NSString *iNotVisible3;
}
-(id) init {
self = [super init];
if (self){
iProtected = #"iProtected";
iPackage = #"iPackage";
iPrivate = #"iPrivate";
iProtected2 = #"iProtected2";
iPublic = #"iPublic";
_iPublic2 = #"iPublic2";
iNotVisible = #"iNotVisible";
_iNotVisible2 = #"iNotVisible2";
iNotVisible3 = #"iNotVisible3";
}
return self;
}
#end
Note that the iNotVisible variables are not visible from any other class. This is a visibility issue, so declaring them with #property or #public doesn't change it.
Inside a constructor it's good practice to access variables declared with #property using underscore instead self to avoid side effects.
Let's try to access the variables.
File: Cow.h
#import "Animal.h"
#interface Cow : Animal
#end
File: Cow.m
#import "Cow.h"
#include <objc/runtime.h>
#implementation Cow
-(id)init {
self=[super init];
if (self){
iProtected = #"iProtected";
iPackage = #"iPackage";
//iPrivate = #"iPrivate"; // compiler error: variable is private
iProtected2 = #"iProtected2";
iPublic = #"iPublic";
self.iPublic2 = #"iPublic2"; // using self because the backing ivar is private
//iNotVisible = #"iNotVisible"; // compiler error: undeclared identifier
//_iNotVisible2 = #"iNotVisible2"; // compiler error: undeclared identifier
//iNotVisible3 = #"iNotVisible3"; // compiler error: undeclared identifier
}
return self;
}
#end
We can still access the not visible variables using the runtime.
File: Cow.m (part 2)
#implementation Cow(blindAcess)
- (void) setIvar:(NSString*)name value:(id)value {
Ivar ivar = class_getInstanceVariable([self class], [name UTF8String]);
object_setIvar(self, ivar, value);
}
- (id) getIvar:(NSString*)name {
Ivar ivar = class_getInstanceVariable([self class], [name UTF8String]);
id thing = object_getIvar(self, ivar);
return thing;
}
-(void) blindAccess {
[self setIvar:#"iNotVisible" value:#"iMadeVisible"];
[self setIvar:#"_iNotVisible2" value:#"iMadeVisible2"];
[self setIvar:#"iNotVisible3" value:#"iMadeVisible3"];
NSLog(#"\n%# \n%# \n%#",
[self getIvar:#"iNotVisible"],
[self getIvar:#"_iNotVisible2"],
[self getIvar:#"iNotVisible3"]);
}
#end
Let's try to access the not visible variables.
File: main.m
#import "Cow.h"
#import <Foundation/Foundation.h>
int main(int argc, char *argv[]) {
#autoreleasepool {
Cow *cow = [Cow new];
[cow performSelector:#selector(blindAccess)];
}
}
This prints
iMadeVisible
iMadeVisible2
iMadeVisible3
Note that I was able to access the backing ivar _iNotVisible2 which is private to the subclass. In Objective-C all variables can be read or set, even those that are marked #private, no exceptions.
I didn't include associated objects or C variables as they are different birds. As for C variables, any variable defined outside #interface X{} or #implementation X{} is a C variable with file scope and static storage.
I didn't discuss memory management attributes, or readonly/readwrite, getter/setter attributes.

Iphone: Replace functions using reflection

I have a small function which I want to rewrite, so that function is valid for every class.
At the moment I have 10 of the same functions which all work same but every function is for another class.
I know, that I have to do it with reflections, but I am not so sure how to do it.
I already read this link:
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html
The functions I am talking about are:
-(NSCountedSet *)MissionGetReferecedNested:(id)modelObject
{
setOfObjects = [[NSCountedSet alloc]initWithArray:modelObject.MissionSectionList];
return setOfObjects;
}
-(NSCountedSet *)MissionGetSectionReferecedNested:(id)modelObject
{
setOfObjects = [[NSCountedSet alloc]initWithArray:modelObject.DamageAccountList];
return setOfObjects;
}
MissionSectionList and DamageAccountList are both NSMutableArrays from two different classes.
Is it possible to see if a class consists a NSMutableArray and if yes then it should call the .... modelObject.MyMutableArray?
You can use reflection like this:
- (NSCountedSet *)MissionGet:(id)modelObject
{
SEL propertySelector = NULL;
if ([modelObject respondsToSelector:#selector(MissionSectionList)]) {
propertySelector = #selector(MissionSectionList);
} else if ([modelObject respondsToSelector:#selector(DamageAccountList)]) {
propertySelector = #selector(DamageAccountList);
}
if (!propertySelector) {
[NSException raise:#"Invalid modelObject value" format:#"Model object %# does not contain any recognised selectors", modelObject];
}
return [[NSCountedSet alloc] initWithArray:[modelObject performSelector:propertySelector]];
}
But a more common technique among cocoa programmers would be:
- (NSCountedSet *)MissionGet:(id <MyCustomProtocol>)modelObject
{
return [[NSCountedSet alloc] initWithArray:[modelObject missionArray]];
}
Where you would accept any object which confirms to the protocol MyCustomProtocol. The protocol is defined in a header files somewhere, using:
#protocol MyCustomProtocol
#property (readonly) NSArray *missionArray;
#end
And then in each of your classes, declare it as implementing the protocol:
#interface MissionSectionListClass <MyCustomProtocol>
And add a method implementation:
#implementation MissionSectionListClass <MyCustomProtocol>
- (NSArray *)missionArray
{
return self.MissionSectionList;
}
#end
Using protocols is a bit more code, but it's the "right" way to go. It allows you to add support for new classes, without any change to your MissiongGet... method.
More info about protocols: http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocProtocols.html
EDIT : Cleared all my answer to this :
I think it's not possible to check if a class has a member variable of specified type. You can only check if a class has a specified method.
So, in this case it will be best if you make all your NSMutableArray list the same name, and then create a declared property for this list, and then do a respondsToSelector in your ...GetReferencedNested method.
So, for example, in all of your class create this property :
#property (nonatomic, retain) NSMutableArray * list;
and then in the ..MissionGetReferencedNested method :
if ([modelObject respondsToSelector:#selector(list)])
...
Correct me if i'm wrong...
In terms of style I'd also follow Abhi's suggestion.
But if you really want to inspect a class that you are stuck with and, for example build a NSCountedSet with the first NSMutableArray variable you can find, you could do it like this:
#import "Utilities.h"
#import <Foundation/Foundation.h>
#import <objc/objc-runtime.h>
#implementation Utilities
+ (NSCountedSet*)initCountedSetWithFirstArrayinObject:(id)someObject {
unsigned int c;
Ivar *ivar_arr = class_copyIvarList([someObject class], &c);
for (unsigned int i = 0; i < c; i++) {
if ([#"#\"NSMutableArray\"" isEqualToString:
[NSString stringWithCString:ivar_getTypeEncoding(ivar_arr[i]) encoding:NSUTF8StringEncoding]
]) {
return [[NSCountedSet alloc] initWithArray:object_getIvar(someObject, ivar_arr[i])];
}
}
return nil;
}
#end
Of course this has very limited real world use because it depends on you knowing that the first array will be the one you're interested in.
I think I have to go with the runtime type editing.(http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html)
The idea with the protocols was good but there I have to change a lot of things in the classes.(which is not possible/allowed) for me. My intension was only to change the functions so that I have only one function for all classes.
I think with the runtime type editing I can check what classes and attributes I have (?) Am I right?
Did somebody already work with runtime type editing?

"Static class in Objective C"

I need to know how I can make static method and static property like static method in java...
Thanks
Maxime
In Objective-C those are called class methods, and they are prefaced with a plus sign (+)
#interface MyClass : NSObject
+ (void)myClassMethod;
- (void)myInstanceMethod;
#end
Static methods in Objective C are known as class methods and start with a '+' sign, e.g.:
+ (void)aStaticMethod
{
// implementation here
}
Static variables are declared using the static keyword.
As others have pointed out, static class methods are prefixed with a plus (+) in declaration, like this:
#interface MyClass : NSObject
+ (void)myClassMethod;
#end
Objective-C does not make static properties quite as simple, and you need to jump through the following hoops:
declare a static variable
set up getter and setter methods for access to it
retain it's value
Complete example:
static NSString* _foo = nil;
#interface MyClass : NSObject
+ (NSString *)getFoo;
+ (void)setFoo;
#end
// implementation of getter and setter
+ (NSString *) getFoo {
return _foo;
}
+ (void) setFoo:(NSString*) value {
if(_foo != value) {
[_foo release];
_foo = [value retain];
}
}
// optionally, you can set the default value in the initialize method
+ (void) initialize {
if(!_foo) {
_foo = #"Default Foo";
}
}
I am not an Obj-C expert, but this seems to work well in my code. Correct me if anything here is off.
You cannot have static properties generated automatically but you can create a getter and a setter static methods manually.
+ (NSObject *) myStaticValue;
+ (void)setMyStaticValue:(NSObject *)value;
if you want to create static property means, you are creating a class variable. properties are only used for instance variable. If you creating a static means all objects share the same variable; Because it is class variable.
you can declare it in the implementation file of your class.
It should comes before the #implementation compiler directive. But that static variable can use only within its class. you can use it via your own getter-setter methods not by property.

Set a variable in a different class

I am trying to create an application were 2 classes share a variable. Just to keep the code looking a little bit cleaner I created a 3rd class. This "third class" sole job is to house this variable.
In class 3 I put a "get" and "set" method.
SharedURL.H (Class 3)
#interface SharedURL : NSObject {
NSString *theURL;
}
-(NSString *)getTheURL;
-(void)setTheURL:(NSString *)blah;
#property (readwrite, copy) NSString *theURL;
#end
Implementation:
#import "SharedURL.h"
#implementation SharedURL
#synthesize theURL;
-(NSString *)getTheURL;
{
return theURL;
}
-(void)setTheURL:(NSString *)blah;
{
theURL=blah;
}
#end
In classes 1 and 2:
I Import the class header
I set up the instance variable like so
SharedURL *XMLURL;
I define the property like so
#property (readwrite, assign) SharedURL *XMLURL;
Then in the implementation I set the set method like this
[XMLURL setTheURL:#"http://localhost:8888/xml/MyXMLFile.xml"];
However whenever I implement the fallowing code the getter method returns nil.
NSLog(#" the url is %#", [XMLURL getTheURL]);
How can I get this to actually save the variable that I imput and then return it. I'm looking at some sample code and i cannot find my error it looks to me like I am doing it perfectly fine I think I am overlooking something stupid.
If I understand this right you are calling class 3 from either class 1 or 2 (lets say 1) and set the URL then your go to class 2 and and only ask for the URL, right?
I think your problem is that you are calling something that is independent for each object. I think you can fix this by instead of saying -(NSString *)getTheURL and -(void)setTheURL you need to change it to +(NSString *)getTheURL and +(void)setTheURL (in both the .h and .m files) making it not variable dependent.