Using storyboards for developing a static library in iOS - ios

I am a new iOS developer. I have to develop a static library. I have number of viewcontrollers and the flows between them are defined using a story board. I have created a two targets from my project. One is a static library and the other is a bundle. I use my bundle to include my story board in it. I have used this code to launch my first viewcontroller from the storybaord.
-(void)showFromViewController:(UIViewController *)vc{
NSBundle * bundle = [NSBundle bundleWithURL:[[NSBundle mainBundle] URLForResource:#"storyBoards" withExtension:#"bundle"]];
UIStoryboard * libStoryBoard = [UIStoryboard storyboardWithName:#"Main1" bundle:bundle];
ViewController1 * viewController = [libStoryBoard instantiateViewControllerWithIdentifier:#"ViewController1"];
[vc presentViewController:viewController animated:YES completion:NULL];
}
vc is a ViewController that calls this function.
And yes ViewController has target membership with the static library.
However after including the '.a' and '.bundle' in another project and calling the above function it throws an error in the console Log.
Unknown class ViewController1 in Interface Builder file.
Can anyone suggest meright way to use a story board along with a static library. And if Yes then can you point out the right way to launch the first viewcontroller from the storyboard who's class is included in the static library.

simply you can navigate like this
LoginViewController *loginVC=[self.storyboard instantiateViewControllerWithIdentifier:#"loginView"];
[self presentViewController:loginVC animated:YES completion:nil];

I have a similar setup. I have my main project, and I have a ModelController sub project which has a static library and a resources bundle that are used in my main project.
I created a storyboard and a test view controller and used your method above to load.
The only things that might catch you out are in your static library > target > build phases > copy headers > ensure you add your ViewController1.h file into this list.
Other than that, everything worked fine for me.

One possible cause here is that the view controller class (implemented in the static library) is stripped out by the linked, and therefore unavailable to the storyboard loader at runtime. I ran into this problem, and it went away when I made sure that the class in question was referenced from the code that was using the storyboard.
In my case that was easy because I needed to reference the class anyway (I just hadn't written that code yet), but I verified that [ViewController class] was enough to prevent the linker from erroneously stripping the class out.

Related

How can I include my resource files in my framework without using a separate bundle?

I've been following this guide to create an iOS static library: https://github.com/jverkoey/iOS-Framework#walkthrough. I managed to create a framework that can be imported into another Xcode project.
Now, I want my framework to be able to show a Storyboard. I imagine that the .storyboard file counts as a resource. The previous guide states that I should create a Bundle for my resource files, such as images, instead of putting them in the framework itself.
However, I do want to put them in the framework itself. I don't want to use a separate bundle.
All guides I find around tell me the same thing. I understand the advantages of using a separate bundle, but I just don't want to do it right now.
Now then, I am lost on how to include my .storyboard file in my framework so that I can show it with this:
UIStoryboard *sb = [UIStoryboard storyboardWithName:#"NameOfStoryboard" bundle:[NSBundle bundleForClass:[self class]]];
UIViewController *vc = [sb instantiateViewControllerWithIdentifier:#"NameOfViewController"];
[otherView presentViewController:vc animated:YES completion:NULL];
The above code does not seem to work (it can't find the storyboard file). I imagine this is because the .storyboard is not currently included in the framework. Sadly, I don't know how to include it.
In the framework's Xcode project, under Build Phases, I see a tab labeled "Copy files" which looks like what I need.
Now, I'm not sure what this is doing, but in any case, it doesn't seem to be working anyway.
I also did this:
How can I include my .storyboard file in my framework without using a separate bundle?
Why don't you want to use separate bundle for a framework? So if an app is using your framework it would be able to use resources from it(Xibs, storyboards, whatever)
For example a call from the app that uses your framework can look something like this:
FrameworkViewController *frameworkView = [[FrameworkViewController alloc] initWithNibName:#"FrameworkViewController"
bundle:[NSBundle yourFrameworkBundle]];
and in your framework you can write a helper class NSBundle+YourFrameworkBundle that gives access to framework bundle:
NSBundle+YourFrameworkBundle.h
#interface NSBundle (YourFrameworkBundle)
+ (NSBundle *)yourFrameworkBundle;
#end
NSBundle+YourFrameworkBundle.m
#import "NSBundle+YourFrameworkBundle.h"
#implementation NSBundle (YourFrameworkBundle)
+ (NSBundle *)yourFrameworkBundle
{
static NSBundle *frameworkBundle = nil;
static dispatch_once_t predicate;
dispatch_once(&predicate, ^{
NSString *mainBundlePath = [[NSBundle mainBundle] resourcePath];
frameworkBundle = [NSBundle bundleWithPath:[mainBundlePath stringByAppendingPathComponent:#"YourFrameworkBundle.bundle"]];
});
return frameworkBundle;
}
#end
To bundle Resources for the framework create a separate target where you would link all your resources.

iOS Today Extension created as .app rather than .appex

I'm trying to add a Today Extension to a project I've been working on for quite some time. In fact the app is in the AppStore already and I'm looking to enhance it with a Today Extension.
The problem is that the Extension won't launch at all. Not on the device nor on the simulator.
EDIT: just skip the next sections and read on at the last EDIT as I think I found the problem. I just not sure how to fix it.
I've done a test project following a tutorial and it works just fine. The environment seem(!) to be identical. Xcode 6.1.1, iOS 8.1 on the device and simulator.
My project is Objective-C based. For the Extension I’ve tried both Objective-C and Swift targets. On both occasions all three (four with obj-C) files were created as expected (storyboard, viewController and PLIST).
Having done nothing more (as with the example project) I'm trying to launch the widget with the widget scheme selected. With the test projects the widget would launch while it won't with the actual project.
I put a println()/NSLog in the viewDidLoad of the widgets viewController to see if anything happens but nothing.
Happy to provide code or settings but at this pointing time I've no idea where to start.
I just realised that with the test project the today view would launch/appear automatically when the widget gets run from Xcode. With my actual project I'm just getting the HomeScreen and have to pull down the Today view myself. So, really nothing at all happens regarding the widget while everything looks identical compared to the test project.
Any help is appreciated.
EDIT: Here is something I came across which might constitute the problem. The widget never gets launched really and gets stuck at ´Waiting to Attach´ in Xcode's Debug navigator. While other seemed to have had the same problem all potential solutions I found so far did't work for me.
EDIT: I noticed that when I add a Today widget as a target the binary is named .app. All test projects I did the binary gets created as .appex. All the information on the web suggests that it should be named .appex really. Where does this come from and how do I alter this?
I had the same problem.
The following steps helped:
selected target Today Extortion -> Build Settings -> line Wrapper Extension add (change) value to appex
See:
Same problem happened today when I created a Notification Content extension in an old project.(2016, Xcode8 iOS10)
Finally I found the cause:
"Wrapper Extension" in Build Settings of the project was “app”, and when the new target of extension was created, "Wrapper Extension” inherited from the project settings as “app”.
Clearing the project setting before adding an extention target will make Xcode creat an extention as “appex” automatically.
I am herewith sharing the step and source code.
Step 1:- App extension must have a containing app - you can't just create an app extension to be downloaded from the store, first create a regular app to contain the app extension. For the sake of this demonstration just create a new single view project and leave it untouched. Go to File-> New-> Project and select Single view application under iOS -> Applications call it 'ExtendableApp'.
Step 2:- If you want to create your custom experience simply set your ExtensionViewController to inherit from UIViewController, Once your extension is activated all the regular viewDidLoad, viewDidAppear, etc will be called.
Step 3:- In your controller storyboard create outlets for button, I am herewith describing 3 buttons.
Step 4:- In ExtensionViewController.m write
- (void)viewDidLoad {
[super viewDidLoad];
self.preferredContentSize = CGSizeMake(self.view.frame.size.width, 60.0f);
// Do any additional setup after loading the view from its nib.
}
Step 5:- I am assuming that you have set the outlets and IB Action of your buttons in extension storyboard
- (IBAction) mActionButtonTapped :(UIButton *) sender {
switch (sender.tag) {
case 0: {
NSURL *url = [NSURL URLWithString:#"IDENTIFIER_1://"];
[self.extensionContext openURL:url completionHandler:nil];
}
break;
case 1: {
NSURL *url = [NSURL URLWithString:#"IDENTIFIER_2://"];
[self.extensionContext openURL:url completionHandler:nil];
}
break;
case 2: {
NSURL *url = [NSURL URLWithString:#"IDENTIFIER_3://"];
[self.extensionContext openURL:url completionHandler:nil];
}
break;
default:
break;
}
}
Step 6:- In your project write these code in appDelete.m
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
[self appExtensionCallBack:url.absoluteString];
return YES;
}
- (void) appExtensionCallBack :(NSString *)urlString {
if ([urlString isEqualToString:#"IDENTIFIER_1://"]) {
[self.tabBarController setSelectedIndex:0];
} else if ([urlString isEqualToString:#"IDENTIFIER_2://"]) {
[self.tabBarController setSelectedIndex:1];
} else if ([urlString isEqualToString:#"IDENTIFIER_3://"]) {
[self.tabBarController setSelectedIndex:2];
}
}
Note :- I am using Tab Bar Controller in my project, You can give own respected controller.
- (void) moveToControllerScene {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:STORY_BOARD_IDENTIFIER bundle:nil];
YOUR_CONTROLLER_OBJECT *obj = [storyboard instantiateViewControllerWithIdentifier:#"YOUR_CONTROLLER_OBJECT"];
[navController pushViewController:obj animated:YES];
}
Step 7:- For testing the Extension in real device you have to make a separate App ID and Provisioning profile. Delete appropriate provisioning profile in extension and ur project.

Vector file not found in Metaio cloud plugin viewcontroller

I have installed a Metaio SDK in my IOS app and currently i am getting an error in the MetaioCloudPluginViewController.h that the vector file is not found, i have tried to change the type from .m or .mm where i have used this sdk file but unfortunately if i would do it then the new errors are popping up such as "comparison between pointer and integer". I have changed few things in my build setting but still the result is same.
This the file which i am including in the stated viewcontroller.
#include <vector>
The below code is used in one of the viewcontroller.m file.
- (IBAction)onStartPushed:(id)sender {
// Create a new ARViewController. All channel details and properties are defined in that class.
// see ARViewController.mm for the implementation
ARViewController* metaioCloudPlugin = [[ARViewController alloc] init];
// present the viewcontroller
[self presentViewController:metaioCloudPlugin animated:YES completion:nil];
// release it, because it's retained as modalViewController
//[metaioCloudPlugin release];
}
Thanks for your time.
You need to rename your viewcontroller.m to viewcontroller.mm file because there is a C++ code.
Hope this helps.

Aviary SDK crash on initializing on iOS

I integrate Aviary SDK on my app to enhance my app image editor feature. I read its documents, run its sample code and it works fine. But when run on my app, I face an issue. It crashed EXC_BAD_ACCESS after run over a method
[AFOpenGLManager beginOpenGLLoad];
I followed the setup guide on Aviary document
https://developers.aviary.com/docs/ios/setup-guide#project-setup
At first, I just create a Singleton manager to manage. I call [AFOpenGLManager beginOpenGLLoad]; on init function
- (id)init {
if (self = [super init]) {
[AFOpenGLManager beginOpenGLLoad];
}
return self;
}
- (void) launchPhotoEditorWithImage:(UIImage *)editingResImage
highResolutionImage:(UIImage *)highResImage
fromController:(UIViewController *)controller
{
// Customize the editor's apperance. The customization options really only need to be set
once in this case since they are never changing, so we used dispatch once here.
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[self setPhotoEditorCustomizationOptions];
});
// Initialize the photo editor and set its delegate
AFPhotoEditorController * photoEditor = [[[AFPhotoEditorController alloc]
initWithImage:editingResImage] autorelease];
[photoEditor setDelegate:self];
// If a high res image is passed, create the high res context with the image and the
photo editor.
if (highResImage) {
[self setupHighResContextForPhotoEditor:photoEditor withImage:highResImage];
}
// Present the photo editor.
[controller presentViewController:photoEditor animated:YES completion:nil];
}
After run over the init function, it crashed on
Do I miss somethings, the sample code run well.
Edit 1:
compileShader is called from createProgram but I can read this method
Edit 2:
I realize somethings. My app project has a lib named libmediastreamer_voip.a . I think there is misunderstanding. I mean maybe Aviary lib and libmediastreamer_voip.a lib also have the function named compileShader. So when on Aviary lib calls compileShader it runs on compileShader on Aviary lib but run into compileShader on libmediastreamer_voip.a.
I wonder I could be like that? I create a new project and integrate Avairy SDK, it works well, just integrate to my app it crashes
I am a member of the iOS team at Aviary. This is caused by a conflict between our compileShader function and yours. Our function was not properly namespaced and resulted in the conflict. We will be addressing this in the next release of the SDK.
Michael
What I think about it. Check your shader value. It should have correct shader path from your resources or somewhere else with appropriate type (GL_VERTEX_SHADER or GL_FRAGMENT_SHADER).
Seems to me you've it's nil

Creating a custom cocoa pod with a storyboard in it

I am creating a pod, and in the resource bundle I have a storyboard (localised).
When I try to instantiate a storyboard, an error occurred: Could not find a storyboard named 'MyStoryboard' in bundle NSBundle. The code look like this:
NSURL *bundleURL = [[NSBundle mainBundle] URLForResource:#"MyBundle" withExtension:#"bundle"];
NSBundle *bundle = [NSBundle bundleWithURL:bundleURL];
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MyStoryboard" bundle:bundle];
MyBundle structure looks like this:
- MyBundle.bundle
- Base.lproj
- MyStoryboard.storyboard
- es.lproj
- MyStoryboard.strings
Can storyboard can be included in a bundle in the first place?
I have not seen examples of Pod that includes storyboards. If you know of any pods that share their storyboard, let me know too.
There are two things to keep in mind.
You add your pod resources via a predefined bundle like
s.resources = ["Resources/Pod.bundle"]
in this case the content of your bundle will be copied to your xcode project without any "further processing". This means that storyboards or xib files will not be compiled and won't be available in your project.
You can explicitly mention your storyboard/nib files like
s.resources = ["Resources/**/*.storyboard"]
In this case the storyboard will be compiled and will be available in your project. The downside of this (at the moment of this writing) is that you can not use localized storyboards, because all storyboards will be processed and copied at the root location of your bundle. So storyboards with the same name in different .lproj folders will be overwritten.
You want the resources option. Here are some specs that include theirs:
JCAutocompletingSearch/0.9.2/JCAutocompletingSearch.podspec
JCAutocompletingSearch/0.9.3/JCAutocompletingSearch.podspec
JCAutocompletingSearch/0.9.4/JCAutocompletingSearch.podspec
JCAutocompletingSearch/0.9.5/JCAutocompletingSearch.podspec
JCAutocompletingSearch/0.9.6/JCAutocompletingSearch.podspec
Keystone-Contacts-iOS/1.1.4/Keystone-Contacts-iOS.podspec
LumberjackConsole/2.0.0/LumberjackConsole.podspec
LumberjackConsole/2.0.1/LumberjackConsole.podspec
Mixpanel/2.1.0/Mixpanel.podspec
Mixpanel/2.2.0/Mixpanel.podspec
Mixpanel/2.2.1/Mixpanel.podspec
Mixpanel/2.2.2/Mixpanel.podspec
Mixpanel/2.2.3/Mixpanel.podspec
Mixpanel/2.3.0/Mixpanel.podspec
Mixpanel/2.3.1/Mixpanel.podspec
Mixpanel/2.3.2/Mixpanel.podspec
Mixpanel/2.3.4/Mixpanel.podspec
Mixpanel/2.3.5/Mixpanel.podspec
OpenBLE/1.0.0/OpenBLE.podspec
I solved my problem by using this line code to get bundle
let bundle = Bundle(for: type(of: self))
I currently have the same issue here. While not answering the question itself, I'd like to provide additional information that most likely is valid in your case, too:
Calling
NSString *path = [bundle pathForResource:#"MyStoryboard" ofType:#"storyboard"];
NSLog(#"path: %#",path);
will print
/var/mobile/Containers/Bundle/Application/_identifier_/MyApp.app/MyBundle.bundle/Base.lproj/MyStoryboard.storyboard
i.e. the storyboard itself is found, but not loadable "the normal way".

Resources