I have recently made some significant changes to a Corona Enterprise app I am writing for iOS. The code was using a .xib file to launch the AppDelegate, and I have removed that and I am loading a different AppDelegate in my main.mm
The following is my main.mm
//
// main.mm
// Examples
//
#import <UIKit/UIKit.h>
#import "CoronaApplicationMain.h"
#import "MyAppDelegate.h"
int main(int argc, char *argv[])
{
#autoreleasepool
{
CoronaApplicationMain( argc, argv, [MyAppDelegate class] );
}
return 0;
}
This is my MyAppDelegate.h
//
// MyAppDelegate.h
//
#import <Foundation/Foundation.h>
#import "CoronaDelegate.h"
#interface MyAppDelegate : NSObject< CoronaDelegate >
#end
And finally, this is MyAppDelegate.mm
//
// MyAppDelegate.mm
//
#import "MyAppDelegate.h"
#import "CoronaRuntime.h"
#import "CoronaLua.h"
#implementation MyAppDelegate
- (void)willLoadMain:(id<CoronaRuntime>)runtime
{
NSLog ( #"willLoadMain" );
}
- (void)didLoadMain:(id<CoronaRuntime>)runtime
{
NSLog ( #"didLoadMain" );
}
#end
I am not posting my main.lua as it seem irrelevant. If I am not posting something that is important, then apparently I am assuming that it is not.
When I run the app in xcode iOS simulator, I get a black screen and my willLoadMain and didLoadMain are never called.
Please let me know if you see something that I am missing.
Thanks,
Roger
My problem was that somewhere I read that I should remove the .xib files (this was not needed). Once I re-added them to the project and updated the app-info.plist, everything began working again. Since I am rather new to Corona Enterprise, Lua and Objective C, I do not understand the details of why this failed and then began working. At any rate, this issue is now resolved.
Related
Trying to get ObjC app project to call Swift function within ObjC static lib..........
My ObjC app project build gets build error for reference to a Swift function that is within an ObjC static lib (.a) that is imported into the app project.
The file Hub_lib-Bridging-Header.h has no code.
OBJ-C APP PROJECT..............................................
ViewController.mm within the ObjC app project...
#import "ViewController.h"
#import "Hub_lib.h"
#import "Hub_lib-Swift.h"
#import "hublib.hpp"
#interface ViewController ()
#end
#implementation ViewController
. . .
- (IBAction)run_simple_central:(id)sender {
[self BLE.start_central];
}
BLE.h within ObjC app project...........
#import <CoreBluetooth/CoreBluetooth.h>
#import "Hub_lib-Swift.h"
#interface BLE: NSObject
//< CBPeripheralManagerDelegate >
#property(strong, nonatomic) CBPeripheralManager* peripheralManager;
#property(strong, nonatomic) CBMutableCharacteristic* transferCharacteristic;
#property(strong, nonatomic) NSData* dataToSend;
#property(nonatomic, readwrite) NSInteger sendDataIndex;
-(void)start_central;
#end /* BLE_h */
BLE.m within app; a wrapper for call to swift..........................
#import "BLE.h"
#import "Hub_lib-Swift.h"
#interface BLE ()
#end
#implementation BLE
-(void)start_central
{
Hub_lib* BLE_central = [Hub_lib new];
[BLE_central centralManager.run_central];
}
made a test project to be able to replicate your errors.
You are close but you need to take care of how your static lib has its internal methods and classes exposed in its header so you can use them elsewhere.
let's begin with the Objective-C Static Library project. Hub_lib.h
#import <Foundation/Foundation.h>
// we want the lib header as clean as possible
// it will then be imported in your project with '#import <Hub_lib/Hub_lib.h>'
// auto-generated swift -> objc bridging header imported here will
// mess it up when imported somewhere else.
// so when using swift->objc bridging place next line in .m file instead
//#import "Hub_lib-Swift.h"
//#class BLE_Central; // pre-declaration of a later fully declared Class.
// as we moved the property into .m file we dont need it here.
#interface Hub_lib : NSObject
// to make this work you would need pre-declaration of BLE_Central, see above interface
//#property BLE_Central *ble; // placed in .m interface extension instead.
-(void)run_central;
#end
static lib counterpart / implementation Hub_lib.m
#import "Hub_lib.h"
#import "Hub_lib-Swift.h"
#interface Hub_lib ()
#property BLE_Central *ble_central;
#end;
#implementation Hub_lib
-(instancetype)init {
if (!(self=[super init])) return nil;
_ble_central = [[BLE_Central alloc] init];
return self;
}
-(void)run_central {
[_ble_central run_central];
}
#end
notice BLE_Central property is placed in the class interface extension and when you want to use swift module stuff that exposes back to objc you need to declare the auto-generated bridge somewhere (best done in .m file #import "Hub_lib-Swift.h")
your BLE_central.swift with its protocol method implementation
import Foundation
import UIKit
import CoreBluetooth
import os
var centralManager: CBCentralManager = CBCentralManager()
class BLE_Central: NSObject, CBCentralManagerDelegate, CBPeripheralDelegate {
func centralManagerDidUpdateState(_ central: CBCentralManager) {
os_log("centralManagerDidUpdateState")
}
var discoveredPeripheral: CBPeripheral?
var transferCharacteristic: CBCharacteristic?
var writeIterationsComplete = 0
var connectionIterationsComplete = 0
let defaultIterations = 5 // change this value based on test usecase
var data = Data()
// as you figured out before we need to expose to #objc
#objc public func run_central()
{
os_log("run_central")
// out-commented for testing purposes
//mobile_sys_hub_lib.centralManager = CBCentralManager(delegate: self, queue: nil, options: [CBCentralManagerOptionShowPowerAlertKey: true])
os_log("Scanning started")
}
}
As long no extra code from objc is used in swift inside the static lib, the
Hub_lib-Bridging-Header.h is empty
//
// Use this file to import your target's public headers that you would like to expose to Swift.
//
Next let's see how to import your static lib in your "sim backend UI" Objective-C Project app.
Goto "sim backend UI" App Target settings > General > Framework, Libraries, and.. > hit the + button and search for your compiled libHub_lib.a file. > select it > hit ok. Should be very much in your framework list by now.
Yes, thats not enough! You have to declare its header in your app project somewhere. Where exactly is up to you. Instead of implementing it multiple times we do the following in BLE.h
#import <Foundation/Foundation.h>
#import <CoreBluetooth/CoreBluetooth.h>
//#import "Hub_lib-Swift.h" // no no no no
#import <Hub_lib/Hub_lib.h> // much better. test-compile once if it is crying
NS_ASSUME_NONNULL_BEGIN
#interface BLE: NSObject
// <CBPeripheralManagerDelegate> // "//<Protocol>" will confuse doxygen
#property (strong, nonatomic) CBPeripheralManager* peripheralManager;
#property (strong, nonatomic) CBMutableCharacteristic* transferCharacteristic;
#property (strong, nonatomic) NSData* dataToSend;
#property (nonatomic, readwrite) NSInteger sendDataIndex;
-(void)start_central;
#end /* BLE_h */
NS_ASSUME_NONNULL_END
counterpart BLE.m
#import "BLE.h"
#implementation BLE
-(void)start_central
{
NSLog(#"invoked BLE start_central");
Hub_lib *Hub_central = [Hub_lib new];
[Hub_central run_central];
}
#end
Your ViewController.m or .mm makes use of BLE.h with its already imported static lib header
#import "ViewController.h"
#import "BLE.h"
#interface ViewController ()
#property (nonatomic) BLE *ble;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
UIButton *btn = [UIButton buttonWithType:UIButtonTypeSystem];
btn.frame = CGRectMake(100, 100, 200, 50);
[btn setTitle:#"run simple central" forState:(UIControlStateNormal)];
[btn setTitleColor:UIColor.greenColor forState:(UIControlStateNormal)];
btn.layer.backgroundColor = UIColor.orangeColor.CGColor;
btn.layer.cornerRadius = 5.0f;
[self.view addSubview:btn];
[btn addTarget:self action:#selector(run_simple_central:) forControlEvents:(UIControlEventTouchUpInside)];
}
- (IBAction)run_simple_central:(id)sender {
// BLE needs to be allocated to take effect.
if (!_ble) _ble = [[BLE alloc] init];
// testing.. should log "run_central" + "Scanning started"
[self.ble start_central];
}
#end
Made a testButton so you can see if the implementation invokes what you expect. Compile!
And? Aoutsch! Does not work. What happened?
If your App is a plain Objective-C project it doesn't know about swift yet and will complain in a weirdo way, possibly via something like
Link: Could not find or use auto-linked library 'swiftCoreImage'
Undefined symbol: value witness table for Builtin.UnknownObject*
Solution: Most easy way is to create a swift file in your app project and allow Xcode to make a bridging header for you. (Alternatively change project settings, search for "bridge" and go step by step thru the properties)
The swift file does not have to have special content.
//
// MakeProjectSwiftCompatible.swift
//
import Foundation
Compile again. now it should work because the partly implemented swift module from within your static lib can properly work when your Objc-App-Project is able to work with swift stuff.
Edit as you asked to work with Objective-C++/C++ in your static library things change a little bit.. so here some additional example code to proof it.
In Hub_lib project (targeting your "framework") add some files which will keep some random testing c++ code
//HubCPP.h
#import <Foundation/Foundation.h>
#include <vector>
NS_ASSUME_NONNULL_BEGIN
class SomeCPPClass
{
public:
SomeCPPClass(id<NSObject> obj, size_t size);
~SomeCPPClass();
id<NSObject> getBuffer() { return buffers[bufferIdx]; }
unsigned int getCurrentIdx();
private:
std::vector <id <NSObject>> buffers;
unsigned int bufferIdx;
bool isReady;
};
NS_ASSUME_NONNULL_END
To make Xcode know that you work with C++ you need to have implementation file ending with .mm and also need to change HubCpp.h "Identity and Type (right Xcode panel while file selected)" to C++ Header
// HubCpp.mm
#import "HubCPP.h"
SomeCPPClass::SomeCPPClass (id<NSObject> obj, size_t size) :
bufferIdx (0),
isReady(false)
{
uint8_t ringSize = 255;
assert (ringSize > 0);
for (uint8_t i = 0; i < ringSize; i++)
{
//buffers.push_back ();
bufferIdx = (unsigned int)size;
}
}
SomeCPPClass::~SomeCPPClass() {
// cleanup allocated stuff here.
}
unsigned int SomeCPPClass::getCurrentIdx() {
return bufferIdx;
}
Rename Hub_lib.m to .mm and change its import rules accordingly to the following ..
#import "Hub_lib.h"
#import <CoreBluetooth/CoreBluetooth.h> //needed because the -Swift.h bridge will cry in the next line
#import "Hub_lib-Swift.h"
#import "HubCPP.h"
lets change the proofing method in Hub_lib.mm so it really uses C++
-(void)run_central {
[_ble_central run_central];
SomeCPPClass *cpp = new SomeCPPClass(#"justSomeNSStringObject",2);
unsigned int idx = cpp->getCurrentIdx();
NSLog(#"objectiveCplusplus testIdx = %u", idx);
}
Compile Hub_lib (scheme). It should work by now and also accept the use of #import <vector>.
If this works go on and change your Objc-Project-App.
Switch your compile Scheme to target your Objc-App.
Change file name BLE.m to BLE.mm (makes it a Objective C++ Source)
Change file name BLE.h to BLE.hh (makes it a C++ header)
Change in BLE.mm #import "BLE.h to #import "BLE.hh
in ViewController.m kick out the line #import "BLE.h" and replace it into ViewController.h instead as #import "BLE.hh"
(In general its much easier to keep your compiler informed what language to expect in implementation when you place import headers in header files.)
Compile. Thats it! Your Objective-C++ static lib should properly work at this point.
Edit
You can find a ready made workspace for Xcode here...github: combine cpp swift and objective-c in static lib
Solution from StackO user: Asperi
Emptied top folder
Created workspace at top folder
1.1 Copied clean app and lib to top folder
Add ObjC lib .xcodeproj to workspace using Xcode > File > Add files ...
Add ObjC app .xcodeproj to workspace
Added dependency of sim_backend_UI to lib via workspace
a. app proj > General tab > Frameworks, Libs.. > +
b. Select lib .a
c. Add.
Add Some.swift (any swift file you want) to sim_backend_UI, just for the purpose Xcode add required system swift dynamic libraries (which will be needed for swift part in static library as well)... and confirm creating bridge in appeared dialog
a. new file > Swift > Some.swift
b. Create Bridging Header
c. Added to Some.swift ...
import Foundation
struct Some{}
Set Xcode active scheme to app and target device
Build
"succeeded"
I'm doing a Tweak and i use Flex to edit some Obj-C but one of these i cant edit so, i think if i do a Tweak with MSHook can resolve this, BUT NO idk how to write correctly i'm new on this, i want to disable "shootCooldown" but idk if is posible, so this is my code on Tweak.x
#import <substrate.h>
#import <Foundation/Foundation.h>
#interface ControlsWidget : NSObject {
NSString *_shootCooldown;
}
#end
NSString *_shootCooldown;
%hook ControlsWiget
{
shootCooldown = MSHookIvar<BOOL>(self, "_someBOOL");
}
%end
I have an iOS project that uses both Obj-C and Swift.
In main.m, I want to instantiate a variable to be accessed by Swift. The specific use case is to store the absolute time at main, and then measure time elapsed since main elsewhere.
Here's what my relevant files look like:
main.m
#import <UIKit/UIKit.h>
CFAbsoluteTime StartTime;
int main(int argc, char* argv[])
{
StartTime = CFAbsoluteTimeGetCurrent(); // This is what I want to access elsewhere.
#autoreleasepool {
...
}
}
myapp-Bridging-Header.h
#import "AppDelegate.h"
extern CFAbsoluteTime StartTime;
AppDelegate.h
#import <UIKit/UIKit.h>
extern CFAbsoluteTime StartTime;
#interface AppDelegate : NSObject <UIApplicationDelegate>{}
#property (nonatomic, strong) IBOutlet UIWindow* window;
// ... other irrelevant #property
#end
And then in the actual .swift file, I'm just trying to access StartTime without declaring anything (as I thought it worked since it's being externed), but I'm getting an unresolved identifier error.
My Car.m implementation file is as follows. Here I have 1 private method engineStarting.
Here I have used class extension concept to introduce
private method and I have also used Car+Maintainance as a category.
#import "Car.h"
//private methods
#interface Car()
-(BOOL) engineStarting;
#end
#implementation Car
#synthesize model=_model;
-(void)drive{
NSLog(#"%# is driving",_model);
}
-(void)stop{
NSLog(#"%# has stopped now",_model);
}
-(void)turnleft{
NSLog(#"%# is turning left",_model);
}
-(void)turnright{
NSLog(#"%# is turning right",_model);
}
-(BOOL) engineStarting{
return true;
}
My main.m file looks like
#import <Foundation/Foundation.h>
#import "Car.h"
#import "Car+Maintanance.h"
int main(int argc, const char * argv[]) {
#autoreleasepool {
// insert code here...
NSLog(#"Hello, World!");
Car *car=[[Car alloc]init];
car.model=#"maruti";
//using car its own methods
// i am getting error in this line(no visible #interface......)
[car engineStarting];
[car drive];
[car stop];
[car turnleft];
[car turnright];
//using maintainanace
if([car neddOilChange]){
[car changeOil];
}
}
return 0;
}
As you said you've created private method -(BOOL) engineStarting which means you can access it just within car class.
If you want that method to be visible in your main.m file move the declaration to car.h file it will make it public.
You say that you want to keep -engineStarting privately, but use it outside the implementation? That's contradictory, because private means: "Unvisible outside the implementation."
Probably you are messed up with the terms. And you are right in a way: There is no black and white private/public pair, but a greyscale: Something can be visible to an implementation only (usually called private), to an implementation and subclass implementations (usually called protected), to an implementation and subclass implementations and friend classes (in a framework, usually called package) and public at all. Beside this you can have the desire to make a method public only to some subsystems (modules) and so on. So it is very complex.
What you can do for it, is to create a separate category and import the header of that category file to the area, where it should be visible.
//Car_PublicInFrameworkAddition.h
#interface Car(PublicInFrameworkAddition)
-(BOOL) engineStarting;
#end
//Car_PublicInFrameworkAddition.m
#implementation Car(PublicInFrameworkAddition)
-(BOOL) engineStarting
{
…
}
#end
Somewhere.m
// Somewhere should see the addition
#import "Car_PublicInFrameworkAddition.h"
I keep reading different things about this and it seems dangerously confusing. Can someone please tell me the proper pattern to define notification strings that can be used globally? Everything I've tried have caused linker errors. For example, in my GlobalVariables singleton I added:
#import <Foundation/Foundation.h>
extern NSString *kMPTimeChanged;
#interface GlobalVariables : NSObject etc.
And then in the init:
#implementation GlobalVariables
#pragma mark Singleton Methods
+ (id)sharedGlobals {
static GlobalVariables *sharedGlobals = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedGlobals = [[self alloc] init];
});
return sharedGlobals;
}
- (id)init {
if (self = [super init]) {
kMPTimeChanged=#"kMPTimeChanged";
return self;
}
It didn't build, I got multiple errors.
In your .h file you should write:
extern NSString * const kMPTimeChanged;
In your .m file, you should write:
NSString * const kMPTimeChanged = #"My Constant";
Both of these of these should be outside of your #interface and #implementation blocks.
I'd recommend declaring your variables as const extern. Then:
// Globals.h
extern NSString * const kMPTimeChanged;
// Globals.m
NSString * const kMPTimeChanged = #"...";
If your values are constants, just use a header, for example called Constants.h. In this header you can declare constants like this:
#define kMPTimeChanged #"kMPTimeChanged"
I don't like the extern variables. Sometimes it's hard to figure out where they came from and I wind up having to do searches on large code bases for poorly named variables which just seem to exist from no where. I guess I'm sort of in the global variables are evil crowd. Still, they are useful, so I have my own solution.
My solution is simple Constants class with a bunch of static methods, properties, whatever is needed (all read only of course). The problem is you are stuck importing this class in everywhere! There is an easy solution to that though.
In the import in your project-Prefix.pch file. This will automatically get added to all your code and you'll be able use your constants and still know where they are coming from without having to think about it.
Here is an example of my project-Prefix.pch file
#import <Availability.h>
#ifndef __IPHONE_5_0
#warning "This project uses features only available in iOS SDK 5.0 and later."
#endif
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#import "Constants.h"
#endif
Now you access Constants.serverUrl anywhere and still know exactly where serverUrl came from.