阅读 545

iOS 获取SSID不成功引起的内存泄露

定位内存泄露的时候发现CNCopyCurrentNetworkInfo有内存泄露,而且只有返回值是空的时候才会有,这就很奇怪。这里就有两个问题:获取SSID不成功?为什么有内存泄露?

为什么获取SSID不成功?

其实一开始我也是一顿搜索,后面发现答案就在CNCopyCurrentNetworkInfo头文件里面,来看看头文件里面写了啥

/*!
 @function CNCopyCurrentNetworkInfo
 @discussion Returns the network information for the specified interface when the requesting application meets one of following 4 requirements -.
	1. application is using CoreLocation API and has the user's authorization to access location.
	2. application has used the NEHotspotConfiguration API to configure the current Wi-Fi network.
	3. application has active VPN configurations installed.
	4. application has active NEDNSSettingsManager configurations installed.

	- An application that is linked against iOS 12.0 SDK and above must have the "com.apple.developer.networking.wifi-info" entitlement.
	- An application will receive a pseudo network information if it is linked against an SDK before iOS 13.0, and if it fails to meet any of the
	  above requirements.
	- An application will receive NULL if it is linked against iOS 13.0 SDK (or newer), and if it fails to meet any of the above requirements.
	- On Mac Catalyst platform, to receive current Wi-Fi network information, an application must have "com.apple.developer.networking.wifi-info"
	 entitlement and user's authorization to access location.

	Network Information dictionary will contain the following keys, and values:
	<pre>
	@textblock
	Keys                      : Values
	=======================================
	kCNNetworkInfoKeySSIDData : CFDataRef
	kCNNetworkInfoKeySSID     : CFStringRef
	kCNNetworkInfoKeyBSSID    : CFStringRef
	@/textblock
	</pre>

	Pseudo network information will contain "Wi-Fi" SSID and "00:00:00:00:00:00" BSSID. For China region, the SSID will be "WLAN".
 @param interfaceName Name of the interface you are interested in
 @result Network Information dictionary associated with the interface.
	 Returns NULL if an error was encountered.
	 You MUST release the returned value.
 */
CFDictionaryRef __nullable
CNCopyCurrentNetworkInfo	(CFStringRef	interfaceName)
API_DEPRECATED_WITH_REPLACEMENT("[NEHotspotNetwork fetchCurrentWithCompletionHandler:]", ios(4.1, API_TO_BE_DEPRECATED), macCatalyst(14.0, API_TO_BE_DEPRECATED))
API_UNAVAILABLE(macos, tvos, watchos);
复制代码

获取wifi信息的必要条件:

  • 大于等于iOS12,必须要在entitlement中配置com.apple.developer.networking.wifi-info,值为YES。等价于在Capability添加Access WiFi Infomation

  • 小于等于iOS13,必须要满足四个条件其一。

    • 用户同意获取地址权限
    • NEHotspotConfiguration API配置过的Wi-Fi (没试过)
    • 安装过VPN configurations(没试过)
    • 安装过NEDNSSettingsManager configurations(没试过)
  • 大于等于iOS14,可以使用新的API [NEHotspotNetwork fetchCurrentWithCompletionHandler:]

经过这些设置,Wifi信息应该可以获取到了,内存泄露也没有了。

为什么会有内存泄露?

先上获取SSID的代码

+ (NSString *_Nullable)getDeviceSSID
{
    NSString *wifiName = nil;
    CFArrayRef wifiInterfaces = CNCopySupportedInterfaces();
    if (!wifiInterfaces) {
        return nil;
    }
    NSArray *interfaces = (__bridge NSArray *)wifiInterfaces;
    for (NSString *interfaceName in interfaces) {
        CFDictionaryRef dictRef = CNCopyCurrentNetworkInfo((__bridge CFStringRef)(interfaceName));
        if (dictRef) {
            NSDictionary *networkInfo = (__bridge NSDictionary *)dictRef;
            wifiName = [networkInfo objectForKey:(__bridge NSString *)kCNNetworkInfoKeySSID];
            CFRelease(dictRef);
            break;
        }
    }
    CFRelease(wifiInterfaces);
    return wifiName;
}
复制代码

如果wifiInterfaces为nil,那么就没有办法释放,而CNCopySupportedInterfaces的返回值是一定要释放的。

文章分类
iOS
文章标签