I tried to create a singleton to set and get a string between different views:
globalVar.h:
#interface globalVar : NSObject
{
NSString *storeID;
}
+ (globalVar *)sharedInstance;
#property (nonatomic, copy) NSString *storeID;
#end
globalVar.m:
#import "globalVar.h"
#implementation globalVar
#synthesize storeID;
+ (globalVar *)sharedInstance
{
static globalVar *myInstance = nil;
if (nil == myInstance) {
myInstance = [[[self class] alloc] init];
}
return myInstance;
}
#end
Now how do I actually use the string? Say I want to set it to "asdf" in one view and load the "asdf" in another view.
To set it, do something like:
[globalVar sharedInstance].storeID = #"asdf";
And to use it:
NSString *myString = [globalVar sharedInstance].storeID;
First, you need to change how you create your instance. Do it like this:
+ (GlobalVar *)sharedInstance
{
static GlobalVar *myInstance;
#synchronized(self) {
if (nil == myInstance) {
myInstance = [[self alloc] init];
}
}
return myInstance;
}
You do not want to use [self class], because in this case self is already the globalVar class.
Second, you should name the class GlobalVar with a capital G.
Third, you will use it like this:
[GlobalVar sharedInstance].storeID = #"STORE123";
NSLog(#"store ID = %#", [GlobalVar sharedInstance].storeID);
Related
I have the following class so far:
#interface BRPerson : NSObject
#property (nonatomic) NSString *name;
#property (nonatomic) NSString *address;
-(instancetype)initWithName:(NSString*)name andAddress:(NSString*)address;
#implementation BRPerson
-(instancetype)initWithName:(NSString*)name andAddress:(NSString*)address{
self.name = name;
self.address = address;
return self;
}
#end
and my main is:
#import <Foundation/Foundation.h>
#import "BRPerson.h"
int main(int argc, const char * argv[]) {
#autoreleasepool {
NSString *filepath = [[NSBundle mainBundle] pathForResource:#"Directory"
ofType:#"txt"];
}
return 0;
}
The Directory.txt file is a plain file I created that is set up as:
name, address
name2, address2
name3, address3
I am trying to write a program that reads names and addresses and creates a new instance of the BRPerson class with the name being the instance name. Would it first have to be stored in NSDictionary (with name being the key and address the value)?
Any help is appreciated. Thank you in advance.
Following Objective-C's pattern for initializers, do the following:
-(id)initWithName:(NSString*)name andAddress:(NSString*)address{
self = [super init];
if (self) {
_name = name;
_address = address;
}
return self;
}
You might also consider providing a convenience factory method, like this:
+ (instancetype)personWithName:(NSString*)name andAddress:(NSString*)address {
return [[self alloc] initWithName:name andAddress:address];
}
With this, the loop that builds the instances will look like many parts of the SDK:
NSMutableArray *persons = [#[] mutableCopy];
while (/* more input */) {
NSString *name = // next name from input
NSString *address = // next address from input
BRPerson *person = [BRPerson personWithName:name andAddress:address];
[persons addObject];
}
// here, the array persons will contain several BRPerson instances
// as specified by the input
For example:
someObject.a.and.b.offset(5)
In objecitive-c, we know that a Class can have properties and methods, how to mix them to implement chainable syntax? How to design?
Have a look at this library: Underscore Library
Actually what it does it to return the same object you are operating on, so you can call more methods on the object (chaining them). Also block properties are used in order to obtain this syntax.
Here is an example from the website:
NSArray *tweets = Underscore.array(results)
// Let's make sure that we only operate on NSDictionaries, you never
// know with these APIs ;-)
.filter(Underscore.isDictionary)
// Remove all tweets that are in English
.reject(^BOOL (NSDictionary *tweet) {
return [tweet[#"iso_language_code"] isEqualToString:#"en"];
})
// Create a simple string representation for every tweet
.map(^NSString *(NSDictionary *tweet) {
NSString *name = tweet[#"from_user_name"];
NSString *text = tweet[#"text"];
return [NSString stringWithFormat:#"%#: %#", name, text];
})
.unwrap;
You might want to look at this SO-Thread aswell.
There is another library shown which implements this behaviour.
Here is my note. For example:
#class ClassB;
#interface ClassA : NSObject
//1. we define some the block properties
#property(nonatomic, readonly) ClassA *(^aaa)(BOOL enable);
#property(nonatomic, readonly) ClassA *(^bbb)(NSString* str);
#property(nonatomic, readonly) ClassB *(^ccc)(NSString* str);
#implement ClassA
//2. we implement these blocks, and remember the type of return value, it's important to chain next block
- (ClassA *(^)(BOOL))aaa
{
return ^(BOOL enable) {
//code
if (enable) {
NSLog(#"ClassA yes");
} else {
NSLog(#"ClassA no");
}
return self;
}
}
- (ClassA *(^)(NSString *))bbb
{
return ^(NSString *str)) {
//code
NSLog(#"%#", str);
return self;
}
}
// Here returns a instance which is kind of ClassB, then we can chain ClassB's block.
// See below .ccc(#"Objective-C").ddd(NO)
- (ClassB * (^)(NSString *))ccc
{
return ^(NSString *str) {
//code
NSLog(#"%#", str);
ClassB* b = [[ClassB alloc] initWithString:ccc];
return b;
}
}
//------------------------------------------
#interface ClassB : NSObject
#property(nonatomic, readonly) ClassB *(^ddd)(BOOL enable);
- (id)initWithString:(NSString *)str;
#implement ClassB
- (ClassB *(^)(BOOL))ddd
{
return ^(BOOL enable) {
//code
if (enable) {
NSLog(#"ClassB yes");
} else {
NSLog(#"ClassB no");
}
return self;
}
}
// At last, we can do it like this------------------------------------------
id a = [ClassA new];
a.aaa(YES).bbb(#"HelloWorld!").ccc(#"Objective-C").ddd(NO)
I'm trying to call a class method that is defined in an imported header file.
When I run the code below, I get this error in the View on the "double *result = ..." line:
+[CalculatorBrain runProgram:usingVariableValues:]: unrecognized selector sent to class 0x6908
** CalculatorViewController.m **
#import "CalculatorViewController.h"
#import "CalculatorBrain.h"
#interface CalculatorViewController()
#property (nonatomic, strong) CalculatorBrain *brain;
#property (nonatomic, strong) NSMutableDictionary *variableValues;
#end
#implementation CalculatorViewController
#synthesize brain = _brain;
#synthesize variableValues = _variableValues;
- (CalculatorBrain *)brain {
if (!_brain) _brain = [[CalculatorBrain alloc] init];
return _brain;
}
- (NSMutableDictionary *)variableValues {
if (!_variableValues) {
_variableValues = [[NSMutableDictionary alloc] init];
}
return _variableValues;
}
- (IBAction)enterPressed {
double *result = [CalculatorBrain runProgram:[self.brain program] usingVariableValues:[self variableValues]];
}
** CalculatorBrain.h **
#import <UIKit/UIKit.h>
#interface CalculatorBrain : NSObject
+ (double *)runProgram:(id)program usingVariableValues:(NSDictionary *)variableValues;
#property (readonly) id program;
#end
** CalculatorBrain.m **
#import "CalculatorBrain.h"
#interface CalculatorBrain()
#property (nonatomic, strong) NSMutableArray *programStack;
#end
#implementation CalculatorBrain
#synthesize programStack = _programStack;
... other code ...
+ (double)runProgram:(id)program :(NSDictionary *) usingVariableValues
{
NSLog(#"variableValues is %#", usingVariableValues);
NSMutableArray *stack;
if ([program isKindOfClass:[NSArray class]]) {
stack = [program mutableCopy];
NSLog(#"runProgram");
// if vars are passed in
if ([usingVariableValues isKindOfClass:[NSDictionary class]]) {
NSLog(#"vars are passed in: %#", usingVariableValues);
id obj;
int index = 0;
NSEnumerator *enumerator = [program objectEnumerator];
// for every obj in programStack
while ((obj = [enumerator nextObject])) {
id varVal = [usingVariableValues objectForKey:(obj)];
// test
NSLog(#"usingVariableValues objectForKey:(obj) is %#", varVal);
// if the obj is a variable key
if (!varVal) {
varVal = 0;
NSLog(#"varVal is false");
}
NSLog(#"Replacing object at index %# of stack with var %#", index, varVal);
// replace the variable with value from usingVariableValues OR 0
[stack replaceObjectAtIndex:(index) withObject:varVal];
index += 1;
}
}
}
return [self popOperandOffStack:stack];
}
+ (double *)runProgram:(id)program usingVariableValues:(NSDictionary *)variableValues;
Is defined as a class method, but you call it as an object method
double *result = [self.brain runProgram:[self.brain program] usingVariableValues:[self variableValues]];
To call it on the class do:
double *result = [[self.brain class] runProgram:[self.brain program] usingVariableValues:[self variableValues]];
Or
double *result = [CalculatorBrain runProgram:[self.brain program] usingVariableValues:[self variableValues]];
You changed your code, indicating, that the method is still not found. Did you implement it?
If it is implemented, then you might have to add the implementation file (aka .m) to the target in Xcode.
By the way,: probably you want your method to return a double not a double*, a pointer to a double.
your header has a signature:
+ (double *)runProgram:(id)program usingVariableValues:(NSDictionary *)variableValues;
While your implementation has
+ (double)runProgram:(id)program :(NSDictionary *) usingVariableValues
They are not identical:
The header promisses a pointer to a double to be returned. You don't want that.
They don't even have the same name
+runProgram:usingVariableValues: vs +runProgram::
singleton.h
#import <Foundation/Foundation.h>
#interface CrestronControllerValues : NSObject {
NSString* ipAddress;
NSString* portNumber;
NSString* phoneAddress;
NSString* cameleonVersion;
NSString* systemName;
NSString* iPID;
NSString* systemFeedBackName;
NSString* dJoinConnectedFB;
NSString* dJoinLow;
NSString* dJoinHigh;
NSString* aJoinLow;
NSString* aJoinHigh;
NSString* sJoinLow;
NSString* sJoinHigh;
NSMutableArray *currentPhonebookEntriesTelepresence;
NSMutableArray *currentPhonebookEntriesVideoChat;
NSMutableArray *currentPhonebookEntriesAudioChat;
}
#property (nonatomic, retain) NSString* ipAddress;
#property (nonatomic, retain) NSString* portNumber;
#property (nonatomic, retain) NSString* phoneAddress;
#property (nonatomic, retain) NSString* cameleonVersion;
#property (nonatomic, retain) NSMutableArray *currentPhonebookEntriesTelepresence;
#property (nonatomic, retain) NSMutableArray *currentPhonebookEntriesVideoChat;
#property (nonatomic, retain) NSMutableArray *currentPhonebookEntriesAudioChat;
#property (nonatomic, retain) NSString* systemName;
#property (nonatomic, retain) NSString* iPID;
#property (nonatomic, retain) NSString* systemFeedBackName;
#property (nonatomic, retain) NSString* dJoinConnectedFB;
#property (nonatomic, retain) NSString* dJoinLow;
#property (nonatomic, retain) NSString* dJoinHigh;
#property (nonatomic, retain) NSString* aJoinLow;
#property (nonatomic, retain) NSString* aJoinHigh;
#property (nonatomic, retain) NSString* sJoinLow;
#property (nonatomic, retain) NSString* sJoinHigh;
+ (id)sharedManager;
#end
i have my singleton.m:
static CrestronControllerValues *sharedMyManager= nil;
#implementation CrestronControllerValues
#synthesize ipAddress, portNumber ,systemName, iPID, systemFeedBackName, dJoinConnectedFB, dJoinLow, dJoinHigh, aJoinLow, aJoinHigh, sJoinLow, sJoinHigh, cameleonVersion, currentPhonebookEntriesAudioChat, currentPhonebookEntriesTelepresence, currentPhonebookEntriesVideoChat, phoneAddress;
+(CrestronControllerValues*)sharedManager
{
#synchronized(self) {
if(!sharedMyManager) {
sharedMyManager = [CrestronControllerValues alloc];
sharedMyManager = [sharedMyManager init];
}
}
}
+(id)alloc
{
#synchronized(self)
{
NSAssert(sharedMyManager == nil, #"Attempted to allocate a second instance of a singleton.");
sharedMyManager = [super alloc];
return sharedMyManager;
}
return nil;
}
-(id)init {
self = [super init];
if (self != nil) {
// initialize stuff here
self.ipAddress = #"10.8.40.64";
self.portNumber = 41794;
self.systemName = #"";
self.iPID = 3;
self.cameleonVersion = nil;
self.currentPhonebookEntriesAudioChat = [[NSMutableArray alloc]initWithObjects:nil];
self.currentPhonebookEntriesTelepresence = [[NSMutableArray alloc]initWithObjects:nil];
self.currentPhonebookEntriesVideoChat = [[NSMutableArray alloc]initWithObjects:nil];
self.phoneAddress = nil;
self.systemFeedBackName = #"";
self.dJoinConnectedFB = 5000;
self.dJoinLow = 1;
self.dJoinHigh = 1000;
self.aJoinLow = 1;
self.aJoinHigh = 1000;
self.sJoinLow = 1;
self.sJoinHigh = 1000;
}
return self;
}
return self;
}
-(void)setPhoneAddress:(NSString *)phoneaddress
{
#synchronized(self) {
if (phoneAddress != phoneaddress)
{
[phoneAddress release];
phoneAddress = [phoneaddress retain];
}
}
}
-(NSString*)getPhoneAddress
{
return phoneAddress;
}
-(void)setCurrentPhonebookEntriesAudioChat:(NSMutableArray *)entries
{
#synchronized(self) {
if (currentPhonebookEntriesAudioChat != entries)
{
[currentPhonebookEntriesAudioChat release];
currentPhonebookEntriesAudioChat = [entries retain];
}
}
}
-(NSMutableArray*)getCurrentPhonebookEntriesAudioChat
{
return currentPhonebookEntriesAudioChat;
}
-(void)setCurrentPhonebookEntriesTelepresence:(NSMutableArray *)entries
{
#synchronized(self) {
if (currentPhonebookEntriesTelepresence != entries)
{
[currentPhonebookEntriesTelepresence release];
currentPhonebookEntriesTelepresence = [entries retain];
}
}
}
-(NSMutableArray*)getCurrentPhonebookEntriesTelepresence
{
return currentPhonebookEntriesTelepresence;
}
-(void)setCurrentPhonebookEntriesVideoChat:(NSMutableArray *)entries
{
#synchronized(self) {
if (currentPhonebookEntriesVideoChat != entries)
{
[currentPhonebookEntriesVideoChat release];
currentPhonebookEntriesVideoChat = [entries retain];
}
}
}
-(NSMutableArray*)getCurrentPhonebookEntriesVideoChatLocal
{
return currentPhonebookEntriesVideoChat;
}
-(void)setCameleonVersion:(NSString *)cameleonversion
{
cameleonVersion = cameleonversion;
}
-(NSString*)getCameleonVersion
{
return cameleonVersion;
}
-(void)setIPaddress:(NSString *)ipaddress
{
ipAddress = ipaddress;
}
-(NSString*)getIPaddress
{
return ipAddress;
}
-(void)setPortNumber:(NSString *)portnumber
{
portNumber = portnumber;
}
-(NSString*)getPortNumber
{
return portNumber;
}
-(void)setSystemName:(NSString *)systemname
{
systemName = systemname;
}
-(NSString*)getSystemName
{
return systemName;
}
-(void)setIPID:(NSString *)ipid
{
iPID=ipid;
}
-(NSString*)getIpid
{
return iPID;
}
-(void)setSystemFeedBackName:(NSString *)systemfeedbackname
{
systemFeedBackName=systemfeedbackname;
}
-(NSString*)getSystemFeedBackName
{
return systemFeedBackName;
}
-(void)setDJoinConnectedFB:(NSString *)djoinconnectedfb
{
dJoinConnectedFB = djoinconnectedfb;
}
-(NSString*)getDJoinConnectedFB
{
return dJoinConnectedFB;
}
-(void)setDJoinLow:(NSString *)djoinlow
{
dJoinLow=djoinlow;
}
-(NSString*)getDJoinLow
{
return dJoinLow;
}
-(void)setDJoinHigh:(NSString *)djoinhigh
{
dJoinHigh = djoinhigh;
}
-(NSString*)getDJoinHigh
{
return dJoinHigh;
}
-(void)setAJoinLow:(NSString *)ajoinlow
{
aJoinLow = ajoinlow;
}
-(NSString*)getAJoinLow
{
return aJoinLow;
}
-(void)setAJoinHigh:(NSString *)ajoinhigh
{
aJoinHigh = ajoinhigh;
}
-(NSString*)getAJoinHigh
{
return aJoinHigh;
}
-(void)setSJoinLow:(NSString *)sjoinlow
{
sJoinLow = sjoinlow;
}
-(NSString*)getSJoinLow
{
return sJoinLow;
}
-(void)setSJoinHigh:(NSString *)sjoinhigh
{
sJoinHigh = sjoinhigh;
}
-(NSString*)getSJoinHigh
{
return sJoinHigh;
}
- (void)dealloc
{
[self.ipAddress release];
[self.iPID release];
[self.portNumber release];
[self.currentPhonebookEntriesVideoChat release];
[self.currentPhonebookEntriesTelepresence release];
[self.currentPhonebookEntriesAudioChat release];
[self.aJoinHigh release];
[self.aJoinLow release];
[self.cameleonVersion release];
[self.sJoinHigh release];
[self.sJoinLow release];
[self.dJoinHigh release];
[self.dJoinLow release];
[self.dJoinConnectedFB release];
[super dealloc];
}
#end
and then i use it in 3 classes total
in one i set values:
if i read values from the CCV (sharedobject) i get the correct values. but this is in the same class as they are set from
CCV = [CrestronControllerValues sharedManager];
CCV.currentPhonebookEntriesAudioChat = currentPhonebookEntriesAudioChat;
and another i read the values:
(these show/read as nil)
switch (viewOptions) {
case 1:
[self setTableArray:CCV.currentPhonebookEntriesVideoChat];
break;
case 2:
[self setTableArray:CCV.currentPhonebookEntriesVideoChat];
break;
case 3:
[self setTableArray:CCV.currentPhonebookEntriesTelepresence];
break;
case 4:
[self setTableArray:CCV.currentPhonebookEntriesAudioChat];
break;
default:
[self setTableArray:CCV.currentPhonebookEntriesVideoChat];
break;
}
but besides the class that i actually set the values in i do not get the filled array when i access it from another class
i have done NSLOG(#"%#", CCV) and from what i can see all three classes have the same pointer so the shared instance seems to be working
Here is a simplier singleton pattern, less code is more:
#implementation MySingleton
static MySingleton* _sharedMySingleton = nil;
+(MySingleton*)sharedMySingleton
{
#synchronized([MySingleton class])
{
if (!_sharedMySingleton)
_sharedSingleton = [[MySingleton alloc] init];
}
return _sharedMySingleton;
}
sharedMyManager has not been set at the time you are initializing the ivars.
In a init it is best practice to set the ivars directly, that is do not use setters such as created by #synthesize, the class is not completely established so calling methods on it is not a great idea.
A singleton is just a class like any other class with one exception, there is only one. Also all the extra methods to guarantee a singleton are really just noise that is best not present--but that is a matter of taste.
Consider:
sharedMyManager = [[super allocWithZone:NULL] init];
Rewrite it as:
id x = [super allocWithZone:NULL];
id y = [x init];
sharedMyManager = y;
When init is executed, the assignment to sharedMyManager hasn't been evaluated yet. Thus, sharedMyManager is nil and all your assignments are no-ops in your init method.
In your init method, you should always refer to your instance variables through self; either by directly assignment to them (which is a reference to self, really) or using the setter methods directly (i.e. self.foo = 442;).
(This is what #CocoaFu said, but clarified)
Looking at the code a little more closely, there are a ton of problems with it.
NSString properties should be copy, not retain.
you are leaking all of the currentPhonebookEntries* mutable arrays.
Getter methods should not have the prefix get*
there is no need to implement any of those getter/setter methods when using #synthesize (and you are actually creating two getter methods for each; one with and one without the get prefix).
the dealloc method should either directly release the instance variables or it should set the properties to nil; the [self.ivar release] is discouraged.
The code I showed above is merely illustrative. If your init still assigns through sharedMyManager, you didn't fix the problem.
so in the end all i can do is apologize. none of you had the code that you would have needed to see what was going on.
here is the array being saved (aboved was abridged (bad idea))
if ([phonebookEntriesAudioChat count] >=8) {
[CCV setCurrentPhonebookEntriesAudioChat:phonebookEntriesAudioChat];
[phonebookEntriesAudioChat removeAllObjects];
}
basically i was tring to add an item to the array from a socket return. getting one address up to 8 for each return/message. so i populated a temporary array (phonebookEntriesAudioChat) and added one to it for each message and once it got to 8 saved it to my singleton (CCV). but some how (and im still trying to figure this out) it would get to 8, be saved, temporary array cleared, then resaved the array (an empty one) to the singleton.
thanks for all the help and direction, i know i dont get points for my own answer if one of you wants some easy points just re answer with a simliar description as this and ill give u the check. otherwise im just going to vote up ur comments and mark this as the answer in a day or two.
I have the following objective C class. It is to store information on a film for a cinema style setting, Title venue ID etc. Whenever I try to create an object of this class:
Film film = [[Film alloc] init];
i get the following errors: variable-sizedobject may not be initialized, statically allocated instance of Objective-C class "Film", statically allocated instance of Objective-C class "Film".
I am pretty new to Objective C and probably am still stuck in a C# mindset, can anyone tell me what I'm doing wrong?
Thanks michael
code:
// Film.m
#import "Film.h"
static NSUInteger currentID = -1;
#implementation Film
#synthesize filmID, title, venueID;
-(id)init {
self = [super init];
if(self != nil) {
if (currentID == -1)
{
currentID = 1;
}
filmID = currentID;
currentID++;
title = [[NSString alloc] init];
venueID = 0;
}
return self;
}
-(void)dealloc {
[title release];
[super dealloc];
}
+(NSUInteger)getCurrentID {
return currentID;
}
+(void)setCurrentID:(NSUInteger)value {
if (currentID != value) {
currentID = value;
}
}
#end
// Film.h
#import <Foundation/Foundation.h>
#interface Film : NSObject {
NSUInteger filmID;
NSString *title;
NSUInteger venueID;
}
+ (NSUInteger)getCurrentID;
+ (void)setCurrentID:(NSUInteger)value;
#property (nonatomic) NSUInteger filmID;
#property (nonatomic, copy) NSString *title;
#property (nonatomic) NSUInteger venueID;
//Initializers
-(id)init;
#end
You need your variable that holds the reference to your object to be of a reference type. You do this by using an asterisk - see below:
Film *film = [[Film alloc] init];
Coming from Java I often think of the above as:
Film* film = [[Film alloc] init];
I tend to associate the 'reference' marker with the type. But hopefully someone more versed in C/C++/ObjC will tell me why this is wrong, and what the 'asterisk' is actually called in this context.