将 UnsafeMutablePointer 传递给函数时出错
Posted
技术标签:
【中文标题】将 UnsafeMutablePointer 传递给函数时出错【英文标题】:Error passing an UnsafeMutablePointer to a function 【发布时间】:2017-07-26 10:28:31 【问题描述】:我是一名使用 swift 的 ios 开发人员。 我正在使用 sdk 与 ip camera 通信,从中检索数据,并将其显示给用户。 我有一个随 sdk 一起提供的项目,它是用 obj c 编写的,并且可以正常工作。问题是我无法将参数从函数传递给预期的参数类型。 SDK 非常旧,我使用静态库和桥接头集成它,我能够成功连接到相机。我认为sdk是用c或c++编写的,我基本上在参数转换方面遇到了问题。
Fos.h
typedef struct
int channel;
long long time;
unsigned int index;
FOSMEDIATYPE type; //Is video or audio
FOSDECFMT fmt; //The format of video or audio.
short isKey;
short multiAudioPage;
int frameTag;
union
FOSVIDEO_INFO video; //Media type is video.
FOSAUDIO_INFO audio; //Media type is audio.
media;
unsigned long long pts; //Pts.
unsigned int len; //Size of data.
char data[0]; //Just data.
ATTRIBUTE_PACKED FOSDEC_DATA; //Save the video or audio data,include video or audio information.
.
Objective C 函数,当前工作
- (IBAction)login:(id)sender
//[self._imageView add]
NSString* str = [self._textField text];
const char* url = [str UTF8String];
char ip[128];
int port;
char usr[64];
char pwd[64];
int count = sscanf(url, "%[^:]:%d/%[^:]:%s", ip, &port, usr, pwd);
if (count != 4)
return;
mHandle = FosSdk_Create(ip, "", usr, pwd, port, port, FOSIPC_H264, FOSCNTYPE_IP);
//mHandle = FosSdk_Create(ip, "FASDFDSAFDASFASD", usr, pwd, port, port, FOSIPC_H264, FOSCNTYPE_P2P);
if (mHandle == FOSHANDLE_INVALID)
return;
[self._Login setEnabled:NO];
[self._Logout setEnabled:YES];
[NSThread detachNewThreadSelector:@selector(RunInThread:) toTarget:self withObject:^(void *param)
int usrPrivilege = 0;
FOSCMD_RESULT ret = FosSdk_Login(mHandle, &usrPrivilege, 500);
if (FOSCMDRET_OK != ret)
return;
ret = FosSdk_OpenVideo(mHandle, FOSSTREAM_SUB, 500);
if (FOSCMDRET_OK != ret)
return;
//char* framebuf = (char*)malloc(512*1024);
FOSDEC_DATA* data = NULL;
int outlen = 0;
while (mHandle)
// FosSdk_RetainHandle(mHandle, &usrPrivilege);
if ( FOSCMDRET_OK == FosSdk_GetVideoData(mHandle, (char**)&data, &outlen, FOSDECTYPE_RGB24) && outlen>0)
if (data->type == FOSMEDIATYPE_VIDEO)
//int a=0;
//a++;
[self imageFromAVPicture:data->data width:data->media.video.picWidth height:data->media.video.picHeight];
else
usleep(20*1000);
];
.
fos.h中的方法签名
FOSSDK FOSCMD_RESULT FOSAPI FosSdk_GetVideoData(FOSHANDLE handle, char **data, int *outLen, FOSDECFMT videoFmt);
.
从objective-c调用时
FosSdk_GetVideoData(<#unsigned int handle#>, <#char **data#>, <#int *outLen#>, <#FOSDECFMT videoFmt#>)
];
.
从 swift 调用时
FosSdk_GetVideoData(handle: UInt32,
data: UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>!,
outLen: UnsafeMutablePointer<Int32>!,
videoFmt: FOSDECFMT)
.
错误是数据参数,确切地说:
Cannot convert value of type 'UnsafeMutablePointer<FOSDEC_DATA>' to expected argument type 'UnsafeMutablePointer<Int8>?'
.
我尝试将数据声明更改为此,但它给了我这个错误
let data = UnsafeMutablePointer<Int8>(&fosdecData)
Ambiguous use of 'init'
.
这个指针有点复杂,但我能够将我的设备与相机配对,使用的方法也使用了 unsafeMutablePointers。 但是,我不知道如何将这个 empy 数据对象传递给函数。
SDK 已过时且文档不完整,这无济于事。 无论如何,我需要让它工作。 希望能得到一些帮助,谢谢码农! .
编辑,感谢 OOPer . 这是swift中的更新版本,实际上会产生意外错误。从函数返回的结果现在是 0,所以它是正确的。但是,尝试访问原始 FosdedData 结构时,我有一个 Command failed due to signal: Segmentation fault: 11。 我怎么能解决这个问题?抱歉,问题太长了,我想准确一点。
var mhandle : UInt32 = FOS_HANDLE_INIT.rawValue
override func viewDidLoad()
super.viewDidLoad()
//These functions basically do camera pairing, and write result on mhandle, which is equal to 0 , if functions work, otherwise 1
initializeFOS()
startEzLinkFOS()
sdkCreateFOS()
loginFOS()
openVideoFOS()
var data: UnsafeMutablePointer<FOSDEC_DATA>? = nil
var outlen : Int32 = 0
while self.mhandle > 0
let resultOOPer = withUnsafeMutablePointer(to: &data) pointerToFosdecData in
pointerToFosdecData.withMemoryRebound(to: UnsafeMutablePointer<Int8>?.self, capacity: 1, (pointerToInt8Pointer) in
FosSdk_GetVideoData(self.mhandle, pointerToInt8Pointer, &outlen, FOSDECTYPE_RGB24)
)
if resultOOPer == FOSCMDRET_OK && outlen > 0
if let unwrData = data
//if unwrData.pointee.type == FOSMEDIATYPE_VIDEO
//Produced Output when i try access pointee, which is actually the fosdecData struct i need:
//Command failed due to signal: Segmentation fault: 11
//
usleep(20*1000)
【问题讨论】:
【参考方案1】:首先,以这种方式使用UnsafeMutablePointer
的初始化器可能会产生意想不到的结果,你不应该这样做:
let data = UnsafeMutablePointer<FOSDEC_DATA>(&fosdecData)
Swift 编译器可能会为 inout 参数准备一个临时区域并传递该区域的地址,该地址在调用后立即释放。不幸的是,此代码在某些情况下可能有效,但您知道在某些情况下有效的代码可能是一个难以修复的错误。
其次,在您的 Objective-C 代码中,您将data
声明为FOSDEC_DATA*
-- 指向FOSDEC_DATA
的指针 -- 并将其初始化为NULL
。
您为什么要尝试使用&fosdecData
初始化您的data
Swift 版本?您的 Objective-C 代码中没有 fosdecData
。
data
声明的等效 Swift 代码应该是这样的:
var data: UnsafeMutablePointer<FOSDEC_DATA>? = nil
你应该将data
声明为UnsafeMutablePointer<FOSDEC_DATA>?
——指向FOSDEC_DATA
的指针——并将其初始化为nil
。
此外,它必须是var
,您的FosSdk_GetVideoData
会将其重写为指向FOSDEC_DATA
的有效指针。
第三,你需要将UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>!
传递给FosSdk_GetVideoData
的第二个参数,但是&data
会生成一个UnsafeMutablePointer<UnsafeMutablePointer<FOSDEC_DATA>?>
类型的指针。
要进行这种指针类型转换,您需要使用withMemoryRebound<T, Result>(to:capacity:_:)
。你需要调用withUnsafeMutablePointer<T, Result>(to:_:)
来获得指向data
的指针。
let result = withUnsafeMutablePointer(to: &data)
pointerToFosdecDataPtr in
//pointerToFosdecDataPtr: UnsafeMutablePointer<UnsafeMutablePointer<FOSDEC_DATA>?>
pointerToFosdecDataPtr.withMemoryRebound(to: UnsafeMutablePointer<Int8>?.self, capacity: 1)
pointerToInt8Ptr in
//pointerToInt8Ptr: UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>
//...
因此,您的 Swift 代码等同于您的 Objective-C 代码将是这样的:
var data: UnsafeMutablePointer<FOSDEC_DATA>? = nil
var outlen: Int32 = 0
while mHandle != 0
let result = withUnsafeMutablePointer(to: &data)
pointerToFosdecDataPtr in
//pointerToFosdecDataPtr: UnsafeMutablePointer<UnsafeMutablePointer<FOSDEC_DATA>?>
pointerToFosdecDataPtr.withMemoryRebound(to: UnsafeMutablePointer<Int8>?.self, capacity: 1)
pointerToInt8Ptr in
//pointerToInt8Ptr: UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>
FosSdk_GetVideoData(mHandle, pointerToInt8Ptr, &outlen, FOSDECTYPE_RGB24)
//Implicit `return` works here and the result is passed to `result`.
if result == FOSCMDRET_OK && outlen > 0
if let data = data, data.pointee.type == FOSMEDIATYPE_VIDEO
//...
//self.imageFromAVPicture...
else
usleep(20*1000)
编辑
更新代码以反映当前工作 Objective-C 代码的整体行为。 (在 Objective-C 代码中将 mhandle
重命名为 mHandle
。)
【讨论】:
非常感谢OOPer,这段代码让编译器很高兴,但是结果是1,在这种情况下是负数。所以函数返回一个错误。 . 另外,我注意到 data 属性为 nil,尝试访问 data.pointee 时出现错误 Command failed due to signal: Segmentation fault: 11 感谢您的报告。但我上面的代码let result = ...; if result == FOSCMDRET_OK ...
将输出与您的ObjC 代码if ( FOSCMDRET_OK == ...) ...
等效的机器代码。您是否填写了与您的 ObjC 代码等效的所有代码?例如,我的代码省略了while (mHandle) ...
,因为您没有在问题中提到该部分。但事实上,你需要它。并且通常,当 API 调用的结果返回非 OK 值时,API 不会影响指针参数指定的区域。所以,如果它返回了1
并且不正常,那么很自然data
仍然是nil
。
您没有显示mHandle
的声明方式,也没有给出值。如果您使用我的 Swift 代码得到非 OK 结果,那是因为您的 Swift 代码的其他部分是错误的。不要隐藏代码的相关部分并显示所有部分。
如果我省略了相关代码,我很抱歉。我实际工作的目标 c 函数实现(文件 .h 和 .m )和 .swift 类是否足够?如果您想看一下,我也可以将项目发送给您,这不是问题,并且是我仅为相机实现而创建的项目,因此它非常基本。感谢您的所有帮助,这是预览paste.ofcode.org/37dqy55aSbci868attH7qi3
@Simone,我已经更新了答案中的最后一个代码,这相当于您的 当前工作 Objective-C 代码。目前我能做的就这些了。如果您需要更多信息,则应在问题中包含更多信息(不要过多)。可能还有很多其他人可以解决您的问题,在问题中包含此类信息,他们无需阅读冗长的 cmets 即可回答。以上是关于将 UnsafeMutablePointer 传递给函数时出错的主要内容,如果未能解决你的问题,请参考以下文章
如何快速将自己转换为 UnsafeMutablePointer<Void> 类型
如何快速将自己转换为 UnsafeMutablePointer<Void> 类型
如何将 UnsafeMutablePointer<UnsafeMutablePointer<Int8>?> 转换为 UnsafeMutablePointer<Unsafe
取消引用 UnsafeMutablePointer<UnsafeMutableRawPointer>
Swift:无法将“UnsafeMutablePointer”类型的值转换为预期的参数类型“UnsafeMutablePointer”
如何将该 UnsafeMutablePointer<UnsafeMutablePointer<Float>> 变量转换为 AudioBufferList?