Entries

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

NSCodingとBoost.Serialization

タグ: Objective-C C++ Boost
struct GPSPosition
{
    int degree;
    int minutes;
    float seconds;
};

こんな構造体があって

#import <Foundation/Foundation.h>

@interface Foo : NSObject <NSCoding>
{
@public // ←手抜き
    GPSPosition pos;
}
@end

こんなインタフェースがあったら

@implementation Foo
- (id)initWithCoder:(NSCoder*)decoder
{
    if (self = [super init])
    {
        pos.degree = [decoder decodeIntegerForKey:@"pos.degree"];
        pos.minutes = [decoder decodeIntegerForKey:@"pos.minutes"];
        pos.seconds = [decoder decodeFloatForKey:@"pos.seconds"];
    }
    return self;
}
- (void)encodeWithCoder:(NSCoder*)encoder
{
    [encoder encodeInteger:pos.degree forKey:@"pos.degree"];
    [encoder encodeInteger:pos.minutes forKey:@"pos.minutes"];
    [encoder encodeFloat:pos.seconds forKey:@"pos.seconds"];
}
@end

こんな風に実装することで

Foo* foo1 = [[[Foo alloc] init] autorelease];
foo1->pos.degree = 34;
foo1->pos.minutes = 17;
foo1->pos.seconds = 8.5;
NSData* data = [NSKeyedArchiver archivedDataWithRootObject:foo1];
Foo* foo2 = [NSKeyedUnarchiver unarchiveObjectWithData:data];
NSLog(@"%d,%d,%f", foo2->pos.degree, foo2->pos.minutes, foo2->pos.seconds);

オブジェクトをシリアライズできる。

34,17,8.500000

実に簡単ヽ( ´ー`)ノ

以上はObjective-CとFoundationフレームワークの話だが、C++の場合はBoost.Serializationを使うことでこれまた簡単に構造体やクラスのシリアライズができる。

namespace boost {
namespace serialization {

template <typename Archive>
inline void serialize(Archive& ar, GPSPosition& pos, const unsigned int version)
{
    ar & pos.degree & pos.minutes & pos.seconds;
}

} // namespace serialization
} // namespace boost

そしてObjective-CはObjective-C++によってC++も扱えるので、このようにすればBoost.Serialization用に定義したシリアライズ関数をNSCodingの実装でも流用できる。

#include <vector>
#include <boost/iostreams/device/back_inserter.hpp>
#include <boost/iostreams/device/array.hpp>
#include <boost/iostreams/stream_buffer.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>

template <typename T>
inline void encode(const T& target, NSCoder* encoder, NSString* key)
{
    typedef std::vector<char> bytes_type;
    typedef boost::iostreams::back_insert_device<bytes_type> device_type;
    
    bytes_type bytes;
    {
        boost::iostreams::stream_buffer<device_type> stream_buffer(bytes);
        boost::archive::binary_oarchive boa(stream_buffer);
        boa << target;
    }
    [encoder encodeBytes:reinterpret_cast<uint8_t*>(&bytes[0]) length:bytes.size() forKey:key];
}

template <typename T>
inline void decode(T& target, NSCoder* decoder, NSString* key)
{
    typedef boost::iostreams::array_source device_type;
    
    NSUInteger length;
    const uint8_t* bytes = [decoder decodeBytesForKey:key returnedLength:&length];
    
    boost::iostreams::stream_buffer<device_type> stream_buffer(reinterpret_cast<const char*>(bytes), length);
    boost::archive::binary_iarchive bia(stream_buffer);
    bia >> target;
}
@implementation Foo
- (id)initWithCoder:(NSCoder*)decoder
{
    if (self = [super init])
    {
        decode(pos, decoder, @"pos");
    }
    return self;
}
- (void)encodeWithCoder:(NSCoder*)encoder
{
    encode(pos, encoder, @"pos");
}
@end
スポンサーサイト

コメント

コメントの投稿

コメントの投稿
管理者にだけ表示を許可する

トラックバック

トラックバック URL
http://idlysphere.blog66.fc2.com/tb.php/208-c010406d
この記事にトラックバックする(FC2ブログユーザー)

Appendix

タグ

Blog内検索

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。