Compiling in XCode 3.1.3 using GCC 4, under Leopard 10.5.8, with 10.5 as my target...
I have an interface, thus:
#interface testThing : NSObject { classContaininghooHa *ttv; }
#end
And an implementation, thus:
#implementation: testThing
- (void) instanceMethodMine
{
[ttv hooHa]; // works perfectly, compiles, links, hooHa is invoked.
}
// void cFunctionMine()
// {
// [ttv hooHa]; // compiler: 'ttv' undeclared (first use in this function) "
// }
void stupidCFunctionMine((testThing *)whom) // whom is passed class 'self' when invoked
{
[whom instanceMethodMine]; // compiles, links, works. :/
}
#end
Now, my understanding -- clearly flawed -- was that if you declared a variable, class ID or otherwise, it was private to the class, but within the class, is performed essentially as a global, stored in the allocated class instance for the duration of its existence.
That's how it acts for objc methods.
But in the c function above, also written within the class, the variable appears to be invisible. The doesn't make sense to me, but there it is.
Can someone explain to me what is going on?
While you're at it, how can I declare this as an instance variable so I can use the method within a c function declared within the class scope as shown above, as well as within methods?
Insight much appreciated.
It doesn't make any difference where you are declaring/defining your "normal" c functions. They are not part of the class, they are just plain old c functions. No connection to the class whatsoever. Passing the instance they work on is a workaround if you really don't want to make this function a true objective-c method.
interface methods have full access to it's member variables. And the C function is not part of the class and so it cannot access any class variables unless it takes an class instance as the argument.
void cFunctionMine()
{
[ttv hooHa]; // compiler: 'ttv' undeclared (first use in this function)
}
Clearly cFunctionMine is not part of the interface. So it does not what ttv is to send the message hooHa.
While you're at it, how can I declare this as an instance variable so I can use the method within a c function declared within the class scope as shown above, as well as within methods?
void cFunctionMine()
{
// 1. Create an instance using alloc and init
testThing *ttv = [ [testThing alloc] init ] ;
[ttv hooHa] ;
// Now the above statement is valid. We have a valid instance to which
// message can be passed to.
// .....
[ ttv release ] ;
// release the resources once you are done to prevent memory leaks.
}
Related
I'm attempting to create a class in Swift 3 to implement a Cordova plugin. I have this building and running, but the application crashes whenever any properties of the class are accessed. I've tried two ways of initializing the class:
#objc(DSFMediaCentre)
class DSFMediaCentre : CDVPlugin
{
var players = [UUID:DSFPlayerHandler] ();
...
}
and
#objc(DSFMediaCentre)
class DSFMediaCentre : CDVPlugin
{
var players :[UUID:DSFPlayerHandler];
override init () {
players = [:];
}
...
}
However, when my players property is used, the result is a EXC_BAD_ACCESS exception, with an address that looks like a null pointer dereference.
The object is being created by Objective C code, which is a language I have no familiarity with at all, but I think this is the line that creates it:
obj = [[NSClassFromString(className)alloc] initWithWebViewEngine:_webViewEngine];
The CDVPlugin class contains a comment stating that initWithWebViewEngine should not be overridden (and indeed I do not seem to be able to override this method, because while it is declared in the CDVPlugin.m file, it isn't mentioned in CDVPlugin.h, so the Swift compiler doesn't seem to know about it), but rather initialization code should be placed in a method called pluginInitialize instead. However, if I do that I get a compiler error ("Class DSFMediaCentre has no initializers").
Furthermore, if I put my init() method back in and set it to call pluginInitialize(), like this:
override init () {
super.init(); // necessary otherwise next line is an error
pluginInitialize();
}
override func pluginInitialize() {
players = [:];
}
the error then changes to "Property 'self.players' not initialized at super.init call".
How do I make this class initialize correctly?
You have a mismatch between the strict initialization system required by the language and the procedure used by the framework you're working with.
Swift demands that a) properties be initialized as part of object construction, and b) that construction be chained to the type's supertype. But the CDVPlugin type is doing the construction on your behalf; you don't have the ability to customize it. (This makes more sense in ObjC, because it doesn't have the same compile-time restrictions as Swift.)
The situation is similar to unpacking an object from a nib file. In that case too, because it's the nib loading system that's constructing your object, you don't have the ability to customize the initializer. Your type will always be constructed by init(coder:). In a certain sense, your initialization point moves further down, to awakeFromNib(), and among other things, that forces outlets to other objects in the archive to be declared as optional, usually implicitly unwrapped.
The same solution should avail you here. You should consider pluginInitialize() to be your initialization point. The language then requires that properties be optional, since they are not filled at its initialization point. Therefore, make the property an IUO:
#objc(DSFMediaCentre)
class DSFMediaCentre : CDVPlugin
{
var players :[UUID:DSFPlayerHandler]!
override func pluginInitialize() {
players = [:];
}
}
and all should be well.
The other solution is to use lazy keyword
lazy var players :[UUID:DSFPlayerHandler] = [:]
So, you don't need to initialize players in initializer but still make sure players always non-nulable
How can you use a Objective C method as an argument for glutDisplayFunc (and functions like it)? I'm quite new to ObjC, so I don't completely know how this works
In C++, you can just pass in a void, but in ObjC, I tried this:
//...
glutDisplayFunc([self display]);
//...
-(void) display{
glutPostRedisplay();
}
I've also tried static methods
//...
glutDisplayFunc([self display]);
//...
+(void) display{
glutPostRedisplay();
}
but every time I get the error "passing 'void' to parameter with incompatible type void(*)(void)".
I thought you could just pass in a void.
So, how can I make this work (it has to be a method)
In C++, you can just pass in a void
No, you can't.
So, how can I make this work (it has to be a method)
You can't. What you're interested in would be as something known as closure or delegate, but GLUT will just take global scope C style callback functions. The best thing you could to was write a global scope wrapper with a calling convention compatible to C, which then calls the method of a global scope class instance.
i have helper C functions in some Objective C classes.
Just found out that the values of global, static C variables which i use in these functions are shared between instances of the class (duh), which is not what i want.
Is there a way to declare these variables local to instances of the class, so that they are visible by the helper functions without passing them explicitly?
Is there a way to declare these variables local to instances of the class
Sure, make them instance variables.
But:
so that they are visible by the helper functions without passing them explicitly?
You can pass the object into the function. If you have appropriate accessors, the function can get them. And if you have mutators, it can modify them, too.
But if you're doing that, you might as well just create a method, and automatically have access to the instance variables.
want to avoid method calls where necessary
logically separate it so your low level code is in c or c++, then add the required data to your objc class:
/* c example */
typedef struct t_generator {
UInt32 a;
} t_generator;
static void Generate(t_generator* const gen) {
/.../
}
#interface MONObjCGeneratorContainer : NSObject
{
t_generator generator;
NSString * name;
UInt32 b;
}
#end
if the data interface is as simple you can just access them from the instance:
- (void)method { GenerateB(&b); }
that should meet all the requirements you have posted (so far).
RS232MsgGetEventDescriptions.h:
#define DECLARE_RS232_NEWMSG(ClassID)\
enum \
{ \
ID = ClassID \
}; \
#interface RS232MsgGetEventDescriptions : RS232Msg
{
}
#end
RS232MsgGetEventDescriptions.m
#implementation RS232MsgGetEventDescriptions
DECLARE_RS232_NEWMSG(RM_GET_EVENT_DESCRIPTIONS);
#end
EventLogs.m
-(void)event
{
service = [CServiceAppDlg alloc];
if ([service:(REMOTE_MESSAGE_ID)RS232MsgGetEventDescriptions.ID withEvent:pEvent])
{
NSLog(#"Get Event descriptions!!");
}
}
I'm getting an error like "Accessing Unknown 'ID' class method"
I should not modify the definition here.How to pass the ID.I am going to call different descriptions ID in the same way so is this declaration of ID.
The reason why you are getting a Accessing Unknown 'ID' class method error message is because you have not declared a method called ID in your class RS232MsgGetEventDescriptions.
When you say RS232MsgGetEventDescriptions.ID in your code, you are calling the property ID of object RS232MsgGetEventDescriptions, which is equivalent to [RS232MsgGetEventDescriptions ID]. However, RS232MsgGetEventDescriptions is not an object, but a class and you don't have a class method called + (REMOTE_MESSAGE_ID)ID in your class specification (you don't have it declared on the interface or implemented on the class implementation).
I would also like to point out that it is bad practice to use the dot notation for something other than a property. Since classes cannot have #properties (these are for objects) you should call this method using standard Objective-C messaging notation [RS232MsgGetEventDescriptions ID].
Xcode will still allow you to write object.methodName to call methods with no parameters, and object.methodName = value for methods that take 1 parameter. Because they are interpreted as follows:
object.methodName; // Becomes [object methodName]
object.methodName = value; // Becomes [object setMethodName:value]
I want to make a global vector of my own object class called "Person". However, the compiler says that
error C2039: '{dtor}' : is not a member of 'System::IDisposable'
1> c:\windows\microsoft.net\framework\v2.0.50727\mscorlib.dll : see declaration of 'System::IDisposable'
So I looked up how to implement IDisposable (which I now know is used primarily for unmanaged resources) but still can't seem to implement it with the following:
ref class Globals : System::IDisposable
{
public:
static cliext::vector<Person^> person_data = gcnew cliext::vector<Person^>;
void Dispose()
{
delete person_data;
}
};
The 2 errors I get are:
error C2605: 'Dispose' : this method is reserved within a managed class
1> did you intend to define a destructor?
error C3766: 'Globals' must provide an implementation for the interface method 'void System::IDisposable::Dispose(void)'
1> c:\windows\microsoft.net\framework\v2.0.50727\mscorlib.dll : see declaration of 'System::IDisposable::Dispose'
You don't have to explicitly derive from IDisposable. Following the MSDN doco, use the following pattern:
ref class Globals
{
public:
static cliext::vector<Person^> person_data = gcnew cliext::vector<Person^>;
!Globals() // finalizer
{
delete person_data;
{
protected:
~Globals() // destructor calls finalizer
{
this->!Globals();
}
};
Use a destructor. In C++/CLI ~ClassName() is Dispose() and !ClassName() is equivalent to C#'s ~ClassName(). In your case:
ref class Globals : System::IDisposable
{
public:
static cliext::vector<Person^> person_data = gcnew cliext::vector<Person^>;
void ~Globals()
{
delete person_data;
}
};
use a finalizer as shown at http://www.codeproject.com/KB/mcpp/cppclidtors.aspx
You don't need to implement Dispose() yourself, either directly or via a destructor. The implicitly-generated destructor already destroys all member objects. The IDisposable interface will be added automatically, don't mention it explicitly.
Next, you need to make up your mind whether person_data is a handle (which has to be set to an instance created with gcnew) or member object semantics (like stack semantics, the constructor is automatically called by the constructor of the parent object, the destructor called automatically when the lifetime of the parent object ends, and you use "." instead of "->" to access members).
Also, are you sure you want one copy of person_data shared between all instances of "Globals", but destroyed by the first instance to be disposed, leaving any other instances holding an invalid reference (reference to disposed object)? It looks like you're trying to use a Singleton anti-pattern here, is that correct?
From C++/CLI in Action The C++/CLI Dispose pattern has these rules (paraphrased):
If a class has a finalizer or a
destructor the compiler generates
Dispose(bool) that will call either
the finalizer or destructor based on
the bool value.
If it has just a d'tor (~type) then the compiler calls
Dispose(true) so the d'tor is called.
If it has just a finalizer (!type)
then the compiler calls
Dispose(false) so the finalizer is
called
Also for the second rule: The compiler will implement the IDisposable interface for you (by generating Dispose()). It then uses SuppressFinalize to make sure the finalizer isn't called.
I did this to your code and the only way I could get it to compile was to make person_data a instance member. The error i got when it was static was error C2039: '{dtor}' : is not a member of 'System::IDisposable' which doesn't make much sense.
Also, do you even need to delete the person_data vector since is a managed object? Maybe you do but I haven't used the cliext enough to say.
Edit Perhaps the first paragraph of this article has the answer (emphasis mine):
When you declare a member variable as
static and when the application
starts, the compiler creates a copy of
that member. This member would be
maintained by the compiler while the
program is running. If you declare an
instance of a class, like the above
vehicle variable, the static member is
not part of the object: the compiler
creates and maintains the static
member, whether you use it or not,
whether you declare a class variable
or not.