Migrate a bunch of old articles to nuggets

Recently, I seem to be reinventing the old story, but I did not have the habit of Git Or Blog before, so I saved a lot of technical sharing at work in the computer files. Now I still want to reorganize and share.

Mixed C++ is also used in the previous work, so I rehash it out, but did rearrange it

Why use C++ codec

1) need to use the tool library or the source is C++

Various platforms, various languages, there will be a lot of open source tools and library files for everyone to learn and use, but such as C and C++ this version of the classic language, many underlying, algorithmic libraries are realized by C++, especially many face recognition, graphics filter algorithm, video processing algorithm, and even the underlying graphics rendering OpenGL

2) C++ is fast in execution

C + + is known to all the execution efficiency of fast, so in the development of the high complexity of the algorithm level content, mostly choose to use c + + to complete, I’m in the client, although not as machine learning, such as large data processing need efficient algorithm is widely used in the work, but the above mentioned facial recognition, graphics filter algorithm, and even video processing, There is also a lot of in-game AI that could be used in what we know as client development

3) Cross-platform

C++ is compiled cross-platform. Binary files compiled from C++ code can run normally on android, iOS, and even WP, which is true cross-platform

When it comes to cross-platform, many people certainly mention H5 cross-platform and ReactNative cross-platform, which usually belong to interpreted cross-platform. They agree on a script language, and the low-level assistance is implemented on the basis of each platform. Even the low-level implementation is realized by C++, which interprets the script language at the bottom level and explains the implementation logic at runtime. For example, WebKit is the core of the browser and JavaScriptCore is the core of RN. Although JS is used to write codes in the development, its essence is to explain the native execution of JS at runtime. Js code does not compile. What these platforms compile at compile time is the syntax interpreter +NA underlying code, which is more or less implemented in C++

Why we use C++ for logic

The reason why we use C++ for the core module of the client is actually from (2) and (3), because our business involves extremely complex text typesetting, and whether it is iOS platform or android platform, the basic typesetting is difficult to meet the unique political requirements of Chinese and even our country. To achieve this, we had to package a set of extremely complex layout strategy controls on each platform, so instead of using CoreText’s basic layout API, we chose to use C++ to implement a set of layout strategy for both platforms. Of course, there are also high requirements for the speed and efficiency of layout

Commonality between ObjectiveC and C++

In iOS development, OC code and C++ code can be perfectly integrated together, what is perfect? You can even use STL to build a C++ List array (C++ code) as soon as you type [NSArray objectAtIndex:xx] (OC code) on the next line. They can be perfectly compiled to generate normal programs, and can also be single-step debug to follow up layer by layer methods at any time. If you step out of an OC messageSend, you can step into a C++ Class function. There is no obstacle between the two. All variables, Pointers, structures, and data can be viewed freely

Full downward compatibility with C is their common ground and bond

Why is that? C++ and OC are fully backward compatible with all C objects, which are essentially void *, even though they have ARC to help manage memory. C++ is also void *. OC calls the function send message because it encapsulates the runtime mechanism (which is also C). But at the end of the day, every function entity is still an IMP, still a function pointer, and this is the same as C++, so the interface between them is so smooth

Other remixes are not so easy

  • If you want to interact with the two environments, you need to write a set of JNI by hand, manually convert the data in the C++ environment and the data in the Java environment, and the breakpoint debugging can not enter the breakpoint in the so, want to debug. Added: Must write log to local disk by fwrite

  • I get before the game, done in C + + mixed lua scripts, the two exchanged more egg pain, although the lua interpreter bottom is written in C, but all the memory is the lua interpreter (or virtual machine) in the data, so if both to each other, also want to write a passage to exchange data, the exchange of data, is through the cumbersome data alignment, Push the stack, out of the stack to communicate.

  • In fact, it can be regarded as a model project of JS code mixing Oc. Like Lua, the whole JS running environment also relies on a set of JS virtual machines provided by JavaScriptCore to execute. It has its own context JSContext. Strings, arrays, and dictionaries are automatically converted by JavaScriptCore, but once two environments need to exchange unique data types, such as function in JS, and custom NSObject in OC, then JSValue is needed to convert and pass

ObjectiveC: how to mix C++

  • To create a pure C++ class, you just need to create.h and.cpp files and import them directly into the project. If you need to use some C++ standard library, you can import libstdC++ directly from Xcode

  • If you want to create an object that recognizes both C++ and OC, just create a.h file and a.m file as usual, and rename the.m file to a.mm file, which tells the compiler that this file can be mixed — ObjectiveC++

  • If you want to create a pure OC class, do I need to say so?

Now in your project, you can have these three kinds of files, basically can meet our needs for mixed editing.

How’s it going? Are you dying to try it?

Example: calling C++ in an OC environment

I’m going to do it step by step, even if it’s the wrong code, I’m going to show you the wrong code, I’m going to explain, I’m going to put in the right code,

The code is not all complete code

Cppobject. h C++ header file. CPP file is left empty, do not write logic

#include <string>
class CppObject
{
public:
    void ExampleMethod(const std: :string& str){};
    // constructor, destructor, other members, etc.
};

Copy the code

Ocobject. h OC’s header file.m is changed to.mm, but the logic is not written

#import <Foundation/Foundation.h>
//#import "CppObject.h"

@interface OcObject : NSObject {
    CppObject* wrapped;
}

@property CppObject* wrapped2;

- (void)exampleMethodWithString:(NSString*)str;
// other wrapped methods and properties
@end

Copy the code

So the header file is ready, so the implementation file, I’m not going to write the logic, but I’m going to run and see what happens, okay?

Ocobject. h is a C++ header file that xcode does not recognize and cannot compile.

Yi? Just said C++ and OC seamless communication? And the reason for that is simple, we can tell the compiler xcode that this is a mixed file by changing.m to.mm, but I’m not saying that we’re changing.h to.hh, but for xcode, we know the mixed syntax for.mm, but we don’t know the mixed syntax for.h, and if all of the.h is written in C++, No problem if dot h is all OC, no problem if dot h has C++ in it and OC in it? There is a problem with that (other header files introduced in.h also count)

How do you deal with that? Two ways

  • I’m not writing in.h anymore, so I’ll move to.mm

  • Don’t let me write c++? Ok, I’ll write C, but C is good anyway, so I’ll write void star for ID

So I’m going to do this in my.mm file

#import "OcObject.h"
#import "CppObject.h"
@interface OcObject(a){
    CppObject* wrapped;
}
@end

@implementation OcObject

- (void)exampleMethodWithString:(NSString*)str
{
    // NOTE: if str is nil this will produce an empty C++ string
    // instead of dereferencing the NULL pointer from UTF8String.
    std::string cpp_str([str UTF8String], [str lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
    wrapped->ExampleMethod(cpp_str);
}
Copy the code

Write a printf(), print a string, and you’re done

Example: calling OC in a C++ environment

First we need to build a C++ environment

--AntiCppObject.h

#include <iostream>

class AntiCppObject
{

public:
    AntiCppObject();
    void ExampleMethod(const std: :string& str){};
    // constructor, destructor, other members, etc.
};


--AntiCppObject.cpp

#include "AntiCppObject.h"

AntiCppObject::AntiCppObject()
{
    
}
Copy the code

And then we’re going to create an OC class and plug it into C++, and I’m not going to fill out my m file, just write an NSLog

--AntiOcObject.h

#import <Foundation/Foundation.h>

@interface AntiOcObject : NSObject

- (void)function;

@end
Copy the code

Now we are going to plug into the C++ environment. Change CPP to.mm file, no problem

Then modify the header file

--AntiCppObject.h
#import "AntiOcObject.h"
class AntiCppObject
{
    AntiOcObject* AntiOc;
public:
    AntiCppObject();
    void ExampleMethod(const std: :string& str){};
    // constructor, destructor, other members, etc.
};
Copy the code

Now, after the example I just did, you should immediately think, this is not right, header files can’t be mixed, they’ll get an error. So how do you do that?

So we’re going to do the same thing, we’re going to either void star, or we’re going to try to put our definition in a.mm file, as usual, we’re going to put a structure in.h, hide that oc object, and declare it in a.mm file

--AntiCppObject.h

#include <iostream>
struct sthStruct;
class AntiCppObject
{
    sthStruct* sth;
public:
    AntiCppObject();
    void function(a);
    // constructor, destructor, other members, etc.
};

---AntiCppObject.cpp

#include "AntiCppObject.h"
#import "AntiOcObject.h"

struct sthStruct
{
    AntiOcObject* oc;
};

AntiCppObject::AntiCppObject()
{
    AntiOcObject* t =[[AntiOcObject alloc]init];
    sth = new sthStruct;
    sth->oc = t;
}

void AntiCppObject::function()
{
    [this->sth->oc function];
}
Copy the code

You see, this implements calling OC in C++

ObjectiveC++ mixed editing precautions

  • Simply rename the. M file to a. Mm file to tell the compiler that this file can be mixed – ObjectiveC++
  • If you have two languages in a project, try to keep them as separate as possible. Although you can rename all the files in one go, the two languages are still very different, confusing and difficult to deal with
  • Header file has no suffix change, no. Hh file ^_^. So we want to keep the header clean, move the mixed code out of the header file into the MM file, and make sure that the header file is either pure C++ or pure OC (of course, C is absolutely fine).
  • Objective-c is fully compatible with C, as is C++, and can sometimes be used flexiblyvoid *Pointers, acting as Bridges, pass back and forth between the two environments (not shown in the above example)

Be careful with your memory

  • According to the previous principle, C++ and OC should be separated as far as possible, and each should maintain its own memory in its own independent area. Objective-c can be ARC or MRC, and C++ developers can manage memory by themselves
  • New and delete C++ classes in init and dealloc in the.mm file
  • In the.mm file, init and release operations are performed in the C++ environment constructors and destructors
--OcObject.mm
-(id)init
{
    self = [super init];
    if (self) {
        wrapped = new CppObject();
    }
    return self;
}

-(void)dealloc
{
    delete wrapped;
}

--AntiCppObject.mm
AntiCppObject::AntiCppObject()
{
    AntiOcObject* t =[[AntiOcObject alloc]init];
    sth = new sthStruct;
    sth->oc = t;
}

AntiCppObject::~AntiCppObject()
{
    if(sth) { [sth->oc release]; } delete STH; }Copy the code

What does this example tell us?

If it is created by OC, its memory will naturally be managed by OC. If it is MRC, please use Release. If it is ARC, as long as it is empty, it will automatically be released

If we use the C++ method to create the new constructor, we need to manually use the destructor to release it

A lot of things work the same way

  • When we use CF function in iOS development, if you use CFCreateXX, you must manually call CFRlease
  • When we write C++, those using malloc must be free by themselves, and those using new must be delete by themselves

Id the use of

In the example above, I mentioned void star a lot but didn’t elaborate on it, the magic should come last

So let’s start with this very special thing called ID

In the second example, we used a struct to hide the OC code in a.mm file, so can we not use the struct? Of course I can

--AntiCppObject.h
#include <iostream>
struct sthStruct;
class AntiCppObject
{
    id sthoc;
    sthStruct* sth;
public:
    AntiCppObject();
    ~AntiCppObject();
    void function(a); // constructor, destructor, other members, etc. }; --AntiCppObject.cpp#include "AntiCppObject.h"
#import "AntiOcObject.h"

struct sthStruct
{
    AntiOcObject* oc;
};

AntiCppObject::AntiCppObject()
{
    AntiOcObject* t =[[AntiOcObject alloc]init];
    sth = new sthStruct;
    sth->oc = t;
    
    sthoc = [[AntiOcObject alloc]init];
}

AntiCppObject::~AntiCppObject()
{
    if (sth) {
        [sth->oc release];
        
        [sthoc release];
    }
    delete sth;
}

void AntiCppObject::function()
{
    [this->sth->oc function];
    [this->sthoc function];
}
Copy the code

So you can see in this case, the struct is still there, the old scheme is still there, but we put an id in the header file, and the xcode compiler doesn’t know the oc object in the.h file that’s all C++ code, but it does know the id, and we use that id, You can hide oc object declarations without struct

The magic void star

We can write an oc object that can hold a void star, we can write C++ that can hold a void star, or we can write static C code that doesn’t have any objects, and we can also store a void star object in a global control. Can be flexibly combined into a variety of mixed use

What is void star? Pointer is the most original form, we can use it a variety of fancy OC and C++ mix

The only thing that needs to be noted is the conversion of id(oc object) to void *. Arc has memory management, and C++ does not. How does memory management automatically free up when both are going around? (NO special processing is required for the conversion of MRC)

Therefore, Arc conversions between the two are often accompanied by some strong key

  • __bridge
  • __bridge_retained
  • __bridge_transfer

The search id and void * conversions are self-referable and are common in iOS core Fundation development. The simplest way to put it is that BridgereAssumes ownership of the memory under fire both from the original object and the modified object (reatain the modified object only once) and bridgeTransfer assumes complete ownership of the memory under fire. The object before release)

I’m going to post a little code here, and this code is just to show you how to use it, so it might be a little bit convoluted by design, and a little bit of bullshit, just to show you how to mix it up

--TrickInterface.h
typedef void (*interface)(void* caller, void *parameter);



--TrickOC.h
#import <Foundation/Foundation.h>
#import "TrickInterface.h"

@interface TrickOC : NSObject
{
    int abc;
}

-(int)dosthing:(void*)param;
@property interface call;
@end

--TrickOC.m
#import "TrickOC.h"
#import "TrickInterface.h"

void MyObjectDoSomethingWith(void * obj, void *aParameter)
{
    [(__bridge id) obj dosthing:aParameter];
}

@implementation TrickOC

-(id)init
{
    self = [super init];
    if (self) {
        self.call = MyObjectDoSomethingWith;
    }
    return self;
}

-(int)dosthing:(void *)param
{
    NSLog(@"111111");
    return 0;
}

@end

--TrickCpp.cpp
#include "TrickCpp.h"
#include "TrickInterface.h"

TrickCpp::TrickCpp(void* oc,interface call)
{
    myoc = oc;
    mycall = call;
}

void TrickCpp::function()
{
    mycall(myoc,NULL);
}

--TrickCpp.h
#include <iostream>
#include "TrickInterface.h"
class TrickCpp
{
    void* myoc;
    interface mycall;
public:
    TrickCpp();
    TrickCpp(void* oc,interface call);
    ~TrickCpp();
    void function(a); // constructor, destructor, other members, etc. }; Example TrickOC* TrickOC = [[TrickOC alloc]init]; void* pointer = (__bridge void*)trickoc; TrickCpp * trick = new TrickCpp(pointer,trickoc.call); trick->function(a);Copy the code

This code first declares a global cfunctioninterface in the global region. The name of the interface is intended to be used as a C++ channel through which all C++ callback ocs communicate

In TrickOc. M file also realized that a global cfunctionMyObjectDoSomethingWith, this is our interface channel cfunction entities

When TrickCpp is created, both the created TrickOc and the cfunction are passed in. When Cpp calls Oc, the cFunction and TrickOc objects are used directly

  • In line with the code as far as possible to isolate the two languages to avoid the development of confusion and difficulties, sometimes need some design, such as C++ do tripartite library in an OC environment for use, OC needs to call any C++ various interfaces and objects, but do not want to tripartite library directly reference OC header file, hope tripartite library decouple, Communicate only through fixed callbacks or protocols
  • This demo code is just a deliberate design, in order to show the deliberate, real development needs to be designed according to their own situation

reference

Blog.csdn.net/weiwangchao…

www.philjordan.eu/article/mix…

Bbs.9ria.com/thread-2297…