I want to create a class in objective-c with already stored data, so that for accessing the data I don't want to instantiate the class. how can I do it?
You can use a singleton or you can use a class made only of class methods and giving you access to static data.
Here is a basic singleton implementation in ObjC:
#interface MySingleton : NSObject
{
}
+ (MySingleton *)sharedSingleton;
#property(nonatomic) int prop;
-(void)method;
#end
#implementation MySingleton
#synthesize prop;
+ (MySingleton *)sharedSingleton
{
static MySingleton *sharedSingleton;
#synchronized(self)
{
if (!sharedSingleton)
sharedSingleton = [[MySingleton alloc] init];
return sharedSingleton;
}
}
-(void)method {
}
#end
and you use it like this:
int a = [MySingleton sharedSingleton].prop
[[MySingleton sharedSingleton] method];
The class method based class would be:
#interface MyGlobalClass : NSObject
+ (int)data;
#end
#implementation MySingleton
static int data = 0;
+ (int)data
{
return data;
}
+ (void)setData:(int)d
{
data = d;
}
#end
Related
So I have a singleton like this:
#import "SCAppManager.h"
#implementation SCAppManager
+ (instancetype)sharedApplication {
static SCAppManager *sharedApplication = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
if (sharedApplication == nil) {
sharedApplication = [[SCAppManager alloc] init];
}
});
return sharedApplication;
}
+ (void)test {
NSLog(#"test");
}
#end
And its interface is this:
#import <Foundation/Foundation.h>
#interface SCAppManager : NSObject
+ (instancetype)sharedApplication;
+ (void)test;
#end
But when a try to use the [[SCAppManager sharedApplication] test]; in a ViewController, I get the error:
No visible #interface for 'SCAppManager' declares the selector 'test'
I've look for all the possibilities and I already imported my singleton class correclty and declared my method in the public interface. I also searched for some answers here, but all the fix didnt work for me.
Has anyone faced this problem?
Thanks!
The error is coming because you declared test as a class method not as instance method. You can call the class method by it's class name, so you should call it like:
[SCAppManager test];
Or change the method to instance method:
.h
#interface SCAppManager : NSObject
+ (instancetype)sharedApplication;
- (void)test;
#end
.m
#implementation SCAppManager
// Other methods
- (void)test
{
NSLog(#"test");
}
#end
And use it like:
[[SCAppManager sharedApplication] test];
// Marketplace.h
#import <Foundation/Foundation.h>
#import "Item.h"
#interface Marketplace : NSObject
+ (void)addItemToMarketplace:(Item *)newItem; // METHOD IN QUESTION
#end
// Marketplace.m
#import "Marketplace.h"
#interface Marketplace()
#property (strong, nonatomic) NSMutableArray *listOfItems;
#end
#implementation Marketplace
+ (void)addItemToMarketplace:(Item *)newItem // METHOD IN QUESTION
{
[self.listOfItems addObject:newItem]; // Raises 3 errors
}
#end
I have declared a class method addItemToMarketplace that takes in an object of type Item and adds this Item to the listOfItems property that I have declared in the interface of the implementation file (I am not sure that I want other classes to fiddle with this property). I have used this method in another class as such [Marketplace addItemToMarketplace:newItem]. I am not sure how to handle the three errors that are raised when I write [self.listOfItems addObject:newItem].
The 3 errors are as follows:
1. Member reference type 'struct objc_class *' is a pointer; maybe you meant to use '->'?
2. Definition of 'struct objc_class' must be imported from module 'ObjectiveC.runtime' before it is required
3. No member named 'listOfItems' in 'struct objc_class'
Making the change proposed in #1, which changes self.listOfItems to self->listOfItems, raises the error "Member reference base type 'Class' is not a structure or union"
Any help would be appreciated.
// NEW CHANGES!
After making some changes and following some suggestions I found on other sites, here's what I have so far:
// Marketplace.h
#import <Foundation/Foundation.h>
#import "Item.h"
#interface Marketplace : NSObject {}
+ (Marketplace *)sharedMarket;
- (void)addItemToMarketplace:(Item *)newItem;
#end
// Marketplace.m
#import "Marketplace.h"
#interface Marketplace()
#property (strong, nonatomic)NSMutableArray *listOfItems;
#end
static Marketplace *sharedMarketplace = nil;
#implementation Marketplace
+ (Marketplace *)sharedMarket
{
if (sharedMarketplace == nil) {
sharedMarketplace = [[super allocWithZone:NULL] init];
}
return sharedMarketplace;
}
- (void)addItemToMarketplace:(Item *)newItem
{
[self.listOfItems addObject:newItem];
}
- (id)init
{
if ( (self = [super init]) ) {
}
return self;
}
+ (id)allocWithZone:(NSZone *)zone {
return [self sharedMarket];
}
- (id)copyWithZone:(NSZone *)zone {
return self;
}
#end
Questions, comments, concerns?
Only the instance methods can operate on instance data. So you need either an instance or change the data to static too:
#interface Marketplace()
#end
static NSMutableArray *listOfItems; // static is implied, so not really necessary
#implementation Marketplace
+ (void)addItemToMarketplace:(Item *)newItem {
if (!listOfItems) listOfItems = [NSMutableArray array];
[listOfItems addObject:newItem];
}
#end
Note that there's no thread safety here.
The + prefix defines a class method. Within that method self refers to the class itself which is almost certainly not what you intend. The class does not have a listOfItems as that is a property available on each instance of the class.
It is not clear what you are attempting to do here. If you are coming from a C/C++ background perhaps you have assumed a different behavior for this method. Are you trying to add an item to a list managed by a particular instance of this class or to a list shared across all instances?
If you just have one instance of marketplace in your app consider using a singleton..
You then might add items to the single marketplace like this:
[[Marketplace theMarketplace] addItem:<*item*>]
Here's one way to set this up:
#interface Marketplace : NSObject
#property ( nonatomic ) NSArray * items ;
#end
#implementation Marketplace
static Marketplace * __marketplace ;
+(void)load
{
__marketplace = [ Marketplace new ] ;
}
+(instancetype)theMarketplace
{
return __marketplace ;
}
-(void)addItem:(Item*)item
{
self.items = [ ( self.items ?: #[] ) arrayByAddingObject:item ] ;
}
#end
(or in Swift)
class Marketplace
{
struct Static
{
static let marketplace = Marketplace()
}
var items:Array<Item> = [] ;
class func get() -> Marketplace { return Static.marketplace }
func addItem( item: Item ) { self.items += item }
}
Does anyone know if there is a way to set a property like a string in the User Defined Runtime Atributes sections of Interface Builder without creating a subclass of said component? For example, I want to store a metadata value for each component in my interface that I use later. I just don't want to have to create a subclass or each component to add a metadata property.
This is one approach I came up with. Opinions?
#import <UIKit/UIKit.h>
#import <objc/runtime.h>
#interface UIControl(MetaData)
#property (nonatomic, retain) id entityProperty;
#end
#implementation UIControl(MetaData)
static char const * const EntityPropertyKey = "EntityProperty";
#dynamic entityProperty;
- (id)entityProperty {
return objc_getAssociatedObject(self, EntityPropertyKey);
}
- (void)setEntityProperty:(id)newEntityProperty {
objc_setAssociatedObject(self, EntityPropertyKey, newEntityProperty, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
#end
...
if (textField.entityProperty)
[managedObject setValue: textField.text forKey:textField.entityProperty];
You could keep an NSDictionary somewhere, perhaps in a singleton object that has methods for issuing unique ids for objects and storing metadata by the id keys in the dictionary. The UI objects have a tag property that you can use, if your ids are just incremented integers. Then the dictionary keys would just be NSNumbers for those unique integers.
Like this:
#import <Foundation/Foundation.h>
#interface ACLMetadataManager : NSArray
+(ACLMetadataManager*) sharedMetadataManager;
-(NSUInteger) getUniqueId;
-(void) setObject: (id) object forId:(NSUInteger) theId;
-(id) objectForId:(NSUInteger) theId;
#end
And:
#import "ACLMetadataManager.h"
#implementation ACLMetadataManager { // Private variables
NSMutableDictionary *_metadata;
NSUInteger _ids;
}
- (id)init {
self = [super init];
if (self) {
_metadata = [[NSMutableDictionary alloc] init];
}
return self;
}
+(ACLMetadataManager*) sharedMetadataManager { // Singleton getter
static ACLMetadataManager *instance;
if (instance != nil) {
return instance;
}
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_4_0
static dispatch_once_t oneTimeThread;
dispatch_once(&oneTimeThread, ^(void) {
instance = [[ACLMetadataManager alloc] init];
});
#else
#synchronized(self) {
instance = [[ACLMetadataManager alloc] init];
}
#endif
return instance;
}
-(NSUInteger) getUniqueId { // Increment unique id when getter is called.
return ++_ids; // Start from 1 because tag is 0 by default.
}
-(void) setObject: (id) object forId:(NSUInteger) theId {
[_metadata setObject:object forKey:[NSNumber numberWithInteger:theId]];
}
-(id) objectForId:(NSUInteger) theId {
return [_metadata objectForKey:[NSNumber numberWithInteger:theId]];
}
// Override some methods to ensure singleton stays instantiated.
- (id) retain {
return self;
}
- (oneway void) release {
// Does nothing here.
}
- (id) autorelease {
return self;
}
- (NSUInteger) retainCount {
return INT32_MAX;
}
#end
Usage:
ACLMetadataManager *metadataManager = [ACLMetadataManager sharedMetadataManager];
myControl.tag = [metadataManager getUniqueId];
[metadataManager setObject:myMetadata forId:myControl.tag];
Is there a way to use something like
if (carRecord.status == CarRecord.statusRepaired) { // using a class constant
// ...
}
such as in a car repair shop, the carRecord object's state status is checked against the CarRecord class's constant. In Objective-C, is there such a way?
You would typically do this with an enum. For example:
//=== CarRecord.h:
typedef enum CarRecordStatus {
CarRecordStatusBroken = 0,
CarRecordStatusRepaired
} CarRecordStatus;
#interface CarRecord (NSObject) {
CarRecordStatus _status;
}
#property (nonatomic, assign) CarRecordStatus status;
#end
//=== CarRecord.m:
#implementation CarRecord
#synthesize status=_status;
- (void)someMethod {
if (self.status == CarRecordStatusRepaired) {
//...
}
}
#end
Here is how would you define it in .h file :
typedef enum CarRecordStatus {
CarRecordStatusBroken = 0,
CarRecordStatusRepaired,
} CarRecordStatus;
#interface MyClassName : NSObject
..interfacebody..
#end
Use it inside MyClassName or any other just import it that's it.
//MainClass.m
#interface InnerClass : NSObject{
}
#end
#implementation InnerClass
-(void)run{
while(isActive){//want to access this variable which defined in MainClass
//do something
}
}
#end
#interface MainClass : NSObject{
BOOL isActive;
}
#end
#implementation MainClass
#end
I have MainClass and it has an inner class (InnerClass). I want to access the boolean type variable (isActive) defined in MainClass class from the inner class. What I am trying to do is that the inner class will run on a separate thread and will keep checking the isActive variable on the main class and if isActive is false then it will stop running the new thread.. Thanks in advance...
Objective-C doesn't have inner classes. Consider making isActive a property of MainClass, give InnerClass a pointer to an instance of MainClass, and let InnerClass simply access the property.
Objective-C doesn't have inner classes as a language construct, however you can do all sorts of tricky things like hiding both the interface and implementation of the "innerclass" in the .m file of the MainClass and having a hidden factory method (not in the interface) on the MainClass that creates the 'innerclass' with a bool* property assigned to &isActive of the main class.
MainClass.h
#interface MainClass : NSObject{
BOOL isActive;
}
#end
MainClass.m
#interface InnerClass : NSObject{
BOOL* isActive;
}
-(id)initWithActive:(BOOL*)isAct){
if (self = [super init]) {
isActive = isAct;
}
return self;
}
#end
#implementation InnerClass
-(void)run{
while(*isActive){//want to access this variable which defined in MainClass
//do something
}
}
#end
#implementation MainClass
//Can use [self newInnerClass] to create a new instance of the innerclass
-(id)newInnerClass{
return [[[InnerClass alloc] initWithActive:&isActive] autorelease];
}
#end