我仍然对 ARC、桥接和某些非免费桥接 CF 对象感到有些困惑。我目前的困惑是围绕 CFSocket。我很确定我清理得正确,但分析工具告诉我不然。也许我的不和谐让我看不到泄漏,或者工具是错误的。我还没准备好责怪这个工具,所以我正在寻找其他人来指出这个问题。例如,我是否缺少__bridge
将所有权转让给我的形式?
在我的项目中,使用 ARC,我有一个基于 TCP 的服务器。我们称这个类为“MyServer”。在 MyServer 中,我有一个内部属性 socket,定义如下:
@property (assign) CFSocketRef socket;
此属性在服务器运行时保存套接字引用。停止服务器将释放引用,删除服务器对象也是如此。我也在尝试清理在启动服务器过程中产生的任何潜在泄漏。正是在这个领域,我遇到了静态分析问题。
使用此方法启动服务器:
- (BOOL)startServer
{
BOOL started = NO;
NSLog(@"[%@ %@] starting server on port %u", NSStringFromClass([self class]), NSStringFromSelector(_cmd),self.port);
self.lastError = nil;
if ([self createSocket]) {
started = YES;
_state = SERVER_STATE_STARTING;
};
return started;
}
该createSocket
方法创建一个套接字(duh),如下所示:
-(BOOL)createSocket
{
BOOL result = YES;
self.socket = CFSocketCreate(kCFAllocatorDefault, PF_INET, SOCK_STREAM,
IPPROTO_TCP, 0, NULL, NULL);
if (self.socket != NULL) {
int reuse = true;
int fileDescriptor = CFSocketGetNative(self.socket);
if (setsockopt(fileDescriptor, SOL_SOCKET, SO_REUSEADDR,
(void *)&reuse, sizeof(int)) == 0) {
struct sockaddr_in address;
memset(&address, 0, sizeof(address));
address.sin_len = sizeof(address);
address.sin_family = AF_INET;
address.sin_addr.s_addr = htonl(INADDR_ANY);
address.sin_port = htons(self.port);
CFDataRef addressData = CFDataCreate(NULL,
(const UInt8 *)&address,
sizeof(address));
if (addressData && CFSocketSetAddress(self.socket, addressData) == kCFSocketSuccess) {
self.listenHandle = [[NSFileHandle alloc] initWithFileDescriptor:fileDescriptor
closeOnDealloc:YES];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(receiveIncomingConnectionNotification:)
name:NSFileHandleConnectionAcceptedNotification
object:nil];
[self.listenHandle acceptConnectionInBackgroundAndNotify];
_state = SERVER_STATE_RUNNING;
} else {
result = NO;
[self errorWithName:@"Unable to bind socket to address."];
}
CFRelease(addressData);
} else {
[self errorWithName:@"Unable to set socket options."];
CFRelease(self.socket);
CFSocketInvalidate(self.socket);
CFRelease(self.socket);
self.socket = nil;
result = NO;
}
} else {
[self errorWithName:@"Unable to create socket."];
// CFRelease(self.socket); //NO - CFRelease(NULL) is a runtime error!
result = NO;
}
return result;
}
当我对此代码运行静态分析时,Xcode 报告了 self.socket 周围的大量潜在泄漏。这是一个示例,来自上述createSocket
方法:
确实,我不再在此路径中引用该对象。也许有某种方法可以告诉系统我想要拥有该对象,而它抱怨的原因是它无法告诉我拥有该对象。我应该使用其中一个__bridge
演员来传达该信息吗?我尝试使属性保持或强大,但这并没有建立,因为它不是一个对象。还有其他想法吗?