CFStreamCreatePairWithSocketToHost(_:_:_:_:_:)
はiOS15でdeprecatedになっており、「Jump to Definition」でインターフェイスを確認すると「Use nwconnection_t in Network framework instead」となっていたためNetwork Frameworkを使うことにしました。 ところがNetwork FrameworkのNWConnectionの receive(minimumIncompleteLength:maximumLength:completion:)
メソッドは一度実行した後データを受信した場合、その後データが送られてきても何も起きないため、StreamDelegateの `stream(:handle:) がデータを受信するたびに実行されるのとは違う形のようでした。 今回実装したいアプリの通信の性質上、「いつ何回データが送られてくるか?」はあらかじめ把握できないため、StreamDelegateのように受信するたびにメソッドが実行される形が望ましいと考えております。 素朴な考えでは
receive(minimumIncompleteLength:maximumLength:completion:) のcompletionの中で
receive(minimumIncompleteLength:maximumLength:completion:) を呼ぶようにすれば何度データが送られてきてもcompletionが実行される実装に出来ると思ったのですが、この実装方法で問題ないかアドバイスをいただきたいです。 (
[weak self] を使っているから問題ない気がするけど循環参照の問題はないか?とかreceiveの取りこぼしがないか?が気になっています。)
swift import Foundation import Network final class Client { let connection: NWConnection init(host: String, port: UInt16) { connection = NWConnection( to: .hostPort(host: .init(host), port: .init(integerLiteral: port)), using: .tcp ) } deinit { connection.cancel() } func start() { connection.start(queue: .main) addReceive() } func send(_ bytes: [UInt8]) { connection.send(content: bytes, completion: .contentProcessed { _ in // do something. }) } private func addReceive() { connection.receive(minimumIncompleteLength: .zero, maximumLength: .max) { [weak self] content, context, isComplete, error in // do something. self?.addReceive() } } }
` ご回答いただけますと幸いです.CFStreamCreatePairWithSocketToHost(_:_:_:_:_:)
はiOS15でdeprecatedになっており、「Jump to Definition」でインターフェイスを確認すると「Use nwconnection_t in Network framework instead」となっていたためNetwork Frameworkを使うことにしました。 ところがNetwork FrameworkのNWConnectionの receive(minimumIncompleteLength:maximumLength:completion:)
メソッドは一度実行した後データを受信した場合、その後データが送られてきても何も起きないため、StreamDelegateの `stream(:handle:) がデータを受信するたびに実行されるのとは違う形のようでした。 今回実装したいアプリの通信の性質上、「いつ何回データが送られてくるか?」はあらかじめ把握できないため、StreamDelegateのように受信するたびにメソッドが実行される形が望ましいと考えております。 素朴な考えでは
receive(minimumIncompleteLength:maximumLength:completion:) のcompletionの中で
receive(minimumIncompleteLength:maximumLength:completion:) を呼ぶようにすれば何度データが送られてきてもcompletionが実行される実装に出来ると思ったのですが、この実装方法で問題ないかアドバイスをいただきたいです。 (
[weak self] を使っているから問題ない気がするけど循環参照の問題はないか?とかreceiveの取りこぼしがないか?が気になっています。)
swift import Foundation import Network final class Client { let connection: NWConnection init(host: String, port: UInt16) { connection = NWConnection( to: .hostPort(host: .init(host), port: .init(integerLiteral: port)), using: .tcp ) } deinit { connection.cancel() } func start() { connection.start(queue: .main) addReceive() } func send(_ bytes: [UInt8]) { connection.send(content: bytes, completion: .contentProcessed { _ in // do something. }) } private func addReceive() { connection.receive(minimumIncompleteLength: .zero, maximumLength: .max) { [weak self] content, context, isComplete, error in // do something. self?.addReceive() } } }
` ご回答いただけますと幸いです. receive
の completion
の中で receive
を呼ぶループを組みますね。一般的にはそうなると思います。// SwiftUI.View struct TestView: View { var body: some View { ScrollView { VStack { TextField("", text: .constant("")) Color.red .frame(height: 1000) Color.blue .frame(height: 200) } } } } // こちらのUIViewControllerを表示する final class TestViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() let content = UIHostingController(rootView: TestView()).view! view.addSubview(content) content.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ content.topAnchor.constraint(equalTo: view.topAnchor), content.leadingAnchor.constraint(equalTo: view.leadingAnchor), content.trailingAnchor.constraint(equalTo: view.trailingAnchor), content.bottomAnchor.constraint(equalTo: view.bottomAnchor) ]) } }
上記のようなコードでUIViewControllerを表示した際、 iOS16.3.1までだとキーボード表示中でも青色のColorが表示されるまでスクロールできたのですが、 iOS16.4以降だとキーボード表示中に青色のColorが表示されるところまでスクロールできないようになっています。(キーボードが表示される階層が変更されている?) こちらはiOS16.4のアップデートにより挙動が変わったと思っているのですが、意図した変更で認識あっていますでしょうか?? 意図せぬ変更で、今後元に戻すことがあるかどうかが気になっています…! また、この事象から、iOS16.4のアップデートではUIの制御に関しての変更もあったと認識したのですが、他にも挙動が変わりうるような変更がありそうかが分かりましたら回答いただけましたら嬉しいです (edited)// SwiftUI.View struct TestView: View { var body: some View { ScrollView { VStack { TextField("", text: .constant("")) Color.red .frame(height: 1000) Color.blue .frame(height: 200) } } } } // こちらのUIViewControllerを表示する final class TestViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() let content = UIHostingController(rootView: TestView()).view! view.addSubview(content) content.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ content.topAnchor.constraint(equalTo: view.topAnchor), content.leadingAnchor.constraint(equalTo: view.leadingAnchor), content.trailingAnchor.constraint(equalTo: view.trailingAnchor), content.bottomAnchor.constraint(equalTo: view.bottomAnchor) ]) } }
上記のようなコードでUIViewControllerを表示した際、 iOS16.3.1までだとキーボード表示中でも青色のColorが表示されるまでスクロールできたのですが、 iOS16.4以降だとキーボード表示中に青色のColorが表示されるところまでスクロールできないようになっています。(キーボードが表示される階層が変更されている?) こちらはiOS16.4のアップデートにより挙動が変わったと思っているのですが、意図した変更で認識あっていますでしょうか?? 意図せぬ変更で、今後元に戻すことがあるかどうかが気になっています…! また、この事象から、iOS16.4のアップデートではUIの制御に関しての変更もあったと認識したのですが、他にも挙動が変わりうるような変更がありそうかが分かりましたら回答いただけましたら嬉しいです (edited)class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() let viewController = UIHostingController(rootView: TestView()) view.addSubview(viewController.view) addChild(viewController) viewController.didMove(toParent: self) viewController.view.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ viewController.view.topAnchor.constraint(equalTo: view.topAnchor), viewController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor), viewController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor), viewController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor) ]) } }
class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() let viewController = UIHostingController(rootView: TestView()) view.addSubview(viewController.view) addChild(viewController) viewController.didMove(toParent: self) viewController.view.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ viewController.view.topAnchor.constraint(equalTo: view.topAnchor), viewController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor), viewController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor), viewController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor) ]) } }
UIViewController
と UIViewController
を親子付けするときに3手必要なの難しいっすよね。-seekToOffset:error:
や -seekToEndReturningOffset:error:
でシークしたあと、 -readDataUpToLength:error:
(以下「read API」)や -writeData:error:
(以下「write API」)を使っています。頻度は低いものの、read APIやwrite APIがエラーになることを確認しています。 read APIは 「Error Domain=NSCocoaErrorDomain Code=257 "ファイルを表示するためのアクセス権がないため、開けませんでした。" UserInfo={NSUnderlyingError=0x280241b30 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}}」というエラーが出たのを確認していますが、ファイルは存在し、同じインスタンスでその手前までread APIの呼び出しが何度も成功した後に起こっているので、アクセス権がないということはないと思います。 write APIは、処理ロジックと作られたデータからの分析ですが、同一インスタンスで28590回成功後、387回失敗、1回成功、1失敗、63406回成功となった形跡があります。 何かエラーになる条件が分かれば、そのタイミングでは処理を避けるといったことを検討したいのですが、エラーになる条件として考えられるものがあれば教えていただきたいです。また、エラー発生時のリカバリについて例えばリトライしてみるというのは回復の可能性があるでしょうか。特にwrite APIの方は一部だけ失敗するとデータ破損を招くので頭を抱えています。 あと、エラーを返さない旧API( -readDataOfLength:
や -writeData:
)と挙動の違いはあるのでしょうか。どうも新APIに置き換えた頃からデータ破損報告が見られるようになった感もあり…(たまたまかもしれません)。 (edited)-seekToOffset:error:
や -seekToEndReturningOffset:error:
でシークしたあと、 -readDataUpToLength:error:
(以下「read API」)や -writeData:error:
(以下「write API」)を使っています。頻度は低いものの、read APIやwrite APIがエラーになることを確認しています。 read APIは 「Error Domain=NSCocoaErrorDomain Code=257 "ファイルを表示するためのアクセス権がないため、開けませんでした。" UserInfo={NSUnderlyingError=0x280241b30 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}}」というエラーが出たのを確認していますが、ファイルは存在し、同じインスタンスでその手前までread APIの呼び出しが何度も成功した後に起こっているので、アクセス権がないということはないと思います。 write APIは、処理ロジックと作られたデータからの分析ですが、同一インスタンスで28590回成功後、387回失敗、1回成功、1失敗、63406回成功となった形跡があります。 何かエラーになる条件が分かれば、そのタイミングでは処理を避けるといったことを検討したいのですが、エラーになる条件として考えられるものがあれば教えていただきたいです。また、エラー発生時のリカバリについて例えばリトライしてみるというのは回復の可能性があるでしょうか。特にwrite APIの方は一部だけ失敗するとデータ破損を招くので頭を抱えています。 あと、エラーを返さない旧API( -readDataOfLength:
や -writeData:
)と挙動の違いはあるのでしょうか。どうも新APIに置き換えた頃からデータ破損報告が見られるようになった感もあり…(たまたまかもしれません)。 (edited)