[解決済み] SwiftでSCNetworkReachabilityを使用する方法
質問
私は この のコードスニペットをSwiftに変換しようとしています。私はいくつかの困難のために軌道に乗るのに苦労しています。
- (BOOL) connectedToNetwork
{
// Create zero addy
struct sockaddr_in zeroAddress;
bzero(&zeroAddress, sizeof(zeroAddress));
zeroAddress.sin_len = sizeof(zeroAddress);
zeroAddress.sin_family = AF_INET;
// Recover reachability flags
SCNetworkReachabilityRef defaultRouteReachability = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&zeroAddress);
SCNetworkReachabilityFlags flags;
BOOL didRetrieveFlags = SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags);
CFRelease(defaultRouteReachability);
if (!didRetrieveFlags)
{
return NO;
}
BOOL isReachable = flags & kSCNetworkFlagsReachable;
BOOL needsConnection = flags & kSCNetworkFlagsConnectionRequired;
return (isReachable && !needsConnection) ? YES : NO;
}
私が抱えている最初の、そして主な問題は、C 言語の構造体をどのように定義して作業するかということです。最初の行で (
struct sockaddr_in zeroAddress;
というインスタンスを定義していると思います。
zeroAddress
を構造体sockaddr_in(?)から定義しているのだと思われます。と宣言してみたところ
var
をこのように宣言してみました。
var zeroAddress = sockaddr_in()
しかし、次のようなエラーが発生します。 呼び出し中のパラメータ 'sin_len' の引数がありません。 というエラーが出ますが、この構造体はいくつもの引数を取るので、理解できます。そこで、もう一度やってみました。
var zeroAddress = sockaddr_in(sin_len: sizeof(zeroAddress), sin_family: AF_INET, sin_port: nil, sin_addr: nil, sin_zero: nil)
予想通り、他のエラーが発生しました。 変数がそれ自身の初期値内で使用されています . このエラーの原因もわかった。C言語では、最初にインスタンスを宣言して、それからパラメータを埋めるのです。私の知る限りSwiftではありえないことです。なので、どうすればいいのか、この時点で本当に迷っています。
私はAppleの公式 ドキュメント を読みましたが、構造体を扱う例はありませんでした。
どなたか、ここで私を助けていただけませんか?私はそれを本当に感謝します。
ありがとうございます。
UPDATEです。 Martinのおかげで、最初の問題を克服することができました。しかし、まだSwiftは私にとっては容易ではありません。私は複数の新しいエラーが出ています。
func connectedToNetwork() -> Bool {
var zeroAddress = sockaddr_in(sin_len: 0, sin_family: 0, sin_port: 0, sin_addr: in_addr(s_addr: 0), sin_zero: (0, 0, 0, 0, 0, 0, 0, 0))
zeroAddress.sin_len = UInt8(sizeofValue(zeroAddress))
zeroAddress.sin_family = sa_family_t(AF_INET)
var defaultRouteReachability: SCNetworkReachabilityRef = SCNetworkReachabilityCreateWithAddress(UnsafePointer<Void>, UnsafePointer<zeroAddress>) // 'zeroAddress' is not a type
var flags = SCNetworkReachabilityFlags()
let didRetrieveFlags = SCNetworkReachabilityGetFlags(defaultRouteReachability, UnsafeMutablePointer<flags>) // 'flags' is not a type
defaultRouteReachability.dealloc(1) // 'SCNetworkReachabilityRef' does not have a member named 'dealloc'
if didRetrieveFlags == false {
return false
}
let isReachable: Bool = flags & kSCNetworkFlagsReachable // Cannot invoke '&' with an argument list of type '(@lvalue UInt32, Int)'
let needsConnection: Bool = flags & kSCNetworkFlagsConnectionRequired // Cannot invoke '&' with an argument list of type '(@lvalue UInt32, Int)'
return (isReachable && !needsConnection) ? true : false
}
EDIT 1: なるほど、この行をこう変えてみました。
var defaultRouteReachability: SCNetworkReachabilityRef = SCNetworkReachabilityCreateWithAddress(UnsafePointer<Void>(), &zeroAddress)
この行で新たに発生したエラーは
'UnsafePointer' は 'CFAllocator' に変換されません。
. どのようにあなたは
NULL
をどのように渡すのでしょうか?
また、この行を変更したところ、エラーがなくなりました。
let didRetrieveFlags = SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags)
EDIT 2:
私は
nil
を見て、この行に
この
の質問をしています。しかし、その答えは、答えと矛盾する
ここで
. に相当するものはないと書かれています。
NULL
に相当するものはないと言っています。
var defaultRouteReachability: SCNetworkReachabilityRef = SCNetworkReachabilityCreateWithAddress(nil, &zeroAddress)
とにかく、次のような新しいエラーが表示されます。 'sockaddr_in' は 'sockaddr' と同一ではありません。 というエラーが出ました。
どのように解決するのですか?
(この回答は、Swift言語の変更のために繰り返し拡張され、少し分かりにくくなっていました。私は今それを書き直し、Swift 1.xを参照しているすべてを削除しました。 編集履歴で見つけることができます。)
で行う方法です。 Swift 2.0 (Xcode 7) :
import SystemConfiguration
func connectedToNetwork() -> Bool {
var zeroAddress = sockaddr_in()
zeroAddress.sin_len = UInt8(sizeofValue(zeroAddress))
zeroAddress.sin_family = sa_family_t(AF_INET)
guard let defaultRouteReachability = withUnsafePointer(&zeroAddress, {
SCNetworkReachabilityCreateWithAddress(nil, UnsafePointer($0))
}) else {
return false
}
var flags : SCNetworkReachabilityFlags = []
if !SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) {
return false
}
let isReachable = flags.contains(.Reachable)
let needsConnection = flags.contains(.ConnectionRequired)
return (isReachable && !needsConnection)
}
説明
-
Swift 1.2 (Xcode 6.3) の時点で、インポートされた C 言語の構造体は Swift ではデフォルトの初期化子を持っており、構造体のすべてのフィールドを 0 に初期化するので、ソケットアドレス構造体は
var zeroAddress = sockaddr_in()
-
sizeofValue()
はこの構造体の大きさを表し、これを に変換する必要があります。UInt8
に対してsin_len
:zeroAddress.sin_len = UInt8(sizeofValue(zeroAddress))
-
AF_INET
はInt32
であるため、これを正しい型に変換する必要があります。sin_family
:zeroAddress.sin_family = sa_family_t(AF_INET)
-
withUnsafePointer(&zeroAddress) { ... }
のアドレスを渡す。 構造体のアドレスをクロージャに渡し、そのクロージャの引数としてSCNetworkReachabilityCreateWithAddress()
. またUnsafePointer($0)
へのポインタを期待するので,この変換は必要です。sockaddr
へのポインタではなくsockaddr_in
. -
から返される値は
withUnsafePointer()
が戻り値 からSCNetworkReachabilityCreateWithAddress()
の戻り値で、これは タイプSCNetworkReachability?
を持つ、つまりオプショナルなものです。 そのguard let
ステートメント (Swift 2.0 の新機能) は、ラップされていない値をdefaultRouteReachability
変数が ではなくnil
. そうでない場合はelse
ブロックが実行され,関数 が返ります。 -
Swift 2の時点では
SCNetworkReachabilityCreateWithAddress()
は は管理されたオブジェクトを返します。明示的に解放する必要はありません。 -
Swift 2の時点では
SCNetworkReachabilityFlags
に準拠しOptionSetType
に準拠し、集合のようなインターフェイスを持つ 集合に似たインタフェースを持つ で空のフラグ変数を作成します。var flags : SCNetworkReachabilityFlags = []
でフラグをチェックし
let isReachable = flags.contains(.Reachable) let needsConnection = flags.contains(.ConnectionRequired)
-
の第2パラメータは
SCNetworkReachabilityGetFlags
は、タイプUnsafeMutablePointer<SCNetworkReachabilityFlags>
であり、これは を渡すことになります。 アドレス を渡さなければならないことを意味します。
また、通知先コールバックの登録は Swift 2 では可能です。 SwiftからCのAPIを操作する と Swift 2 - UnsafeMutablePointer<Void> をオブジェクトに変換する。 .
Swift 3/4 に対応したアップデートを行いました。
安全でないポインタは、もう単純に別の型のポインタに変換することはできません。 に変換することができなくなりました(参照 -) SE-0107 UnsafeRawPointer APIを参照してください。 ). 以下は更新されたコードです。
import SystemConfiguration
func connectedToNetwork() -> Bool {
var zeroAddress = sockaddr_in()
zeroAddress.sin_len = UInt8(MemoryLayout<sockaddr_in>.size)
zeroAddress.sin_family = sa_family_t(AF_INET)
guard let defaultRouteReachability = withUnsafePointer(to: &zeroAddress, {
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
SCNetworkReachabilityCreateWithAddress(nil, $0)
}
}) else {
return false
}
var flags: SCNetworkReachabilityFlags = []
if !SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) {
return false
}
let isReachable = flags.contains(.reachable)
let needsConnection = flags.contains(.connectionRequired)
return (isReachable && !needsConnection)
}
関連
-
[解決済み] 1ビットのセット、クリア、トグルはどのように行うのですか?
-
[解決済み] アトミック属性と非アトミック属性の違いは何ですか?
-
[解決済み] iOSまたはmacOSで、インターネット接続が有効かどうかを確認するにはどうすればよいですか?
-
[解決済み] C++でクラスと構造体はいつ使い分けるべきか?
-
[解決済み] SwiftからObjective-Cのコードを呼び出すにはどうしたらいいですか?
-
[解決済み] Swiftで#pragmaマーク?
-
[解決済み] Swift Betaのパフォーマンス:配列のソート
-
[解決済み] Swiftでindexとelementでループを反復させる方法
-
[解決済み] Swiftを使用してアプリのバージョンとビルド番号を取得するにはどうすればよいですか?
-
[解決済み】高放射能環境下で使用するアプリケーションのコンパイルについて
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[iOS]コンパイルエラー:ld: アーキテクチャ x86_64 のシンボルが見つかりません。
-
[エラー処理】iOSのエラー、アーキテクチャx86_64の未定義シンボルについて
-
制御が非ボイド関数の終了に達する
-
[解決済み] Objective-Cで、ある文字列が他の文字列を含んでいるかどうかを調べるにはどうすればよいですか?
-
[解決済み] UITableViewの下にある余分なセパレータをなくす
-
[解決済み] UIViewController のビューが表示されているかどうかを確認する方法
-
[解決済み] SwiftでUIAlertViewを作成するにはどうしたらいいですか?
-
[解決済み] SwiftでURLから画像を読み込む/ダウンロードする
-
[解決済み] SwiftでiOSキーボードを任意の場所でタッチして閉じる
-
[解決済み] iOS 11、Apple TV 4Kなどを搭載したXcode 9でワイヤレスデバッグを行う方法とは?