SideMenu: How to include in Objective-C project? - objective-c

I'm trying to use the project SideMenu (https://github.com/jonkykong/SideMenu) inside my Objective-C code (I saw the #objc/#objcMembers syntax so I'm guessing it should be possible) and I'm not using storyboards.
Can the controller be used in this scenario? If so, how?
It seems I correctly imported the module as I'm able to see the classes with autocompletion, but if I try to instantiate a SideMenuNavigationController, I cannot access the initWithRootViewController method.
Is there anybody who could point me in the right direction?
Thanks

Not sure if you already figured this out, but in Objective-C, the class is exposed as UISideMenuNavigationController instead. So, you end up with:
UISideMenuNavigationController *menu = [[UISideMenuNavigationController alloc] initWithRootViewController:controller];

Here is the solution I adopted, in case someone was running into the same problem.
In your pod file, use this fork of the SideMenu project:
pod 'SideMenu', :git => 'https://github.com/DanielFontes/SideMenu.git', :commit => '52361cfee8cd89698cc131729d9f337d8fafcffe';
Then, you can instantiate SideMenu as you normally would with an Objective-C class; here is how I configured it in my project:
YourViewController *_view = [[YourViewController alloc] initWithNibName:#"NibName" bundle:nil];
SideMenuSettings *_settings = [[SideMenuSettings alloc] init];
[_settings setPresentationStyle:SideMenuPresentationStyle.menuSlideIn];
SideMenuPresentationStyle *_selectedPresentationStyle = _settings.presentationStyle;
_selectedPresentationStyle.presentingScaleFactor = 0.9;
float width = (self.isiPad)?570:300;
[_settings setMenuWidth:width];
SideMenuNavigationController *_sideMenu = [[SideMenuNavigationController alloc] initWithRootViewController:_view settings:_settings];
[_sideMenu setSideMenuDelegate:self];
[_sideMenu setNavigationBarHidden:YES];
[_sideMenu setLeftSide:YES];
[_sideMenu setStatusBarEndAlpha:0];
[[SideMenuManager defaultManager] setLeftMenuNavigationController:_sideMenu];
[[SideMenuManager defaultManager] addPanGestureToPresentToView:_firstViewController.navigationController.navigationBar];
[[SideMenuManager defaultManager] addScreenEdgePanGesturesToPresentToView:_firstViewController.view];

Related

Phonegap Cordova call javascript functions from Objective-C

I am facing some Objective-C lackiness of knowledge in my PhoneGap App.
I have a library that I need to implement in Objective-C. This Library has some callbacks that I receive in a delegate Class ( called CCController ) :
[MyLib sharedInstance].delegate = self;
This Class is instanciated in the AppDelegate.m like this :
CCController *myClass = [CCController alloc];
[myClass init];
Then, when my Lib sends events, the functions in my CCController are called.
I need, at this point, to call my Javascript functions with a parameter.
How can I implement this ?
I have tried calling a function in AppDelegate.m which contains this :
NSString* jsString = [NSString stringWithFormat:#"myJSFunction(\"%#\");", stringParameter];
[self.viewController.webView stringByEvaluatingJavaScriptFromString:jsString];
But without success, nothing is called in my JS...
How can I implement this ? Thanks for help :)
You have to create a plugin and put the native code there instead using it in the AppDelegate.m.
From the plugin class you can do this:
NSString* jsString = [NSString stringWithFormat:#"myJSFunction(\"%#\");", stringParameter];
[self.webView stringByEvaluatingJavaScriptFromString:jsString];
Plugin development guide

How do I load a nib from a secondary process?

I have a process spawned with NSTask that needs to display a window. I started out just writing all the UI code by hand, but this has become a pain.
So, I created a new class with a xib, MyWindowController. I want to load up an instance of this controller in secondary process and have all the IBOutlets and whatnot work properly.
Here's what I've got so far:
// Get the bundle for the main application (not the subprocess).The executable lives in Contents/Helpers, so look two dirs up from its path for the main app bundle root.
NSArray *executablePathComponents = [[[NSBundle mainBundle] executableURL] pathComponents];
NSIndexSet *indexOfEveryComponentExceptLastTwo = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [executablePathComponents count] - 2)];
NSBundle *myBundle = [NSBundle bundleWithURL:[NSURL fileURLWithPathComponents:[executablePathComponents objectsAtIndexes:indexOfEveryComponentExceptLastTwo]]];
// Load the controller nib.
NSNib *windowControllerNib = [[NSNib alloc] initWithNibNamed:#"MyWindowController" bundle:myBundle];
MyWindowController *windowController = [[MyWindowController alloc] init];
NSArray *topLevelObjects = nil;
[windowControllerNib instantiateNibWithOwner:windowController topLevelObjects:topLevelObjects];
This gives me an instance of the window controller and it displays the window from the nib on screen, so this appears to work. BUT, instantiateNibWithOwner:topLevelObjects is deprecated in favor of instantiateNibWithOwner:topLevelObjects.
Using the non-deprecated method results in an exception: "-[NSNib instantiateWithOwner:topLevelObjects:]: unrecognized selector sent to instance 0x10291ab1"
At the very least I'd like to not use the deprecated method. But maybe there is a better way to approach this whole thing?

xcode with IBAction

I’m trying to make an app in xcode. I have made a class called myApp.m and .h
In my .m I have these lines of code
- (void)loadApp
AlarmItem *item1 = [[[AlarmItem alloc] initWithTitle:#"TEST2"] autorelease];
NSMutableArray *items = [NSMutableArray arrayWithObjects:item1, nil];
RootViewController *rootController = (RootViewController *) [navigationController.viewControllers objectAtIndex:0];
rootController.items = items;
and in my RootViewController I have an this method:
- (IBAction)RefreshMyApp:(id)sender {
MyApp *myApp2 = [[[MyAppalloc] init] autorelease];
[myApp2 loadData];
}
What I’m trying to do is calling the method from the myApp class and displayed in the tableView, but I always get an empty cell.
Any help is appreciated.
Is this meant to get you your UIApplication singleton? (i'm guessing MyAppalloc is a typo and should be MyApp alloc)
MyApp *myApp2 = [[[MyApp alloc] init] autorelease];
if so then you should be doing it like this:
MyApp *myApp2 = (MyApp*)[UIApplication sharedApplication];
If this is not the case you need to make it clearer what MyApp is (your app delegate?)
I guess, your application running in singleton instance, if this is something kind of NSView or a particular control you want to refresh, you could call its particular refresh method like,
[NSTableView reload];
[NSTextField setString];
etc...

Why isn't [NSBundle mainBundle] working here?

I've never loaded a bundle, so I'm not sure why this is not working. I don't think it matters, but the .xib in question here is in the same Resources folder as all my other .xibs.
NSArray *array = [[NSBundle mainBundle] loadNibNamed:#"S3AsyncView" owner:self];
Returns this error:
Instance method -loadNibNamed:owner not found. Return type defaults to id
I find this error strange, because the return type of [NSBundle mainBundle] is of course NSBundle.
There is no such method in NSBundle, hence the error.
I guess you are looking for:
loadNibNamed:owner:options:
Documentation link
You can pass nil to the options, as it expect a NSDictionary
So in your case:
NSArray *array = [[NSBundle mainBundle] loadNibNamed:#"S3AsyncView" owner:self options:nil];
EDIT
If it still doesn't work, verify you have included <UIKit/UIKit.h>.
EDIT 2
Ok, now I see. You tagged your question with iOS, but now you say it's a Cocoa app.
The loadNibNamed:owner:options: is a UIKit addition, so available only on iPhone.
On Mac OS X, you'll use the + (BOOL)loadNibNamed:(NSString *)aNibName owner:(id)owner class method.
So:
NSArray *array = [ NSBundle loadNibNamed: #"whatever" owner: self ];
Three things:
Make sure that you're spelling the method name right. The error message you give shows the method name as: -loadNibNamed:owner:options, which isn't right. There should be a colon after the "options". Perhaps you missed that in pasting the name into your message, but the lesson here is to check carefully that you're using exactly the right method name, with no spelling errors, omitted parts, missing colons, etc.
Make sure that you're linking against UIKit. NSBundle is part of the Foundation framework, but the -loadNibNamed:owner:options: method comes from a UIKit Additions category on NSBundle that's part of UIKit. If you don't link against UIKit, then, NSBundle won't have that method.
I see that you've removed ios from your list of tags. If you're writing for Cocoa and trying to load a nib, see the NSNib class for some convenient methods for loading nibs.
I have come across the very same problem while fixing an issue in a low-level Cocoa/Objective-C++ framework. Strictly speaking, build issue came from this function:
bool osxNibLoadMenuNibFile()
{
const auto cvAppKitVersion = floor( NSAppKitVersionNumber );
if( cvAppKitVersion >= NSAppKitVersionNumber10_8 )
{
NSBundle * mainBundle = [NSBundle mainBundle];
NSDictionary * bundleInfoDict = [mainBundle infoDictionary];
if( bundleInfoDict != nil )
{
NSString * mainNibFleNameStr = [bundleInfoDict valueForKey:#"NSMainNibFile"];
if( mainNibFleNameStr != nil )
{
if( [mainBundle loadNibNamed:mainNibFleNameStr owner:[NSApplication sharedApplication] topLevelObjects:nil] )
{
return true;
}
}
}
}
return false;
}
Clang gave me:
warning: instance method '-loadNibNamed:owner:topLevelObjects:' not found (return type defaults to 'id') [-Wobjc-method-access]
The issue was not a build configuration, as all standard frameworks were there already. The issue was more trivial: the definition of that single method is present in a separate header. So please be sure to add:
#import <AppKit/NSNibLoading.h>
which contains:
#interface NSBundle(NSNibLoading)
- (BOOL)loadNibNamed:(NSNibName)nibName owner:(nullable id)owner topLevelObjects:(NSArray * _Nullable * _Nullable)topLevelObjects API_AVAILABLE(macos(10.8));
#end
Interestingly enough, CLion gaves me "unused import directive" even though I definitely use it. Hope this helps someone!

How do I create my own store by subclassing of IASKAbstractSettingsStore?

First off, InAppSettingsKit is just what I was looking for. Once I figure out some things it will save me tons of time.
My question is: how do I create my own store by subclassing IASKAbstractSettingsStore? The home of IASK states:
The default behaviour of IASK is to store the settings in [NSUserDefaults standardUserDefaults]. However, it is possible to change this behaviour by setting the settingsStore property on an IASKAppSettingsViewController.
and
The easiest way to create your own store is to create a subclass of IASKAbstractSettingsStore.
I've spent a good deal of time combing through the code, and I think I understand the basic structure of it. However, I can't figure out how and what to set the settingsStore property to.
I can see the settingsStore defined and implemented in IASKAppSettingsViewController:
id<IASKSettingsStore> _settingsStore;
and
- (id<IASKSettingsStore>)settingsStore {
if (!_settingsStore) {
_settingsStore = [[IASKSettingsStoreUserDefaults alloc] init];
}
return _settingsStore;
}
I tried subclassing IASKAbstractSettingsStore:
#import <Foundation/Foundation.h>
#import "IASKSettingsStore.h"
#interface IASKSettingsStoreMeals : IASKAbstractSettingsStore {
NSString * _filePath;
NSMutableDictionary * _dict;
}
- (id)initWithPath:(NSString*)path;
#end
and then modified IASKAppSettingsViewController's settingsStore property to allocate and initialize my new class IASKSettingsStoreMeals instead of IASKSettingsStoreUserDefaults - the only way I can see to change the property:
- (id<IASKSettingsStore>)settingsStore {
if (!_settingsStore) {
_settingsStore = [[IASKSettingsStoreMeals alloc] init];
}
return _settingsStore;
}
When I build and run, I get the following message when I try the first control (the toggle switch), all other fields do not get saved:
attempt to insert nil value at objects[0] (key: toggleSwitch)
What am I doing wrong? In addition to the changes needed to "rejigger" the code to use IASKSettingsStoreFile (or a subclassed IASKAbstractSettingsStore), I also can't see where to set the file path change the location of where the settings are saved - or is that done behind the scenes. Looking forward to get past this learning curve and using this.
Found the answer.
My question reveals my inexperience with object orientated languages on the whole, and the concept of encapsulation and frameworks in particular. No changes needed to be made to the IASK framework code, all code was added on my root view controller.
I created another instance of IASKAppSettingsViewController, and added the following code to change the plist location:
// the path to write file
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *settingsFile = [documentsDirectory stringByAppendingPathComponent:#"mySettings"];
IASKSettingsStoreFile *mySettingsBundle = [[IASKSettingsStoreFile alloc] initWithPath:settingsFile];
self.appSettingsViewController.settingsStore = mySettingsBundle;
UINavigationController *aNavController = [[UINavigationController alloc] initWithRootViewController:self.appSettingsViewController];
[mySettingsBundle release];
self.appSettingsViewController.settingsStore = mySettingsBundle;
//[viewController setShowCreditsFooter:NO]; // Uncomment to not display InAppSettingsKit credits for creators.
// But we encourage you not to uncomment. Thank you!
self.appSettingsViewController.showDoneButton = YES;
[self presentModalViewController:aNavController animated:YES];
[aNavController release];