• Building an iOS Universal Static Library


    From: http://blog.coderow.com/2012/08/23/building-an-ios-universal-static-library/

    If you have only built applications in iOS, let this be a gentle introduction to creating static libraries for iOS applications. The reasons for doing this are multiple. You may have a set of applications that need to share code with a very well defined interface. You may want to distribute a library to your customers to allow them to build in some of your technology into their application. You may want to use some Objective-C code into your RubyMotion project. In any case, here is a simple example to take you from an app where the code is all together, to one that uses a library for some of the code.

    The Starting App

    The app that I am using to demonstrate a static library is very simple. There is a class for the view controller and a “computation” class that will be in the library. There is also an application delegate class to get this started.

    To create this app, go to XCode and create an empty sample application called TheQuestion.

    From there, right click on the yellow TheQuestion folder and select New File…. Create an Objective-C class from the iOS | Cocoa Touch menu. Have UIViewController be the superclass and have the class name be QuestionViewController. Do New File again and this time create a class called TheAnswer with a superclass of NSObject.

    You can then copy and paste the following code snippets in.

    AppDelegate.m

    AppDelegate.m - in import section

    1
    
    #import "QuestionViewController.h"
    

    AppDelegate.m - before [self.window makeKeyAndVisible]

    1
    2
    3
    
    QuestionViewController *questionViewController = [[QuestionViewController alloc] init];
    self.window.rootViewController = questionViewController;
    self.window.rootViewController.wantsFullScreenLayout = true;
    

    QuestionViewController.h

    QuestionViewController.h

    1
    2
    3
    4
    5
    6
    7
    8
    
    #import <UIKit/UIKit.h>
    @interface QuestionViewController : UIViewController {
        UILabel *answerLabel;
    }
    @property (nonatomic, strong) UILabel *answerLabel;
    @end
    

    QuestionViewController.m

    QuestionViewController.m

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    
    #import "QuestionViewController.h"
    #import "TheAnswer.h"
    @implementation QuestionViewController
    @synthesize answerLabel;
    - (void)loadView
    {
        [super loadView];
        UILabel *questionLabel = [[UILabel alloc] initWithFrame: CGRectMake(10.0, 50.0, 300.0, 200.0)];
        questionLabel.numberOfLines = 0;
        questionLabel.lineBreakMode = UILineBreakModeWordWrap;
        questionLabel.textAlignment = UITextAlignmentCenter;
        questionLabel.text = @"What is the answer to life, the universe and everything?";
        questionLabel.font = [UIFont systemFontOfSize: 16.0];
        answerLabel = [[UILabel alloc] initWithFrame: CGRectMake(10.0, 250.0, 300.0, 200.0)];
        answerLabel.textAlignment = UITextAlignmentCenter;
        answerLabel.font = [UIFont boldSystemFontOfSize: 24.0];
        [self.view addSubview: questionLabel];
        [self.view addSubview: answerLabel];
    }
    - (void)viewDidLoad
    {
        [super viewDidLoad];
      // Do any additional setup after loading the view.
        TheAnswer *theAnswer = [[TheAnswer alloc] init];
        answerLabel.text = [NSString stringWithFormat: @"%d", [theAnswer ofLifeTheUniverseAndEverything]];
    }
    - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
    {
        return (interfaceOrientation == UIInterfaceOrientationPortrait);
    }
    @end
    

    TheAnswer.h

    TheAnswer.h

    1
    2
    3
    4
    5
    6
    7
    
    #import <Foundation/Foundation.h>
    @interface TheAnswer : NSObject
    - (NSInteger)ofLifeTheUniverseAndEverything;
    @end
    

    TheAnswer.m

    TheAnswer.m

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    #import "TheAnswer.h"
    @implementation TheAnswer
    - (NSInteger)ofLifeTheUniverseAndEverything
    {
        return 42;
    }
    @end
    

    The result should then be:

    Creating the Static Library

    Now that we have a working app, we want to split the TheAnswer class into its own library so we can share its goodness with others. The first step is to create a new project that is a Cocoa Touch Static library. Select New | Project… from the XCode menu and then select Cocoa Touch Static Library and call it the TheAnswerLibrary for the project name.

    After creating the library, you should delete the two generated files called TheAnswerLibrary.h and TheAnswerLibrary.m.

    Then add in TheAnswer.h and TheAnswer.m by:

    • control-clicking on the yellow TheAnswerLibrary folder
    • selecting Add files to “TheAnswerLibrary”…
    • browsing over to the TheQuestion project
    • select both TheAnswer.h and TheAnswer.m

    You library is now complete. Do a build and it should build successfully.

    Creating the App that uses the new library

    The next step is to create a new project that will use the library. Create an empty project like you did in the first step and call it TheQuestionApp. Replace the AppDelegate.m with the AppDelegate.m from the TheQuestion project. Add the QuestionViewController .h and .m files to the TheQuestionApp folder like we did for the TheAnswer .h and .m files for the static library.

    If you try to build it at this point, you will get a TheAnswer.h not found error. You can add TheAnswer.h from the TheQuestion project and it will then compile but will fail to link.

    Getting the library file

    If you go back to the TheAnswerLibrary project and display the Products, you will see the built library: libTheAnswerLibrary.a.

    You want to add this file to the TheQuestionApp project. To add it, control-click on the libTheAnswerLibrary.a and select Show In Finder. You can then just drag this into the TheQuestionApp project files. Alternatively, you could copy the file and paste it into the TheQuestionApp’s folder and then add it using the Add Files option. The former method is nice because it just references the built library so that when you rebuild the library the changes are reflected the next time you do a build in the TheQuestionApp.

    Now that have it in the TheQuestionApp, try to run it in the simulator. You should get the following error:

    This happens because the library that you built only contains symbols for ARM. The simulator builds are i386 builds. If you go back to the TheAnswerLibrary project and selected the scheme TheAnswerLibrary > iPhone 5.1 Simulator and did a build, then it would build an i386 build. I tried to use that library to run in the simulator but got a strange error which said:

    ld: warning: ignoring file /Users/username/Projects/Blogging/combined_library/TheQuestionApp/TheQuestionApp/libTheAnswerLibrary.a, file was built for archive which is not the architecture being linked (i386): /Users/username/Projects/Blogging/combined_library/TheQuestionApp/TheQuestionApp/libTheAnswerLibrary.a

    In order to get it to run on the simulator and on device, you need to combine those libraries into one that contains all the symbols and architectures that you need.

    Generating a combined library

    Go back to the TheAnswerLibrary project and select the blue project icon. We want to add a new target. On the bottom of the project settings, you can add a new target:

    You want to add an Aggregate Target:

    Once the target is added, then you will add a custom script to run for that target. There is a button on the lower right of the project settings:

    After clicking on that, you want to add a run script.

    In the script editor section paste in the following script:

    TheAnswer.m

    1
    2
    3
    4
    5
    6
    7
    
    XCODEBUILD_PATH=/Applications/Xcode.app/Contents/Developer/usr/bin
    XCODEBUILD=$XCODEBUILD_PATH/xcodebuild
    $XCODEBUILD -project TheAnswerLibrary.xcodeproj -target "TheAnswerLibrary" -sdk "iphonesimulator" -configuration "Release" clean build
    $XCODEBUILD -project TheAnswerLibrary.xcodeproj -target "TheAnswerLibrary" -sdk "iphoneos" -configuration "Release" clean build
    lipo -create -output "build/libTheAnswerLibrary-Combined.a" "build/Release-iphoneos/libTheAnswerLibrary.a" "build/Release-iphonesimulator/libTheAnswerLibrary.a"
    

    This builds both versions of the library and then combines them into one that has all the architectures you need. To try this out and see if it is working first before putting it into XCode, create a build.sh file in the root of your project and run it.

    If you select the scheme Combined and then do a build, you will find in your projects folder a build folder that contains the combined library.

    Adding ARM6 support

    If you want your library to run on older iPhones, then you need to add in ARM6 support. To enable this, you want to go to the Build Settings and change the Architectures to include armv6, armv7 and i386. Here is the Architecture line of the build settings:

    When you select the column underneath blue TheAnswerLibrary you should see

    remove the only entry and add in armv6, armv7 and i386.

    Now if you build the combined target, your library will have all the architectures you need.

  • 相关阅读:
    运维岗春招--part2
    python 题库|刷题
    leetcode刷题
    运维面经汇总
    python自动化运维阅读笔记
    Python编程汇总
    old_boy 运维学习-第一期
    团队博客作业-Week3
    个人对final发布产品的排名
    各组对final发布产品的排名
  • 原文地址:https://www.cnblogs.com/simonshi2012/p/3141541.html
Copyright © 2020-2023  润新知