Swift転職なら=>【LevTech】
↑クリックして拡大
↑クリックして拡大
↑クリックして拡大
↑クリックして拡大

頭痛が減ったので共有です!

rebuild.fmを応援しています!

HOME > UnmanagedとUnSafePointer

UnmanagedからUnSafePointer移管によるpassRetainedエラー対応

悩まされ続けております。CoreTextで文字を縦書きにしたいのですがSwift2のコードを3に移管する際にUnmanaged CFStringRefでつまづきました。 解決するまでの流れを記載します。

サンプル画像

参考:UnsafeRawPointer Migration
参考:swift3 で UnsafePointer
参考:https://swift.org/migration-guide/se-0107-migrate.html
参考:ルビを振る
参考:How to use CTRubyAnnotationRef in Swift
参考:How to convert Unmanaged to Swift 3
参考:swift3 で UnsafePointer
参考:インスタンスをUnsafeMutablePointerに変換して扱う
参考:How to use CTRubyAnnotationRef in Swift
参考:lingochamp/FuriganaTextView

やってみた

以下が問題のコンパイルエラーの行。↓以下はSwift2の箇所。


var text = [.passRetained(ruby) as Unmanaged?, .None, .None, .None]
let annotation = CTRubyAnnotationCreate(.Auto, .Auto, 0.5, &text)

↓Swift3の自動変換によって以下に変換されましたがエラーが保持されている状態(UnmanagedがUnsafePointerに変換されていますが、 passRetainedがメンバ関数に無いですとのエラー)


var text = [.passRetained(ruby) as UnSafePointer?, .None, .None, .None]
let annotation = CTRubyAnnotationCreate(.Auto, .Auto, 0.5, &text)

passRetainedとは一体何なのか?

Appleの公式サイトには、Creates an unmanaged reference with an unbalanced retain. と記載されている。アンバランスのretainでマネージされていない参照を作成する。はて、、、わからん。

どうやら retainは「保持」の意味でありObjectiveCでもでていた安全面での記載。Apple公式サイトの下の方にはインスタンスは漏れ出す可能性が あるとのことですので、Swift以外の参照を利用した「部外者」的なものでSwiftが管理しきれないデータを取り出す為の 参照ポイントを作りだす。といったところとの認識です。


参考:passRetained(_:)

履歴

↓Swift3の自動変換によって以下に変換されましたがエラーが保持されている状態(UnmanagedがUnsafePointerに変換されていますが、 passRetainedがメンバ関数に無いですとのエラー)


var text = [Unmanaged.passRetained(ruby) as UnsafeMutablePointer, .None, .None, .None]
let annotation = CTRubyAnnotationCreate(.Auto, .Auto, 0.5, &text)

このようにすると、Cannot convert call result type 'Unmanaged<_>' to expected type 'UnsafeMutablePointer<_>' のエラー。。。。

サンプル画像



要は文字列NSStringのポインタをUnmangedのものを渡せばよいので、、、、


	   
	   var text = [Unmanaged.passUnretained(ruby as CFString).toOpaque(), .None, .None, .None]
                        let annotation = CTRubyAnnotationCreate(.Auto, .Auto, 0.5, &text)
	

↑この上のtoOpaqueはこのインスタンスをUnSafeMutableRawPointerにする。でもまだダメだ。。。

格闘の結果、、、、


このサイトを元に作業How to use CTRubyAnnotationRef in Swift
		
	   let kanji = (x as NSString).substring(with: pair.rangeAt(1))
       let hiragana = (x as NSString).substring(with: pair.rangeAt(2)) as CFString;
       let furigana: UnsafeMutablePointer<Unmanaged<CFString>>! = UnsafeMutablePointer<Unmanaged<CFString>>.allocate(capacity:4)
       furigana[0] = Unmanaged.passUnretained(hiragana)
       let annotation: CTRubyAnnotation = CTRubyAnnotationCreate(CTRubyAlignment.auto, CTRubyOverhang.auto, 0.5, furigana)
		

ひとまずこれでコンパイルエラーが消えた。が確認できていないので再度進捗はアップしていく。サンプルではfurigana[1-3]をnullで初期化していたが 方法がわからず、何もセットしない、で処理している。


追記。やっぱり解決できていない。2017年2月17日

このコードでコンパイルは通るようになったがやはりエラー(CTFramesetterCreateWithAttributedString時にNSExceptionの エラーが)が発生している。対処のメモを残しておきます。Objective C の関数で対応したメモがあった。

	2017-02-17 05:46:39.428 testSwift3[970:17985] -[NSNull length]: unrecognized selector sent to instance 0x1097ad130
2017-02-17 05:46:39.435 testSwift3[970:17985] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSNull length]: unrecognized selector sent to instance 0x1097ad130'
	

参考:Unsafe Swift: Using Pointers And Interacting With C
参考:クックパッド開発者ブログ
参考:Swift UITextViewにて単語の上にルビを付ける方法

最終落ち着いたのは以下です。

			let kanji = (x as NSString).substring(with: pair.rangeAt(1))
			let furigana = (x as NSString).substring(with: pair.rangeAt(2))
                        
			var text: [Unmanaged?] = [Unmanaged.passRetained(furigana as CFString) as Unmanaged, .none, .none, .none]
			let annotation = CTRubyAnnotationCreate(.auto, .auto, 0.5, &text[0]!)
                        
			return NSAttributedString(
				string: kanji,
				attributes: [kCTRubyAnnotationAttributeName as String: annotation])
							
		

まとめ

紆余曲折してやっと落ち着きました。。。

↓こんな記事もありますよ!

CoreTextでTextViewの一文字の向きを変える(#2)

さて、サンプルそのままだと面白くないので、本日6月から開始する自転車規制強化 にのっかったサンプル<自転車の転だけ横に曲げる>にしてみます。(14歳以上が対象。自転車のイヤホン装着や片手走行、 酔っ払い運転、歩道運転、片手スマホ、、、、今まで誰もがやり通してきたことが「逮捕や補導の対象」となるようです。赤切符もきられる ようになるとのことで、自転車に酔っ払ってのって自動車の免停なんかになりかね無いので注意です)

NSFileManagerでAPP保存領域のデータ操作

ファイルやディレクトリ作成はなんとなく面倒くさいイメージがありましたが、この記事で少し自分の中で壁が低くなった気がします。 よろしければご利用くださいませ。

外部ブラウザでURLを開く

アプリから外部ブラウザ(Safari)でURLを開く方法を記載します。内部的に利用する場合はWebViewを利用します。
このエントリーをはてなブックマークに追加
右側のFacebookのLikeをクリック頂けると記事更新の際に通知されますので宜しければご利用下さい!