Use Mach-O section as plist

背景

plist以其可讀性強的特點,被大家首選用作配置文件。但是plist 文件的讀取速度實在不給力,是否有可選方案?答案是有的!

使用Section 保存數據

我們的程序編譯后代碼在.text ,數據在.data段,我們可以通過聲明一個字符串在data段的特定的section里(默認字符串在 __cstring這個section中)。

char * str __attribute((used,section("__DATA,Test"))) = "Hello world";

在運行的時候通過

///< 頭文件:getsect.h
extern uint8_t *getsectiondata(
    const struct mach_header_64 *mhp,
    const char *segname,
    const char *sectname,
    unsigned long *size);

來獲取某個二進制文件中,指定segment指定section的內容。這樣子就能從代碼中獲得配置信息。

Coding

#ifndef __LP64__
#define mach_header mach_header
#else
#define mach_header mach_header_64
#endif

//使用 used字段,即使沒有任何引用,在Release下也不會被優化
#define WriteSection(sectName) __attribute((used, section("__DATA,"#sectName" ")))
#define SectionDataWithKeyValue(key,value) char * k##key WriteSection(CustomSection) = "{ \""#key"\" : \""#value"\"}";

// 注入 :
SectionDataWithKeyValue(url, www.baidu.com)


#import "ViewController.h"
#include <mach-o/getsect.h>
#include <mach-o/loader.h>
#include <mach-o/dyld.h>
#include <dlfcn.h>

static NSString *configuration = @"";
const struct mach_header *machHeader = NULL;

@interface ViewController ()
@end

@implementation ViewController

- (void)viewDidLoad {
    
    [super viewDidLoad];
    NSLog(@"%@",[self readConfigFromSectionName:@"CustomSection"]);
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (NSArray <NSDictionary *> *)readConfigFromSectionName:(NSString *)sectionName
{
    NSMutableArray *configs = [NSMutableArray array];
    if (sectionName.length)
    {
        if (machHeader == NULL)
        {
            Dl_info info;
            dladdr((__bridge const void *)(configuration), &info);
            machHeader = (struct mach_header*)info.dli_fbase;
        }
        unsigned long size = 0;
        uintptr_t *memory = (uintptr_t*)getsectiondata(machHeader, SEG_DATA, [sectionName UTF8String], & size);
        
        NSUInteger counter = size/sizeof(void*);
        NSError *converError = nil;
        for(int idx = 0; idx < counter; ++idx){
            char *string = (char*)memory[idx];
            
            NSString *str = [NSString stringWithUTF8String:string];
            NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding];
            id json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&converError];
            if (json && [json isKindOfClass:[NSDictionary class]])
            {
                [configs addObject:json];
            }
        }
    }
    return configs;
}
@end

最終輸出:

2017-06-05 22:41:54.431 WriteSectionData[27360:1459771] (
        {
        url = "www.baidu.com";
    }
)
WriteSectionData.png

由于小端序的原因,所以在鏡像中的地址應該是0x0100001a70。 用hopper 打開程序,定位到地址:0x0100001a70。

WriteSectionData_hop.png

通過字符串定位到鏡像文件的指定section,讀取配置信息。并且實現了代碼編寫的時候注入,無需文件IO(內存讀取),代碼即配置,局部性強,可讀性高。

TODO:性能對比

  • 對比數據從section 和plist 讀取數據轉化為json的耗時
  • 對比數據量一樣的前提下,文件大小的對比。
  • section 段增大,是否會對啟動速度有影響。

更多

關于DATA 段大小的限制

App Size for iOS (& tvOS) only

Your app’s total uncompressed size must be less than 4GB. Each Mach-O executable file (for example, app_name.app/app_name) must not exceed these limits:

For apps whose MinimumOSVersion is less than 7.0: maximum of 80 MB for the total of all __TEXT sections in the binary.
For apps whose MinimumOSVersion is 7.x through 8.x: maximum of 60 MB per slice for the __TEXT section of each architecture slice in the binary.
For apps whose MinimumOSVersion is 9.0 or greater: maximum of 500 MB for the total of all __TEXT sections in the binary.
However, consider download times when determining your app’s size. Minimize the file’s size as much as possible, keeping in mind that there is a 100 MB limit for over-the-air downloads.

以上引用自蘋果官方文檔,官方只給出了TEXT段的大小限制,并沒有給出DATA 段的大小限制。
Ref :

Specifying Attributes of Variables

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 國家電網公司企業標準(Q/GDW)- 面向對象的用電信息數據交換協議 - 報批稿:20170802 前言: 排版 ...
    庭說閱讀 11,081評論 6 13
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,837評論 18 139
  • Spring Boot 參考指南 介紹 轉載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,925評論 6 342
  • *面試心聲:其實這些題本人都沒怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個offer,總結起來就是把...
    Dove_iOS閱讀 27,199評論 30 471
  • 人生有一千種一萬種可能的路走,而我們選了一條幾乎所有人都看來不理解的艱難道路前進。一切的選擇都是為了我們心里夢想的...
    蜀湘情緣閱讀 131評論 0 0