acces c++ datamember in objective-c class - objective-c

What I'm trying to do is quite simple but I probably have the syntax wrong.
I have an Objective-C Interface with a Note class parameter. Note.h is a C++ class that basically looks like this:
#include <string>
using namespace std;
class Note {
public:
string name;
Note(string name){
this->name = name; // ERROR: Cannot find interface declaration for 'Note'
}
};
This is my controller where is using Note. I changed the file extension to .mm
#class Note;
#interface InstrumentGridViewController : UIViewController {
#public
Note* note;
}
#property (nonatomic, retain) Note* note;
And this is how I'm using it:
#implementation InstrumentGridViewController
#synthesize note;
- (void)buttonPressed:(id)sender {
note = Note("fa"); // ERROR: Cannot convert 'Note' to 'Note*' in assignment
NSLog(#"naam van de noot is %s", note->name); // ERROR: Cannot find interface declaration for 'Note'
}
I'm getting these three errors though (I've added them as comments on the right lines)
Any idea how what I'm doing wrong?

You need to allocate the Note object using new:
- (void)buttonPressed:(id)sender
{
if (note != 0)
delete note;
note = new Note("fa");
NSLog(#"naam van de noot is %s", note->name.c_str());
}
However it doesn't seem right to be doing that in the button press action method...
Also don't forget to delete it in your object's dealloc method:
- (void)dealloc
{
delete note;
[super dealloc];
}
Lastly your #property attribute retain is wrong as it's not an Objective-C object; instead use assign and better still make it readonly.
A better way to initialise most objects is by using a const reference to them rather than a copy:
Note(const string &name)
{
this->name = name;
}

Your Note C++ class is not valid. Change its declaration to be instead:
class Note {
public:
string name;
Note(string aName) {
name = aName;
}
};
Also change your InstrumentGridViewController:
- (void)buttonPressed:(id)sender {
note = new Note("fa");
NSLog(#"naam van de noot is %s", note->name);
}
- (void)dealloc {
delete note;
[super dealloc]; // Use this only if not using ARC
}

The Cannot find interface declaration for 'Note' error was caused because of #class Note in my Obj-C controller .h file. It's strange because I have a working sample project where #class is used and it works fine.
I fixed it using forward declarations the way they are described here and here.
// used typedef struct <classname> <classname>
typedef struct Note Note;
// instead of
#class Note
The above goes in the Obj-C header file. In the .mm file goes the #import "Note.h" statement

Related

Why does the static analyzer warn of a garbage value in this code?

With Apple LLVM 4.2 (XCode 4.6), the static analyzer warns "The left operand of '>' is a garbage value" in this class's 'update' method:
Test.h
#import <Foundation/Foundation.h>
typedef struct {
float x;
} TestInnerStruct;
typedef struct {
TestInnerStruct innerStruct;
int value;
} TestOuterStruct;
#interface Test : NSObject {
TestOuterStruct outerStruct;
}
#end
Test.m
#import "Test.h"
#implementation Test
- (id) init {
if (self = [super init]) {
outerStruct.value = 1;
}
return self;
}
- (void) update {
outerStruct.innerStruct = (TestInnerStruct){0.0f};
if (outerStruct.value > 0) {
NSLog(#"Value greater than zero");
}
}
#end
This is a contrived class, made by cutting down the real class to the minimum needed to reproduce this static analyzer warning. In the real class, there are good reasons for using the nested structs.
What path through the code would cause that operand to be a garbage value? Or is the static analyzer getting confused?
Edit for clarification: It's not just that the analyzer's considering the case where [super init] returns nil. I know that because the warning goes away on commenting out the first line of the update method.
Eric is right, and it is apparently a compiler issue: If one changes the definition of TestOuterStruct to
typedef struct {
int value;
TestInnerStruct innerStruct;
} TestOuterStruct;
i.e., if the two elements are interchanged, the code compiles without error.
The outerStruct.value is only set to 1, if self = [super init] succeeds. If is does not (which is of course a VERY rare event, but possible, otherwise the if would not be necessary), the value is not set but garbage.

Objective C, Linking Error with extern variable

I have a very simple java code like this. I don't have any idea how to do this in Objective C. Especially, the static part which calls the getLocalAddress() method and assign it into the static string variable. I know how to set a static variable and a static method in Objective but I dont know how to implement that static { } part in java.
Thanks in advance...
public class Address {
public static String localIpAddress;
static {
localIpAddress = getLocalIpAddress();
}
public Address() {
}
static String getLocalIpAddress() {
//do something to get local ip address
}
}
I added this in my .h file
#import <Foundation/Foundation.h>
extern NSString *localIpAddress;
#class WifiAddrss;
#interface Address : NSObject {
}
#end
And my .m file looks like
#import "Address.h"
#import "WifiAddress.h"
#implementation Address
+(void)initialize{
if(self == [Address class]){
localIpAddress = [self getLocalIpAddress];
}
}
+(NSString *)getLocalIpAddress{
return address here
}
-(id)init{
self = [super init];
if (self == nil){
NSLog(#"init error");
}
return self;
}
#end
And Now I am getting a linking error and it complains about "extern NSString *localIpAddress" part. If I change the extern to static, it works fine. But what I wanted to do is that I want make the scope of "localIpAddress" variable as grobal. Since if I put "static" in front of a variable in Objective-C then the variable is only visible in the class. But this time, I want to make that as a grobal variable. So my question is how to make "localIpAddress" variable as a grobal variable which is initialized once when the first time Address class is created.. Thanks in advance...
You have declared the variable in your .h file (told the compiler that it exists and of which type it is), now you need to define it in your .m file (actually make it exist).
Just add NSString *localIpAddress; to your .m file, or better yet:
NSString *localIpAddress = nil;
(That is, give it a sane default value)
The extern keyword means: there is a variable of the given name and type, but actually lives in an "external" file that needs to be linked. So for each extern declaration, you need to actually define the variable in one of your implementation files (.c, .cxx/.c++/.cpp, .m ; this mechanism is part of the C standard on which Objective-C is standing).
Unless you want other modules to access localIpAddress directly without using your class, declare it as static inside your implementation (.m) file.
extern should be used in the following scenario:
A module defines the variable as global. That particular translation unit must not use extern
Other modules need to access that variable directly. Those particular translation units must use extern
Since this is not your case, do the following in your implementation (.m) file:
static NSString *localIpAddress;
// …
+(NSString *)getLocalIpAddress{
return localIpAddress;
}
and remove
extern NSString *localIpAddress;
from your header (.h) file.
Whenever you need to get that address, use
NSString *addr = [Address getLocalIpAddress];
By the way, the convention is that getter methods do not start with get. For instance, you could’ve named that method localIpAddress.
A quick fix would be to move the localIpAddress variable into your implementation file. Then you wouldn't need to use the extern keyword. Really, if you think about it, you have a static accessor, so there's no reason to have the variable declaration itself in the header.
Let me clarify:
Interface:
#import <Foundation/Foundation.h>
#interface Address : NSObject {
}
+(void) initializeLocalIpAddress;
+(NSString *) localIpAddress;
#end
Implementation:
#import "Address.h"
#import "WifiAddress.h"
NSString *localIpAddress;
#implementation Address
+(void) initializeLocalIpAddress
{
//get the local ip address here
localIpAddress = ...;
}
+(NSString *) localIpAddress
{
return localIpAddress;
}
-(id)init {
if ((self = [super init])) {
NSLog(#"init error");
}
return self;
}
#end

Objective-C - define an enum than can be dot called like ENUMTYPE.ENUMVAL

I've read many things about enum types in objective-c, and I see there is many ways to define them. But I don't see the right way (if there is one) to define an enum that can be called with CARS.ROLLSROYCE and that cannot be used only with ROLLSROYCE in the code.
So I can define ROLLSROYCE in the CARS enum and also in the BEAUTIFULCARS enum.
Do you know the way to define such an enum ?
You are trying to implement namespaces for your Enums in Objective-C. What you're asking for is a lot of elbow grease in Objective-C. You are probably best-off using C++ for this, since it is easy and afaik fully supported in any iOS or Cocoa application. You'll have to rename the files that #import your C++ code to .mm files instead of .m files, and the C++ compiler can be trickier than the Objective-C one. Going this route you'll create a header file like Enums.h.
// Enums.h
namespace CARS
{
enum CARS
{
ROLLSROYCE
};
}
namespace BEAUTIFULCARS
{
enum BEAUTIFULCARS
{
ROLLSROYCE = 45
};
}
And in your .mm sourcefile
#import "Enums.h"
-(void)printEnumvals
{
NSLog(#"CARS %d BEAUTIFULCARS %d",
CARS::ROLLSROYCE,
BEAUTIFULCARS::ROLLSROYCE);
}
If you want to avoid using C++ for this solution, there's a lot more elbow grease, bookkeeping, and opportunity for error. You'll need a header and a source file for this.
// CARS.h
#interface BEAUTIFULCARS : NSObject
{
enum
{
BEAUTIFULCARS_ROLLSROYCE = 45
} BEAUTIFULCARS;
}
#end
#interface CARS : NSObject
{
enum
{
CARS_ROLLSROYCE
} CARS;
}
#end
// CARS.m
#implementation BEAUTIFULCARS
+(NSInteger)ROLLSROYCE{ return BEAUTIFULCARS_ROLLSROYCE; }
#end
#implementation CARS
+(NSInteger)ROLLSROYCE{ return CARS_ROLLSROYCE; }
#end
Your .m source is almost the same:
#import "CARS.h"
-(void)printEnumvals
{
NSLog(#"CARS %d BEAUTIFULCARS %d",
CARS.ROLLSROYCE,
BEAUTIFULCARS.ROLLSROYCE);
}
Objective-C does not manage scope in the same way that most other OO languages do. Interfaces define the properties and messages that an object that interface supports, but don't support protection levels like public or private. When you define an enum in an #interface, that enum ends up in global scope.
For my case, I didn't want to use C++ namespaces or write redundant Objective-C classes for such a simple case, so I fallen back to the C.
// Enum.h
typedef struct
{
const int ROLLSROYCE;
} _CARS;
typedef struct
{
const int ROLLSROYCE;
} _BEAUTIFULCARS;
extern const _CARS CARS;
extern const _BEAUTIFULCARS BEAUTIFULCARS;
And then in Enum.m, define values
// Enum.m
#import "Enum.h"
const _CARS CARS = {0};// 0 is to be assigned to ROLLSROYCE field in struct
const _BEAUTIFULCARS BEAUTIFULCARS = {1}; // same but with 1
And finally, in your "main" code
#import "Enum.h"
// Some method
{
NSLog(#"I can refer to CARS.ROLLSROYCE = %d and BEAUTIFULCARS.ROLLSROYCE = %d", CARS.ROLLSROYCE, BEAUTIFULCARS.ROLLSROYCE);
}
Which will produce this output:
I can refer to CARS.ROLLSROYCE = 0 and BEAUTIFULCARS.ROLLSROYCE = 1

Objective-C Static Class Level variables

I have a class Film, each of which stores a unique ID. In C#, Java etc I can define a static int currentID and each time i set the ID i can increase the currentID and the change occurs at the class level not object level. Can this be done in Objective-C? I've found it very hard to find an answer for this.
Issue Description:
You want your ClassA to have a ClassB class variable.
You are using Objective-C as programming language.
Objective-C does not support class variables as C++ does.
One Alternative:
Simulate a class variable behavior using Objective-C features
Declare/Define an static variable within the classA.m so it will be only accessible for the classA methods (and everything you put inside classA.m).
Overwrite the NSObject initialize class method to initialize just once the static variable with an instance of ClassB.
You will be wondering, why should I overwrite the NSObject initialize method. Apple documentation about this method has the answer: "The runtime sends initialize to each class in a program exactly one time just before the class, or any class that inherits from it, is sent its first message from within the program. (Thus the method may never be invoked if the class is not used.)".
Feel free to use the static variable within any ClassA class/instance method.
Code sample:
file: classA.m
static ClassB *classVariableName = nil;
#implementation ClassA
...
+(void) initialize
{
if (! classVariableName)
classVariableName = [[ClassB alloc] init];
}
+(void) classMethodName
{
[classVariableName doSomething];
}
-(void) instanceMethodName
{
[classVariableName doSomething];
}
...
#end
References:
Class variables explained comparing Objective-C and C++ approaches
As of Xcode 8, you can define class properties in Obj-C. This has been added to interoperate with Swift's static properties.
Objective-C now supports class properties, which interoperate with Swift type properties. They are declared as: #property (class) NSString *someStringProperty;. They are never synthesized. (23891898)
Here is an example
#interface YourClass : NSObject
#property (class, nonatomic, assign) NSInteger currentId;
#end
#implementation YourClass
static NSInteger _currentId = 0;
+ (NSInteger)currentId {
return _currentId;
}
+ (void)setCurrentId:(NSInteger)newValue {
_currentId = newValue;
}
#end
Then you can access it like this:
YourClass.currentId = 1;
val = YourClass.currentId;
Here is a very interesting explanatory post I used as a reference to edit this old answer.
2011 Answer: (don't use this, it's terrible)
If you really really don't want to declare a global variable, there another option, maybe not very orthodox :-), but works... You can declare a "get&set" method like this, with an static variable inside:
+ (NSString*)testHolder:(NSString*)_test {
static NSString *test;
if(_test != nil) {
if(test != nil)
[test release];
test = [_test retain];
}
// if(test == nil)
// test = #"Initialize the var here if you need to";
return test;
}
So, if you need to get the value, just call:
NSString *testVal = [MyClass testHolder:nil]
And then, when you want to set it:
[MyClass testHolder:testVal]
In the case you want to be able to set this pseudo-static-var to nil, you can declare testHolder as this:
+ (NSString*)testHolderSet:(BOOL)shouldSet newValue:(NSString*)_test {
static NSString *test;
if(shouldSet) {
if(test != nil)
[test release];
test = [_test retain];
}
return test;
}
And two handy methods:
+ (NSString*)test {
return [MyClass testHolderSet:NO newValue:nil];
}
+ (void)setTest:(NSString*)_test {
[MyClass testHolderSet:YES newValue:_test];
}
Hope it helps! Good luck.
On your .m file, you can declare a variable as static:
static ClassName *variableName = nil;
Then you can initialize it on your +(void)initialize method.
Please note that this is a plain C static variable and is not static in the sense Java or C# consider it, but will yield similar results.
In your .m file, declare a file global variable:
static int currentID = 1;
then in your init routine, refernce that:
- (id) init
{
self = [super init];
if (self != nil) {
_myID = currentID++; // not thread safe
}
return self;
}
or if it needs to change at some other time (eg in your openConnection method), then increment it there. Remember it is not thread safe as is, you'll need to do syncronization (or better yet, use an atomic add) if there may be any threading issues.
As pgb said, there are no "class variables," only "instance variables." The objective-c way of doing class variables is a static global variable inside the .m file of the class. The "static" ensures that the variable can not be used outside of that file (i.e. it can't be extern).
Here would be an option:
+(int)getId{
static int id;
//Do anything you need to update the ID here
return id;
}
Note that this method will be the only method to access id, so you will have to update it somehow in this code.
(Strictly speaking not an answer to the question, but in my experience likely to be useful when looking for class variables)
A class method can often play many of the roles a class variable would in other languages (e.g. changed configuration during tests):
#interface MyCls: NSObject
+ (NSString*)theNameThing;
- (void)doTheThing;
#end
#implementation
+ (NSString*)theNameThing { return #"Something general"; }
- (void)doTheThing {
[SomeResource changeSomething:[self.class theNameThing]];
}
#end
#interface MySpecialCase: MyCls
#end
#implementation
+ (NSString*)theNameThing { return #"Something specific"; }
#end
Now, an object of class MyCls calls Resource:changeSomething: with the string #"Something general" upon a call to doTheThing:, but an object derived from MySpecialCase with the string #"Something specific".
u can rename the class as classA.mm and add C++ features in it.
Another possibility would be to have a little NSNumber subclass singleton.

How to deal with double composition and inheritance?

I found this related question: How do I use composition with inheritance?
I would like to do the same with Objective-C, that is to say that a GenericView knows that its property obj is a GenericObject, and that a SpecializedView knows that the very same obj property is a SpecializedObject.
Here is an example that will be clearer:
//
// Example.m
#import <UIKit/UIKit.h>
/* HEADER */
// Electrical Machine
#interface ElectricalMachine : NSObject {
}
- (void)plugIn;
#end
// Toaster
#interface Toaster : ElectricalMachine {
}
- (float)getThermostat;
#end
// GenericView
#interface GenericView : NSObject {
ElectricalMachine *machine;
}
- (void)doSomethingGeneric;
#property (nonatomic, retain) ElectricalMachine *machine;
#end
//SpecializedView
#interface SpecializedView : GenericView {
}
- (void)doSomethingSpecialized;
#end
/* IMPLEMENTATION */
// GenericView
#implementation GenericView
#synthesize machine;
- (void)doSomethingGeneric {
Toaster *toaster = [[Toaster alloc] init];
[toaster plugIn];
self.machine = toaster;
[toaster release];
}
#end
// SpecializedView
#implementation SpecializedView
- (void)doSomethingSpecialized {
/* ERROR HERE
* Incompatible types in initialization
* 'ElectricalMachine' may not respond to '-getThermostat'
*/
float r = [machine getThermostat];
r = r;
// ...
}
#end
As you see, I get an error at the end, because for SpecializedView the machine property is an ElectricalMachine, not a Toaster.
Thank you very much for your help!
Old Question
Here is the first version of my question, which was maybe too cryptic:
I have the following generic view:
#interface GenericView {
GenericObject obj;
}
- (id)doSomething;
I also have the following specialized view:
#interface SpecializedView : GenericView {
}
- (id)doSomethingElse;
I have the following object:
#interface GenericObject {
}
- (id)plugIn;
and the following specialized object:
#interface SpecializedObject : GenericObject {
}
- (float)toastTime;
Let's say I want GenericView to handle GenericObject, and SpecializedView to handle the same object, knowing that it is SpecializedObject.
Let me explain by showing implementations:
GenericView doSomething
- (id)doSomething {
[obj plugIn];
}
SpecializedView doSomethingElse
- (id)doSomethingElse {
// ERROR here
float time = [obj toastTime];
}
I will get the following warning:
'GenericObject' may not respond to '-toastBread'
and the following error:
Incompatible types in assignement
Which is logical, since I have defined the type of obj as GenericObject. I want to be able to use methods from GenericObject in GenericView, and methods from SpecializedObject in SpecializedView. Is there a way to precise that obj has to be a GenericObject in GenericView to be handled, and has to be a SpecializedObject to be dealt with in SpecializedView, without adding a property? How would you do that?
Objective-C is a dynamically-typed language and methods are resolved at runtime, not compile time. If in SpecializedView, obj is in fact of an object of type SpecializedObject (even though it's declared as GenericObject), it will in fact respond to a toastBread message. The compiler will generate a warning but you can ignore it.
If SpecializedView may have both GenericObjects and SpecializedObjects, you can make sure that obj responds to toastBread using the respondsToSelector: message (inherited from NSObject):
if ([obj respondsToSelector:#selector(toastBread)]) {
[obj toastBread];
}