iOS how to wrapper C++ class in Swift project - ios

I have a static library in C++, and now I want to use this library in my new Swift project. I found that I couldn't use C++ class directly in Swift project, so I have to wrapper this library in OC. Then I have some problem wrapping this:
//AbstractClassA.h
#include <string>
class AbstractClassA {
public:
virtual string getString() = 0;
virtual int getInt() = 0;
virtual ~AbstractClassA() {};
};
//AbstractClassB.h
class AbstractClassB {
public:
virtual void function(int a) = 0;
virtual ~AbstractClassB() {};
};
//ChildA.h
#include "AbstractClassA.h"
#include "AbstractClassB.h"
class ChildA : public AbstractClassA
{
public:
ChildA(int a = 640);
ChildA( AbstractClassB* classb, int a = 640);
virtual ~ChildA();
string getString();
int getInt();
protected:
int a;
string b;
};
How to wrapper these classes in OC? Thanks for any help!

You create an Objective-C++ class that wraps the C++ class. The header file must not contain any C++ features; the file with the implementation must end in .mm to tell Xcode to use the Objective-C++ compiler, not Objective-C.
In the .h file, you'd have an interface for class ChildAWrapper, methods init, initWithInt:, initWithClassB:, initWithClassB:Int: and readonly properties stringValue and intValue.
In the .mm file, you'd have an instance variable of type ChildA*. The init methods create a ChildA object. dealloc deletes it. You implement the properties by calling the methods of the ChildA object, converting the std::string to an NSString*.
Same for ClassB with an Objective-C class ClassBWrapper. There you want a readonly property void* wrappedClass returning a pointer to the the ClassB object, converted to void*, because ChildAWrapper will need that.

Related

i have a questions when i use iOS-Universal-Framework

The iOS-Universal-Framework's page : https://github.com/kstenerud/iOS-Universal-Framework
It is an XCode project template to build universal (arm6, arm7, and simulator) frameworks for iOS.
I have build my framework by use this template,but i got a problem,i have pack all my class in the template,including a macro definition #define kCOMPANYID 2 in a .h file Macro.h,but the problem is ... the kCOMPANYID must can be modified by the one who use my framework,so the kCOMPANYID must define out of the framework,but the problem is , some classes in my framework must use the kCOMPANYIDïĵŒso it is a conflict,i don't know how to do,please help me,thanks.
you should avoid #define as much as possible
one way is to make a setter/getter function to for it
e.g.
// public header file
void SetCompanyId(int value);
// int GetCompanyId(); // it can be in public header or private header
// some .m or .c or .cpp file
static int companyId;
int GetCompanyId() { return copanyId; }
void SetCompanyId(int value) { companyId = value; }
or if the user mush provide a id, just make it a global variable. you can add const to it so the value can't change
// header file in your framework
extern const int kCompanyId;
// some implementation file in user code
const int kCompanyId = 2;
then user must provided a company id otherwise it will have linker error

How to reference static classes in Actionscript

I apologize in advance for the newbiness of this question; I think I'm not grasping the basics of Actionscript but haven't been able to find an answer elsewhere.
What I want is some global constants like one would have in C++. In C++, I would simply have a file where I would #define MAP_HEIGHT 20, or something like that, and they would be globally accessible when I included the file at the top. In Actionscript, I've tried making a static class instead, like so:
package
{
public class Settings {
public const mapx:int = 20;
public function Settings() {}
}
}
But when I try to reference it in my code with colon syntax
var a:int = Settings::mapx;
I get the error "[Fault] exception, information=TypeError: Error #1034: Type Coercion failed: cannot convert Settings$ to Namespace."
I tried dot syntax:
var a:int = Settings.mapx;
and got a different error, "Access of possibly undefined property mapx through a reference with static type Class."
But what I really want is a file of global static variables, like in C++, and can't find a way to do it in Actionscript.
Mark variables, constants, and functions with the static keyword, as in:
package
{
public class MathUtil
{
public static const PI:Number = 3.141592653589;
public static function deg2rad(angle:Number):Number
{
angle = !isNaN(angle) ? (angle) : (0);
return angle * PI / 180;
}
}
}
Then you may use dot notation.
var pi:Number = MathUtil.PI;
var angle:Number = MathUtil.deg2rad(45);
From ActionScript 3.0 Reference for the Adobe Flash Platform: Statements, Keywords & Directives
Usage
class someClassName {
static var varName;
static const kName;
static function methodName() { }
}
You can use static in class definitions only, not in interface
definitions.
Static class members are not inherited. You cannot refer to a static
class member using the name of a subclass, as you can in Java or C++.
You can, however, refer to a static variable or method within a class
or subclass, without using any qualifier. See the example below.
You cannot use the super statement or the this keyword inside a static
method.

How to define that a function returns an object when building binding for a iOS library

Building a wrapper for an iOS library. So far so good. Except in a method that returns an object. Method always returns NSObject instead. The same story is in delegate that has an object parameter .
For example,TCConnection is defined in Monotouch binding project as
//#interface TCConnection : NSObject
[BaseType (typeof(NSObject))]
public interface TCConnection
{
[ExportAttribute("state")]
int state {get;}
//...
}
class TCDevice is defined as follows
//#interface TCDevice : NSObject
[BaseType (typeof(NSObject))]
public interface TCDevice
{
[ExportAttribute("initWithCapabilityToken:delegate:")]
IntPtr Constructor(String token, TCDeviceDelegate d);
[Export("connect:delegate:")]
TCConnection Connect([NullAllowed] NSDictionary param, [NullAllowed] TCConnectionDelegate del);
}
Everything is compiled nicely to a dll.
When I use the dll in other project, I call
MyTCDeviceDelegate d=new MyTCDeviceDelegate();
String token="XXXXX";
TCDevice dev=new TCDevice(token, d);
TCConnection conn=dev.Connect(null,null);
The last line always throws Invalid Cast exception.It looks like the method returns NSObject.
What I am missing here?

Mocking C++ classes with dependency injection

Say you're testing class A and it has a dependency injection of B which has a dependency injection of C.So you mock B but the only constructor it has requires an injection of C, so do you have to mock C as well and inject the mocked C into the mocked B and only then inject it to A?What if you have 5 consecutive dependancies?
What are the alternatives?
I use Google Mock, so a specific answer would help as well.
Emile has the right idea, you should depend on interfaces not concrete classes. So in your example it would be something like:
#include <iostream>
using namespace std;
class C {
public:
int x;
};
class B {
public:
~B(){};
virtual void doSomething() = 0;
};
class ConcreteB : public B{
public:
ConcreteB(C c) : m_c(c) {}
void doSomething(){
std::cout << "HelloWorld" << std::endl;
}
private:
C m_c;
};
class A{
public:
A(B *b): m_b(b){}
void functionToTestWithSideEffect(){
m_b->doSomething();
}
private:
B *m_b;
};
//#include <gmock/gmock.h>
int main() {
C c;
c.x = 42;
ConcreteB b(c);
A a(&b);
a.functionToTestWithSideEffect();
return 0;
}
In your tests you create a mock B which does not rely on any class C. Then you are only testing the interface with B. In this way you break A's dependency on C. Creating a mock B that doesn't depend on C is pretty simple:
class MockB : public B {
public:
MOCK_METHOD0(doSomething, void());
};
If you change the design so that the classes depend on interfaces instead of concrete classes, you get rid of the constructor problems. Besides improving testability, it may also improve reusability and maintainability, at the cost of more code (interfaces).
In this case you should inject by pointer and not by reference, then you could pass a NULL pointer. This would work assuming you're object is indeed a mock and not a fake object, therefore it has no real dependency on the injected object.
For boost::shared_ptr you could do the following:
boost::shared_ptr<C> null_c_ptr;
MockB mock_b(null_c_ptr);

Do C++ Templates play nicely with VCL classes?

I'm trying to use C++ Template 'mixins' to create some new VCL components with shared additional functionality. Example...
template <class T> class Mixin : public T
{
private:
typedef T inherited;
// ...additional methods
public:
Mixin(TComponent *owner) : inherited(owner)
{
// .. do stuff here
};
};
Used like this:
class MyLabel : public Mixin<TLabel>
{
....
}
class MyEdit : public Mixin<TEdit>
{
....
}
Now, everything compiles fine, and the mixin stuff seems to work - until I try and save the component to a stream using TStream->WriteComponent, where the inherited properties (eg TLabel.Width/Height/etc.) don't get written. This is even with a 'null' mixin like the one shown above.
My code works fine when just deriving classes directly from TForm, TEdit, etc - and the class is correctly registered with the streaming system.
The quick/simple answer is: no; when dealing with a template, the compiler won't generate the proper descriptors to make streaming working. However, since this has come up before, I peeked under the cover to find out what's missing. And what I found is that it's almost there. So here's a little more information.
Upfront the compiler will never treat a template-based type as a Delphi. For example, do something like this:
void testing()
{
__classid(Mixin<Stdctrls::TLabel>); // Error Here
}
... and you'll see the error
"Error E2242 test.cpp 53: __classid requires Delphi style class type (i.e. class marked __declspec(delphiclass) or derived from System::TObject) in function testing()"
This basically says the compiler does not consider this type/class as compatible with Delphi-classes [i.e. those that derive from TObject]. Internally there's just a flag on the symbol that says whether the type is delphi-compatible or not. And I noticed that I could trick the compiler into marking the type as delphi-style if I forced it to walk up the hierarchy.. which is something it has to do if I create an instance of the object. So, with this hack the error goes away:
void testing()
{
typedef Mixin<Stdctrls::TLabel> __ttype;
std::auto_ptr<__ttype> c2(new __ttype(0));
__classid(Mixin<Stdctrls::TLabel>); // No more errors here
}
But much nicer was actually to use the __declspec(delphiclass) directly on the template, as in:
template <class T>
class __declspec(delphiclass) Mixin : public T {
private:
int i;
typedef T inherited;
public:
__fastcall Mixin(TComponent *owner) : inherited(owner) {};
};
So now that the compiler treats the type as a delphi-style class without hacks, I peeked a little more and found the issue you're probably running into: Delphi classes have the TTypeData.PropCount field - http://docwiki.embarcadero.com/VCL/en/TypInfo.TTypeData - which is a sum of the class' properties, including those of its base classes. Due to the way the various pieces of information are computed, the compiler writes out a '0' for that field when a template is involved:(
You can see this by printing out the PropCount, as in:
#include <Stdctrls.hpp>
#include <cstdio>
#include <memory>
#include <utilcls.h>
class TCppComp : public Classes::TComponent {
int i;
public:
__fastcall TCppComp(TComponent* owner): Classes::TComponent(owner) {};
__published:
__property int AAAA = {read=i, write=i};
};
template <class T>
class __declspec(delphiclass) Mixin : public T {
private:
int i;
typedef T inherited;
public:
__fastcall Mixin(TComponent *owner) : inherited(owner) {};
};
typedef Mixin<TCppComp> TMixinComp;
void showProps(TClass meta) {
PTypeInfo pInfo = PTypeInfo(meta->ClassInfo());
int Count = GetPropList(pInfo, tkAny, NULL);
TAPtr<PPropInfo> List(new PPropInfo[Count]);
std::printf("Class: %s - Total Props:%d\n",
AnsiString(pInfo->Name).c_str(), Count);
GetPropList(pInfo, tkAny, *(reinterpret_cast<PPropList*>(&List)));
for (int i = 0; i < Count; i++) {
AnsiString propName(List[i]->Name);
std::printf("\t%s\n", propName.c_str());
}
}
void test() {
showProps(__classid(TCppComp));
showProps(__classid(TMixinComp));
}
int main() {
test();
return 0;
}
When run the above prints:
Class: TCppComp - Total Props:3
AAAA
Name
Tag
Class: #%Mixin$8TCppComp% - Total Props:0
IOW, Mixin shows up with '0' published properties while its base type has 3:(
I suspect the streaming system relies on this count and that's why inherited properties are not being written out in your setup.
I considered tweaking the generated descriptors at runtime but since we write them to _TEXT it's bound to trigger DEP.
I'll look at the logic that computes the PropCount to see if there's some way to get it to compute the correct number. If time allows, please do open a QC for this: now that I've peek underneath, I believe it would not require much effort to get this working as expected.
Cheers,
Bruneau
PS: In my sample I even had the Mixin publish a property and the compiler generated the correct descriptor for that property; however, the total count was still zero.

Resources