60187


SwiftでIPアドレスを取得する方法を調べています。  
<https://codeday.me/jp/qa/20190128/177808.html>  
上記の記事によると、以下のようにコードを書くとIPアドレスが取得できるようなのですが

「＃include< ifaddrs.h>を”ブリッジングヘッダ”に記述してください」とあります。

[code]

    // Return IP address of WiFi interface (en0) as a String, or `nil`
    func getWiFiAddress() -> String? {
        var address : String?
    
        // Get list of all interfaces on the local machine:
        var ifaddr : UnsafeMutablePointer<ifaddrs>?
        guard getifaddrs(&ifaddr) == 0 else { return nil }
        guard let firstAddr = ifaddr else { return nil }
    
        // For each interface ...
        for ifptr in sequence(first: firstAddr, next: { $0.pointee.ifa_next }) {
            let interface = ifptr.pointee
    
            // Check for IPv4 or IPv6 interface:
            let addrFamily = interface.ifa_addr.pointee.sa_family
            if addrFamily == UInt8(AF_INET) || addrFamily == UInt8(AF_INET6) {
    
                // Check interface name:
                let name = String(cString: interface.ifa_name)
                if  name == "en0" {
    
                    // Convert interface address to a human readable string:
                    var addr = interface.ifa_addr.pointee
                    var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
                    getnameinfo(&addr, socklen_t(interface.ifa_addr.pointee.sa_len),
                                &hostname, socklen_t(hostname.count),
                                nil, socklen_t(0), NI_NUMERICHOST)
                    address = String(cString: hostname)
                }
            }
        }
        freeifaddrs(ifaddr)
    
        return address
    }
    
[/code]

ブリッジングヘッダについて調べると、「SwiftからObjective-
Cを呼び出すときに使用する」ものと出てくるのですが、このプログラムの場合、「import
ifaddrs」とswift側に書くだけじゃダメなのでしょうか？必ずブリッジングヘッダを通してifaddrsを読み込まないといけないのでしょうか？


CC BY-SA 4.0
2019-11-01T10:18:42.910
60182
2019-11-01T12:39:44.567
22541
question
swift ios objective-c
Swift IPアドレスの取得方法とブリッジングヘッダについて


**_ブリッジングヘッダについて調べると、「SwiftからObjective-Cを呼び出すときに使用する」ものと出てくる_**

ブリッジングヘッダが導入された本来の目的は「Objective-Cを呼び出す」ことでしょうが、Objective-
CコンパイラはCコンパイラの完全上位互換を目指して作られているので、「C言語で書かれたライブラリを呼び出す」ためにも使われます。

**_このプログラムの場合、「import ifaddrs」とswift側に書くだけじゃダメなのでしょうか？_**

ダメです。

`import
ifaddrs`という記述が可能になるのは、「Swiftコンパイラに`ifaddrs`という名称のモジュール(*)が見えている時だけ」です。iOSやmacOSのSDKには、`ifaddrs`という名称のモジュールは提供されていませんので、(あなたがサードパーティ製の`ifaddrs`という名称のモジュールをインストールしていない限り)`import
ifaddrs`という記述はエラーになります。

(*)この場合の「モジュール」と言うのは一般的な意味ではなく、Apple製開発環境に特有の概念です。Appleの規定した「モジュール」のお約束通りにパッケージングされたライブラリだけが、モジュールとして`import`できます。もちろん`ifaddrs.h`なんてファイルがどこかにある、と言うだけでは、それをモジュールとして扱ってはくれません。

**_必ずブリッジングヘッダを通してifaddrsを読み込まないといけないのでしょうか？_**

そうとは限りません。iOS
SDKに含まれるどれかのモジュールの中に`ifaddrs.h`相当の内容が含まれていれば、そのモジュールを`import`してやれば使えます。

iOSやmacOSのSDKにはDarwinと言うモジュールがあり、その中には標準Cライブラリの多くが含まれています。こちらのXcode
11.1で試したところ、以下のファイルは、ブリッジングヘッダーを使わずとも問題なくコンパイルできました。

getWiFiAddress.swift:

[code]

    import Darwin
    
    func getWiFiAddress() -> String? {
        var address : String?
    
        // Get list of all interfaces on the local machine:
        var ifaddr : UnsafeMutablePointer<ifaddrs>?
        guard getifaddrs(&ifaddr) == 0 else { return nil }
        guard let firstAddr = ifaddr else { return nil }
    
        // For each interface ...
        for ifptr in sequence(first: firstAddr, next: { $0.pointee.ifa_next }) {
            let interface = ifptr.pointee
    
            // Check for IPv4 or IPv6 interface:
            let addrFamily = interface.ifa_addr.pointee.sa_family
            if addrFamily == UInt8(AF_INET) || addrFamily == UInt8(AF_INET6) {
    
                // Check interface name:
                let name = String(cString: interface.ifa_name)
                if  name == "en0" {
    
                    // Convert interface address to a human readable string:
                    var addr = interface.ifa_addr.pointee
                    var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
                    getnameinfo(&addr, socklen_t(interface.ifa_addr.pointee.sa_len),
                                &hostname, socklen_t(hostname.count),
                                nil, socklen_t(0), NI_NUMERICHOST)
                    address = String(cString: hostname)
                }
            }
        }
        freeifaddrs(ifaddr)
    
        return address
    }
    
[/code]

※ちなみに、`Darwin`と言うモジュールは`Foundation`や`UIKit`のサブモジュールとなっているので、上の`import
Darwin`を`import Foundation`とか`import UIKit`に置き換えてもコンパイルできます。

* * *

なお、SandBox環境では、標準Cライブラリの関数やUnix
APIは、本来の動作とは異なる動作をする場合があります。Appleはそこら辺の詳細をドキュメント化してくれていないので、このような関数を使用する場合は、ターゲットバージョンの実デバイスを使用して動作確認しておくことをお勧めします。

(iOSがバージョンアップすると突然使えなくなる、なんて可能性もあります。)


CC BY-SA 4.0
2019-11-01T12:39:44.567
60187
2019-11-01T12:39:44.567
13972
60182
answer