Objective-C: Assigning a value to a static remains nil? - objective-c

I have the following defined in a header file:
static NSArray *knownPrinters = nil;
In a test case:
knownPrinters = [NSArray new];
I have a breakpoint before and after that single line and the value of knownPrinters remains nil despite being assigned. There is only the main thread and I running only one unit test.
Am I going crazy or is there a legitimate reason why this would occur?

I defined your global variable by using extern keyword as rmaddy suggested and it is allocated in a unit test under the same conditions you described. Here is the code
// Header file
#import <Foundation/Foundation.h>
extern NSArray *knownPrinters;
#interface DummyObject : NSObject
#end
Here is the implementation file
#import "DummyObject.h"
NSArray *knownPrinters = nil;
#implementation SingletonObject
#end
And test file,
#import <UIKit/UIKit.h>
#import <XCTest/XCTest.h>
#import "DummyObject.h"
#interface SOStaticAssignTests : XCTestCase
#end
#implementation SOStaticAssignTests
- (void)setUp {
[super setUp];
}
- (void)tearDown {
[super tearDown];
}
- (void)testExample {
knownPrinters = [NSArray new];
NSLog(#"For debugging");
}
#end
I hope it solves your problem.

Related

Objective-C error "No visible #interface for 'XYZPerson' declares the selector 'saySomething'

I am really new to Objective-C and when I was practicing the book exercises, I really am stuck here. Please help me solve this and I have been thinking what could cause this error for more than three hours. Still I didn't get it!
Best regards,
Raj.
Thanks in advance !
main.m
#import <Foundation/Foundation.h>
#import "XYZPerson.h"
#import "XYZShout.h"
int main(int argc, const char * argv[])
{
#autoreleasepool {
//XYZPerson *some = [[XYZPerson alloc]init];
XYZShout *some = [[XYZShout alloc]init];
[some sayHello];
// insert code here...
// NSLog(#"Hello, World!");
}
return 0;
}
XYZPerson.h
#import <Foundation/Foundation.h>
#interface XYZPerson : NSObject
#property NSString *firstName;
#property NSString *secondName;
#property NSDate *dob;
-(void) saySomething;
-(void) sayHello;
#end
XYZPerson.m
#import "XYZPerson.h"
#implementation XYZPerson
-(void) sayHello {
[self saySomething:#"Hello all"];
}
-(void) saySomething:(NSString *)greet {
NSLog(#"%#", greet);
}
#end
XYZShout.h
#import "XYZPerson.h"
#interface XYZShout : XYZPerson
// -(void) saySomething;
#end
XYZShout.m
#import "XYZShout.h"
#implementation XYZShout
-(void) saySomething:(NSString *)greet {
NSString *upperGreet = [greet uppercaseString];
[super saySomething:upperGreet]; // this is where I get the error mentioned above
}
#end
Got it working ! Thanks to #MatthewD , #trojanfoe , #JFS for your big help :)
It looks like you are testing inheritance so I will assume that XYZShout is supposed to be derived from XYZPerson. If so follow the suggestion from #JFS and make sure it does actually derive:
XYZShout.h:
#import <Foundation/Foundation.h>
#import "XYZPerson.h"
#interface XYZShout : XYZPerson
- (void)saySomething:(NSString *)greet;
#end
And also correct the definition of saySomething in XYZPerson (you missed off the parameter):
XYZPerson.h:
#import <Foundation/Foundation.h>
#interface XYZPerson : NSObject
#property NSString *firstName;
#property NSString *secondName;
#property NSDate *dob;
- (void)saySomething:(NSString *)greet;
// ^^^^^^^^^^^^^^^^^
- (void)sayHello;
#end
(Moved from comments into an answer...)
MatthewD: What happens if you change - (void) saySomething; in XYZPerson.h to - (void) saySomething:greet;?
Raj0689: Why does it run when I change it to saySomething:greet and not saySomething ? Since greet is defined only along with saySomething !!
When you call a method, the compiler needs to locate the signature of that method so it can verify that the method is being called correctly. The signature includes the method name and the number and types of parameters. The usual way of providing method signatures is by importing the header file that defines those signatures.
So, in XYZShout.m where you call:
[super saySomething:upperGreet];
The compiler searches XYZShout.h, which is imported by XYZShout.m, and XYZPerson.h, which is imported by XYZShout.h. In XYZShout.h, the following method was being found:
-(void) saySomething;
This matches the called method in name, but not in parameters, so the compiler does not consider this a match. No other definitions of saySomething are found anywhere, so it gives an error instead.
Please make sure to set the XYZShout.h interface to #interface XYZShout : XYZPerson?

EXC_BAD_ACCESS when synthesizing a 'global' object

this is a follow-up question to my last one here: iOS: Initialise object at start of application for all controllers to use .
I have set my application up as follows (ignore the DB Prefix):
DBFactoryClass // Built a DataManaging Object for later use in the app
DBDataModel // Is created by the factory, holds all data & access methods
DBViewControllerA // Will show some of the data that DBDataModel holds
moreViewControllers that will need access to the same DBDataModel Object
i will go step by step through the application, and will then in the end post the error message i get when building.
AppDelegate.h
#import "DBFactoryClass.h"
AppDelegate.m
- (BOOL)...didFinishLaunching...
{
DBFactoryClass *FACTORY = [[DBFactoryClass alloc ]init ];
return YES;
}
DBFactoryClass.h
#import <Foundation/Foundation.h>
#import "DBDataModel.h"
#interface DBFactoryClass : NSObject
#property (strong) DBDataModel *DATAMODEL;
#end
DBFactoryClass.m
#import "DBFactoryClass.h"
#implementation DBFactoryClass
#synthesize DATAMODEL;
-(id)init{
self = [super init];
[self setDATAMODEL:[[DBDataModel alloc]init ]];
return self;
}
#end
ViewControllerA.h
#import <UIKit/UIKit.h>
#import "DBDataModel.h"
#class DBDataModel;
#interface todayViewController : UIViewController
#property (strong)DBDataModel *DATAMODEL;
#property (weak, nonatomic) IBOutlet UILabel *testLabel;
#end
ViewControllerA.m
#import "todayViewController.h"
#implementation todayViewController
#synthesize testLabel;
#synthesize DATAMODEL;
- (void)viewDidLoad
{
todaySpentLabel.text = [[DATAMODEL test]stringValue];
}
#end
DBDataModel.h
#import <Foundation/Foundation.h>
#interface DBDataModel : NSObject
#property (nonatomic, retain) NSNumber* test;
#end
DBDataModel.m
#import "DBDataModel.h"
#implementation DBDataModel
#synthesize test;
-(id)init{
test = [[NSNumber alloc]initWithInt:4];
return self;
}
#end
when i build it, i get the following error: EXC_BAD_ACCESS in this line:
#synthesize DATAMODEL;
of DBFactoryClass.m
What #synthesize does is to automatically generate implementations of the accessors for a property. EXC_BAD_ACCESS there means that you're accessing garbage when one of the accessors is executed.
That's probably happening here:
[self setDATAMODEL:[[DBDataModel alloc]init ]];
Make sure that DBDataModel's implementation of init actually returns a legitimate object.
As far as I can tell, your DBFactoryClass class is never stored anywhere, and therefore released right after the allocation if you use ARC (Since you use the strong keyword I assumed you do).
- (BOOL)...didFinishLaunching... {
DBFactoryClass *FACTORY = [[DBFactoryClass alloc ]init ];
// If you use ARC this might be released right afterwards
return YES;
}
If you want the factory to be a singleton, use something like this
+ (id)sharedInstance {
static dispatch_once_t once;
static MyFoo *instance;
dispatch_once(&once, ^{
instance = [[self alloc] init];
});
return instance;
}

Singleton data out of scope problem

I am trying to pass data between the viewcontrollers of a uitabbarcontroller using a singleton class as below:
#import <Foundation/Foundation.h>
#interface AppSingleton : NSObject {
NSMutableString *selectedStr;
}
#property(nonatomic,retain) NSMutableString *selectedStr;
+(AppSingleton*) sharedAppInstance;
#end
Here is my implementation file:
#import "AppSingleton.h"
#implementation AppSingleton
#synthesize selectedStr;
+(AppSingleton*) sharedAppInstance{
static AppSingleton *sharedAppInstance;
#synchronized(self){
if(!sharedAppInstance){
sharedAppInstance = [[AppSingleton alloc] init];
}
}
return sharedAppInstance;
}
-(void)dealloc{
[selectedStr release];
[super dealloc];
}
#end
I try to set the selectedStr in one of my viewcontrollers as below and print it in the NSLog however I get a null:
AppSingleton *sharedAppInstance;//in the header
sharedAppInstance = [AppSingleton sharedAppInstance];//in viewdidload
[sharedAppInstance setSelectedStr:self.someStr];
NSLog(#"selectedStr is: %#", sharedAppInstance.selectedStr);
When I debug this, the sharedAppInstance.selectedStr seems to be out of scope.
I would like to know where I am making a mistake.
Thank you.
I changed the placing of the setting/getting of my variable within the viewcontroller and it worked..
[sharedAppInstance setSelectedStr:self.someStr];
NSLog(#"selectedStr is: %#", sharedAppInstance.selectedStr);

Memory leak for object in array

I've started cleaning up my app before publication - using "Instruments" Leak analyzer.
I found a leak I can't plug. So I built a simple project to illustrate the problem. Please see code below. I put a button on the view to test fire the procedure "test". It always generates a leak.
First the header and code for an object named "theObj"
#import <Foundation/Foundation.h>
#interface theObj : NSObject {
NSString* theWord;
}
#property (nonatomic,retain) NSString* theWord;
#end
#import "theObj.h"
#implementation theObj
#synthesize theWord;
-(id) initWithObjects: (NSString *) aWord;
{
if (self = [super init]){
self.theWord = aWord;
}
return self;
}
-(void) dealloc{
[theWord release];
[super dealloc];
}
#end
Now the view controller
#import <UIKit/UIKit.h>
#import "theObj.h"
#interface LeakAnObjectViewController : UIViewController {
NSMutableArray* arrObjects;
}
- (IBAction)test;
#end
#import "LeakAnObjectViewController.h"
#implementation LeakAnObjectViewController
- (IBAction)test {
if (arrObjects == nil)
arrObjects = [[NSMutableArray alloc] init];
NSString* aStr = #"first";
[arrObjects addObject:[[theObj alloc] initWithObjects:aStr]];
[arrObjects removeAllObjects];
}
You alloc the object, which means you own it. Then you give it to the array, which means the array owns it as well. Then the array removes it, so you are the only owner. But you don't have a reference to the object anymore, so you can't release it, so it's just leaked.
Someone really needs to learn the rules around memory management. Specifically as it pertains to ownership, etc.

How to move non static variables from interface to implementation in objectiveC?

I am trying to write a cocoa touch static library.
To keep it simple I would prefer not to use private variables within my interface file.
The code right now looks like this:
interface file (myView.h):
#interface myView: UIView {
NSTimer * myTimer;
}
#end
implementation file (myView.h)
#implementation myView
#end
This NSTimer pointer is just a private variable so I tried this:
(not working)
interface file (myView.h):
#interface myView: UIView {
}
#end
implementation file (myView.h)
NSTimer * myTimer;
#implementation myView
#end
It seems to work however it turned out that the timer is now a static variable.
Am I doing sth wrong or is there no solution?
You can't define instance variables in your implementation file.
A possible solution is to have a private structure containing the private variables and have one publicly declared private variable pointing to this private structure:
#interface MyView {
void *privateData;
}
Implementation file:
typedef struct {
NSTimer *myTimer;
} PrivateData;
#implementation MyView()
#property (readonly) PrivateData *privateData;
#end
#implementation MyView
- (id) init {
if (self = [super init]) {
privateData = malloc(sizeof(PrivateData));
self.privateData->myTimer = nil; // or something else
}
return self;
}
-(PrivateData *) privateData {
return (PrivateData *) self->privateData;
}
- (void) myMethod {
NSTimer *timer = self.privateData->myTimer;
}
- (void) dealloc {
// release stuff inside PrivateData
free(privateData);
[super dealloc];
}
#end
It's not beautiful, but it works. Maybe there are better solutions.
Just a note; trying to hide iVar's for the sake of security is silly. Don't bother.
For simplicity's sake, though, it has value.
However, a couple of solutions:
(1) If targeting iPhone OS or 64 bit Cocoa, you can #synthesize the ivar:
Foo.h:
#interface Foo:NSObject
#property(readwrite, copy) NSString *publiclyReadwriteNoiVar;
#property(readonly, copy) NSString *publiclyReadonlyPrivatelyReadwriteNoiVar;
#end
Foo.m:
#interface Foo()
#property(readwrite, copy) NSString *privateProperty;
#end
#implementation Foo
#synthesize publiclyReadwriteNoiVar, publiclyReadonlyPrivatelyReadwriteNoiVar, privateProperty;
#end
(2) Use a private subclass kinda like class clusters:
Foo.h:
#interface Foo:NSObject
#end
Foo.m:
#interface RealFoo:Foo
{
.... ivars here ....
}
#end
#implementation RealFoo
#end
#implementation Foo
+ (Foo *) convenienceMethodThatCreatesFoo
{
.... realFoo = [[RealFoo alloc] init]; ....
return realFoo;
}
#end
Depending on the goal of your encapsulation, there's also the #private directive:
Access Modifiers