Как загрузить изображение из Assets.car(скомпилированной версии xcassets) в NSBundle?

В двух словах:

Как загрузить изображения из скомпилированного Assets.car в NSBundle?

Полная версия:

Я собираюсь преобразовать набор приложений для использования CocoaPods. Каждое приложение полагается на общий пакет под названием Core.

Core включает файлы кода, файлы xib и несколько файлов xcasset.

Здесь соответствующая строка из Podspec для Core, которая создает пакет ресурсов:

  s.resource_bundles = {'CoreResources' => ['Core/Resources/*']}

Podspec проходит pod spec lint, а основной проект, который полагается на него, правильно строит.

Однако ни одно из изображений из любых xcasset файлов в Core не отображается.

Я (наивно) пытаюсь загрузить изображения с помощью категории на UIImage следующим образом:

@implementation UIImage (Bundle)

+ (UIImage *)imageNamed:(NSString *)name bundle:(NSBundle *)bundle
{
    if (!bundle)
        return [UIImage imageNamed:name];

    UIImage *image = [UIImage imageNamed:[self imageName:name forBundle:bundle]];
    return image;
}

+ (NSString *)imageName:(NSString *)name forBundle:(NSBundle *)bundle
{
    NSString *bundleName = [[bundle bundlePath] lastPathComponent];
    name = [bundleName stringByAppendingPathComponent:name];
    return name;
}
@end

Раньше Core был submodule, и это решение работало нормально. Однако при проверке моего предыдущего файла bundle (отдельно от main bundle) я заметил, что все изображения просто копируются в bundle... i.e.

Image.png, [email protected] и т.д. были в комплекте.

При проверке CocoaPods -порожденного расслоения он содержит

Assets.car

который, как я понимаю, является комбинированной, скомпилированной версией всех файлов xcasset в указанном подкаталоге Core.

Как загрузить изображения из этого скомпилированного Assets.car в этот пакет ресурсов Core?

Как взломать, я полагаю, я мог бы...

ссылка на синтаксис Podspec дает это в качестве примера:

spec.resource = "Resources/HockeySDK.bundle"

Это, по-видимому, предполагает, что можно создать пакет вручную в Xcode и CocoaPods просто скопировать его.

Это скорее хак, чем решение.

Я считаю, что CocoaPods (v 0.29+) может справиться с этим полностью...?

Ответ 1

Я был в той же ситуации, что и вы, и я закончил с "взломом", который вы упомянули, но он автоматизирован во время установки pod, поэтому он намного удобнее обслуживать.

В моем podspec у меня есть

# Pre-build resource bundle so it can be copied later
  s.pre_install do |pod, target_definition|
    Dir.chdir(pod.root) do
      command = "xcodebuild -project MyProject.xcodeproj -target MyProjectBundle CONFIGURATION_BUILD_DIR=Resources 2>&1 > /dev/null"
      unless system(command)
        raise ::Pod::Informative, "Failed to generate MyProject resources bundle"
      end
    end
  end

Затем позже в podspec:

  s.resource = 'Resources/MyProjectBundle.bundle'

Трюк здесь заключается в том, чтобы собрать пакет перед установкой pod, чтобы доступный .bundle был доступен, и его можно просто связать, как если бы он был в источнике все время. Таким образом, я могу легко добавить новые ресурсы /images/xibs в цель пакета, и они будут скомпилированы и связаны. Работает как шарм.

У меня есть категория в NSBundle + MyResources, которая позволяет легко получить доступ к ресурсам пакета:

+ (NSBundle *)myProjectResources
{
    static dispatch_once_t onceToken;
    static NSBundle *bundle = nil;
    dispatch_once(&onceToken, ^{
        // This bundle name must be the same as the product name for the resources bundle target
        NSURL *url = [[NSBundle bundleForClass:[SomeClassInMyProject class]] URLForResource:@"MyProject" withExtension:@"bundle"];
        if (!url) {
            url = [[NSBundle mainBundle] URLForResource:@"MyProject" withExtension:@"bundle"];
        }
        bundle = [NSBundle bundleWithURL:url];
    });
    return bundle;
}

Итак, если вы хотите загрузить, например, базовая модель данных:

NSURL *modelURL = [[NSBundle myProjectResources] URLForResource:@"MyModel" withExtension:@"momd"];

Я также использовал некоторые удобные методы для доступа к изображениям:

+ (UIImage *)bundleImageNamed:(NSString *)name
{
    UIImage *imageFromMainBundle = [UIImage imageNamed:name];
    if (imageFromMainBundle) {
        return imageFromMainBundle;
    }

    NSString *imageName = [NSString stringWithFormat:@"MyProject.bundle/%@", name];
    UIImage *imageFromBundle = [UIImage imageNamed:imageName];
    if (!imageFromBundle) {
        NSLog(@"Image not found: %@", name);
    }
    return imageFromBundle;
}

Пока у меня это не получилось.