djinni 创建的 objective-c 协议无效
djinni created objective-c protocol not working
我正在使用 djinni 在 c++、java 和 objective c 之间创建跨平台代码,因为我目前正在将大量代码移动到跨平台 c++ 实现。
问题是,我有一个接口是 objective c 中的协议。在 c++ 中实现的另一个接口获取此协议的 hte 实现作为参数,然后调用该方法。但是在objective c中根本没有调用这个方法。 (更好 swift,但我也尝试在 objective c 中实现此协议,但不起作用)。我调查了更多,但首先是我的代码。
为了查看我的问题是否由现有代码引起,我创建了一个测试项目,但它仍然是这样:
这是我的 djinni idl 文件:
DataProvider = interface +j +o {
const getContentForUrl(url: string): string;
}
DataUser = interface +c {
static create(url: string, dataProvider: DataProvider): DataUser;
getContent(): string;
}
这是创建的 c++ 文件:
DataProvider.hpp:
// AUTOGENERATED FILE - DO NOT MODIFY!
// This file generated by Djinni from htmlparser.djinni
#pragma once
#include <string>
namespace testdjinni {
class DataProvider {
public:
virtual ~DataProvider() {}
virtual std::string getContentForUrl(const std::string & url) = 0;
};
} // namespace testdjinni
DataUser.hpp:
// AUTOGENERATED FILE - DO NOT MODIFY!
// This file generated by Djinni from htmlparser.djinni
#pragma once
#include <memory>
#include <string>
#include <vector>
namespace testdjinni {
class DataProvider;
class DataUser {
public:
virtual ~DataUser() {}
static std::shared_ptr<DataUser> create(const std::string & url, const std::shared_ptr<DataProvider> & dataProvider);
virtual std::string getContent() = 0;
};
} // namespace destdjinni
这是我的 DataUser
接口和 C++ 实现:
DataUserImpl.h:
#ifndef TESTDJINNI_DATAUSER_H
#define TESTDJINNI_DATAUSER_H
#include <string>
#include "generated-src/cpp/DataUser.hpp"
using namespace std;
class DataUserImpl : public testdjinni::DataUser{
private:
string *content;
testdjinni::DataUser *dataUser;
public:
DataUserImpl(const string &url, testdjinni::DataProvider *dataProvider);
virtual string getContent();
};
#endif //TESTDJINNI_DATAUSER
DataUserImpl.cpp:
#include <iostream>
#include "DataUserImpl.h"
#include "generated-src/cpp/DataProvider.hpp"
DataUserImpl::DataUserImpl(const string &url, testdjinni::DataProvider *dataProvider): dataProvider(dataProvider) {
this->url = new string(url);
}
HtmlDocumentImpl::~HtmlDocumentImpl() {
delete url;
}
std::shared_ptr<testdjinni::DataUser> testdjinni::DataUser::create(const std::string & url, const std::shared_ptr<testdjinni::DataProvider> & dataProvider) {
return std::shared_ptr<testdjinni::DataUser>(new DataUserImpl(url, dataProvider.get()));
}
string DataUserImpl::getContent() {
if (this->content == NULL || *this->content == "")
this->content = new string(this->getDataProvider()->getContentForUrl(*this->url));
return *this->content;
};
现在我在 swift 中有了这段代码(我也在 Objective C 中尝试了相同的代码,但没有成功):
class Provider: HPDataProvider {
func getContentForUrl(_ url: String) -> String {
return "Testcontent und so"
}
}
class ViewController: UIViewController {
let provider = Provider()
override func viewDidLoad() {
super.viewDidLoad()
let user = HPDataUser.create("http://www.testurl.com", dataProvider: provider)
print(user?.getContent())
}
}
问题是,实现的协议中的方法 getContentForUrl
根本没有被调用。我崩溃了:
Assertion failed: (string), function toCpp, file /Path/to/my/project/deps/djinni/support-lib/objc/DJIMarshal+Private.h, line 119.
所以我现在可以说的是,字符串似乎是 null
而我的协议实现没有被调用。
好的,所以我下来看看到底发生了什么:
在为 DataProvider+Private.mm
生成的文件中,如下所示:
// AUTOGENERATED FILE - DO NOT MODIFY!
// This file generated by Djinni from htmlparser.djinni
#import "HPDataProvider+Private.h"
#import "HPDataProvider.h"
#import "DJIMarshal+Private.h"
#import "DJIObjcWrapperCache+Private.h"
#include <stdexcept>
static_assert(__has_feature(objc_arc), "Djinni requires ARC to be enabled for this file");
namespace djinni_generated {
class DataProvider::ObjcProxy final
: public ::htmlparser::DataProvider
, private ::djinni::ObjcProxyBase<ObjcType>
{
friend class ::djinni_generated::DataProvider;
public:
using ObjcProxyBase::ObjcProxyBase;
std::string getContentForUrl(const std::string & c_url) override
{
@autoreleasepool {
// Here, the objcpp_result is null, even if the object was not null, but my implementation of the protocol was never called.
auto objcpp_result_ = [djinni_private_get_proxied_objc_object() getContentForUrl:(::djinni::String::fromCpp(c_url))];
return ::djinni::String::toCpp(objcpp_result_);
}
}
};
} // namespace djinni_generated
namespace djinni_generated {
auto DataProvider::toCpp(ObjcType objc) -> CppType
{
if (!objc) {
return nullptr;
}
return ::djinni::get_objc_proxy<ObjcProxy>(objc);
}
auto DataProvider::fromCppOpt(const CppOptType& cpp) -> ObjcType
{
if (!cpp) {
return nil;
}
return dynamic_cast<ObjcProxy&>(*cpp).djinni_private_get_proxied_objc_object();
}
} // namespace djinni_generated
我不知道我能在这里做什么...我的意思是,这只是基本代码...
您遇到的错误是由于 shared_ptr.
使用不当造成的
std::shared_ptr<testdjinni::DataUser> testdjinni::DataUser::create(const std::string & url, const std::shared_ptr<testdjinni::DataProvider> & dataProvider) {
return std::shared_ptr<testdjinni::DataUser>(new DataUserImpl(url, dataProvider.get()));
}
您将 DataProvider 原始指针 (dataProvider.get()) 传递给 DataUserImpl。当所有持有它的 shared_ptr 都将消失时,你用原始指针指向的对象将被销毁。
由于您没有在任何地方保存 shared_ptr,所以随着它的结束,您的 DataProvider 对象也被破坏并且您指向无效的内存。
解决方案是将 shared_ptr 保存为 DataUserImpl 的字段而不是原始指针。这样,您的对象的生命周期将延长到 DataUserImpl 的生命周期。
我正在使用 djinni 在 c++、java 和 objective c 之间创建跨平台代码,因为我目前正在将大量代码移动到跨平台 c++ 实现。
问题是,我有一个接口是 objective c 中的协议。在 c++ 中实现的另一个接口获取此协议的 hte 实现作为参数,然后调用该方法。但是在objective c中根本没有调用这个方法。 (更好 swift,但我也尝试在 objective c 中实现此协议,但不起作用)。我调查了更多,但首先是我的代码。
为了查看我的问题是否由现有代码引起,我创建了一个测试项目,但它仍然是这样:
这是我的 djinni idl 文件:
DataProvider = interface +j +o {
const getContentForUrl(url: string): string;
}
DataUser = interface +c {
static create(url: string, dataProvider: DataProvider): DataUser;
getContent(): string;
}
这是创建的 c++ 文件:
DataProvider.hpp:
// AUTOGENERATED FILE - DO NOT MODIFY!
// This file generated by Djinni from htmlparser.djinni
#pragma once
#include <string>
namespace testdjinni {
class DataProvider {
public:
virtual ~DataProvider() {}
virtual std::string getContentForUrl(const std::string & url) = 0;
};
} // namespace testdjinni
DataUser.hpp:
// AUTOGENERATED FILE - DO NOT MODIFY!
// This file generated by Djinni from htmlparser.djinni
#pragma once
#include <memory>
#include <string>
#include <vector>
namespace testdjinni {
class DataProvider;
class DataUser {
public:
virtual ~DataUser() {}
static std::shared_ptr<DataUser> create(const std::string & url, const std::shared_ptr<DataProvider> & dataProvider);
virtual std::string getContent() = 0;
};
} // namespace destdjinni
这是我的 DataUser
接口和 C++ 实现:
DataUserImpl.h:
#ifndef TESTDJINNI_DATAUSER_H
#define TESTDJINNI_DATAUSER_H
#include <string>
#include "generated-src/cpp/DataUser.hpp"
using namespace std;
class DataUserImpl : public testdjinni::DataUser{
private:
string *content;
testdjinni::DataUser *dataUser;
public:
DataUserImpl(const string &url, testdjinni::DataProvider *dataProvider);
virtual string getContent();
};
#endif //TESTDJINNI_DATAUSER
DataUserImpl.cpp:
#include <iostream>
#include "DataUserImpl.h"
#include "generated-src/cpp/DataProvider.hpp"
DataUserImpl::DataUserImpl(const string &url, testdjinni::DataProvider *dataProvider): dataProvider(dataProvider) {
this->url = new string(url);
}
HtmlDocumentImpl::~HtmlDocumentImpl() {
delete url;
}
std::shared_ptr<testdjinni::DataUser> testdjinni::DataUser::create(const std::string & url, const std::shared_ptr<testdjinni::DataProvider> & dataProvider) {
return std::shared_ptr<testdjinni::DataUser>(new DataUserImpl(url, dataProvider.get()));
}
string DataUserImpl::getContent() {
if (this->content == NULL || *this->content == "")
this->content = new string(this->getDataProvider()->getContentForUrl(*this->url));
return *this->content;
};
现在我在 swift 中有了这段代码(我也在 Objective C 中尝试了相同的代码,但没有成功):
class Provider: HPDataProvider {
func getContentForUrl(_ url: String) -> String {
return "Testcontent und so"
}
}
class ViewController: UIViewController {
let provider = Provider()
override func viewDidLoad() {
super.viewDidLoad()
let user = HPDataUser.create("http://www.testurl.com", dataProvider: provider)
print(user?.getContent())
}
}
问题是,实现的协议中的方法 getContentForUrl
根本没有被调用。我崩溃了:
Assertion failed: (string), function toCpp, file /Path/to/my/project/deps/djinni/support-lib/objc/DJIMarshal+Private.h, line 119.
所以我现在可以说的是,字符串似乎是 null
而我的协议实现没有被调用。
好的,所以我下来看看到底发生了什么:
在为 DataProvider+Private.mm
生成的文件中,如下所示:
// AUTOGENERATED FILE - DO NOT MODIFY!
// This file generated by Djinni from htmlparser.djinni
#import "HPDataProvider+Private.h"
#import "HPDataProvider.h"
#import "DJIMarshal+Private.h"
#import "DJIObjcWrapperCache+Private.h"
#include <stdexcept>
static_assert(__has_feature(objc_arc), "Djinni requires ARC to be enabled for this file");
namespace djinni_generated {
class DataProvider::ObjcProxy final
: public ::htmlparser::DataProvider
, private ::djinni::ObjcProxyBase<ObjcType>
{
friend class ::djinni_generated::DataProvider;
public:
using ObjcProxyBase::ObjcProxyBase;
std::string getContentForUrl(const std::string & c_url) override
{
@autoreleasepool {
// Here, the objcpp_result is null, even if the object was not null, but my implementation of the protocol was never called.
auto objcpp_result_ = [djinni_private_get_proxied_objc_object() getContentForUrl:(::djinni::String::fromCpp(c_url))];
return ::djinni::String::toCpp(objcpp_result_);
}
}
};
} // namespace djinni_generated
namespace djinni_generated {
auto DataProvider::toCpp(ObjcType objc) -> CppType
{
if (!objc) {
return nullptr;
}
return ::djinni::get_objc_proxy<ObjcProxy>(objc);
}
auto DataProvider::fromCppOpt(const CppOptType& cpp) -> ObjcType
{
if (!cpp) {
return nil;
}
return dynamic_cast<ObjcProxy&>(*cpp).djinni_private_get_proxied_objc_object();
}
} // namespace djinni_generated
我不知道我能在这里做什么...我的意思是,这只是基本代码...
您遇到的错误是由于 shared_ptr.
使用不当造成的std::shared_ptr<testdjinni::DataUser> testdjinni::DataUser::create(const std::string & url, const std::shared_ptr<testdjinni::DataProvider> & dataProvider) {
return std::shared_ptr<testdjinni::DataUser>(new DataUserImpl(url, dataProvider.get()));
}
您将 DataProvider 原始指针 (dataProvider.get()) 传递给 DataUserImpl。当所有持有它的 shared_ptr 都将消失时,你用原始指针指向的对象将被销毁。
由于您没有在任何地方保存 shared_ptr,所以随着它的结束,您的 DataProvider 对象也被破坏并且您指向无效的内存。
解决方案是将 shared_ptr 保存为 DataUserImpl 的字段而不是原始指针。这样,您的对象的生命周期将延长到 DataUserImpl 的生命周期。