UI(またはタンバリンと踊る)
プロジェクトのUIに関しては、水平ページングを使用してグリッドテーブルを作成するのは簡単な作業ではありませんでした。 いつものように、既製のソリューションを探して、私はstackoverflow.comに登りましたが、残念ながら、私が経験したことは、ある程度不適当でした。
AQGridViewには大きな期待がありましたが、判明したように、水平方向の塗りつぶしとページングからは、空のスタブしかありません。 彼女に2度目のチャンスを与え、テーブルを90度回転させて、多くの人に使い慣れたトリックを適用することにしました。 最初は、このオプションは機能しているようで、多かれ少なかれ受け入れられましたが、ここでも石がありました。
AQGridView自体と標準のUIScrollViewのバグにより、このコンポーネントを使用することはできませんでした。 状況によっては、グリッドが絶えず壊れ、一部のセルが脱落し、注文が絶えず飛んでしまいました。 曲率に関する疑念を払拭するために、キットのデモで問題を再現しようとしました-バグが確認されました。
UIScrollViewとその派生物については-ここでも最初にAQGridViewに罪を犯しましたが、 UITableViewを使い始めたとき、問題が繰り返されました。 バグの本質は、 UIScrollViewが変換によって切り替えられると 、バウンス効果が落ちることであり、これはiOSにとって非常にく不自然です。
経験的に、 UIScrollViewのサイズ変更と移動は、デバイスが回転したときに非難されることが判明しました。これは、 layoutSubviewsハンドラーを介して手で行われました。 シャーマニックタンバリンをとると、すべてがcenterプロパティを介して回転したUIScrollViewの位置を壊すことがわかりました。 おそらく他のいくつかの条件がありましたが、非常に多くのオプションが試行されたため、もはや思い出すことができません。
この長い歴史はすべて、古き良きUITableViewで歪曲されなければなりませんでした。 バウンスを修正し、回転の問題は解決しました。 彼はテーブルセルを1ページのサイズにし、いくつかのサブセルで構成され、各サブセルは個別のクラスのインスタンスとして実装されます。 次のようになりました。
HTMLとLiang-Knuthアルゴリズムを使用します。
人気のある電子書籍形式の解析とレンダリングも別の話です。 HTMLは原則として難しくありません。libxmlは素晴らしい仕事をしました。 HTMLファイルは再帰的に処理され、テキストのブロックに分割され、対応する属性が各ブロックに設定されます。 このすべてをCoreTextからフレームセッターに駆動することは残り、これで完了です。 しかし、そこにありました! ハイフネーションと幅の整列を行う必要があります。 レベルを下げて、フレームセッターではなくタイプセッターを使用する必要がありました。 これを使用すると、たとえば次の関数を使用して、テキストを行に簡単にカットできます。
CFIndex CTTypesetterSuggestClusterBreak( CTTypesetterRef typesetter, CFIndex startIndex, double width);
行に分割するプロセスでは、ギャップの場所を決定する必要があります。 単語の途中でギャップが発生する場合は、ハイフンを正しく配置する必要があります。 ここで、上記のLiang-Knutアルゴリズムの実装が役立ちます 。
レンダリング(またはユーザーを待たせないでください!)
残っているのは、結果として生じるテキスト行の山をページにカットすることであり、レンダリングすることができます。 経験的に、レンダリング前のこの一連のテキスト処理操作はすべて、かなりの時間がかかることが判明しました。 プロファイラーから、ハイフネーションが原因であることに気付きました。 私は本の計算をバックグラウンドで別のスレッドで実行しました-より速く動作し始めました。
唯一のマイナスは、レンダリングの進行中は、巻き戻しスライダーを使用できないことです。 まだ処理されていないチャプタに移動する必要がある場合は、できるだけ早く画面に表示するために、最初に処理キューに入れてください。
その結果、かなり良い結果が得られ、iPadでは書籍が非常に迅速に処理されます(これがオンザフライでレンダリングされる場合)。
さまざまな画面の向きでレンダリングされたページは次のようになります。
HTTP AFNetworkingの作業では、通常どおり、強くお勧めしました。 確かに、「リーク」が1つありました。メモリリークのアプリケーションを分析すると、循環リンクに関連するファイルダウンロードの進行状況の表示に問題が明らかになりました。 setDownloadProgressBlockメソッドには 、次のようなブロックがありました。
if ([self.progressDelegate respondsToSelector:@selector(fileDownloadRequest:progressBytes:withTotalBytes:)]) { [self.progressDelegate fileDownloadRequest:self progressBytes:alreadyDownloadedBytes+totalBytesRead withTotalBytes:alreadyDownloadedBytes+totalBytesExpectedToRead]; }
ブロックのコードにselfが存在すると、循環依存が発生しました。 これは、デリゲートへのポインタがコピーされる別のローカル変数を作成することで解決され、この変数はすでにブロックで使用されています。 次のようになりました。
id<FileDownloadProgressDelegate> progress = self.progressDelegate; [self.request setDownloadProgressBlock:^(NSInteger bytesRead, NSInteger totalBytesRead, NSInteger totalBytesExpectedToRead) { if ([progress respondsToSelector:@selector(fileDownloadRequest:progressBytes:withTotalBytes:)]) { [progress fileDownloadRequest:self progressBytes:alreadyDownloadedBytes+totalBytesRead withTotalBytes:alreadyDownloadedBytes+totalBytesExpectedToRead]; } }];
将来的には、自由な時間があるので、引き続きiOSの開発経験について説明しますが、今のところ、コメントで私の作業の結果について議論することを勧めます。