I have function in Functions.h that I want to use from another h file.
I tried:
#import "Functions.h"
....
Functions *Func = [[Functions alloc]init];
[self performSelectorInBackground:#selector(?????????) withObject:nil];
Is it even possible?
If the methods are instance methods,
Functions *func = [[Functions alloc] init];
[func performSelectorInBackground:#selector(theMethodToRunInBackground) withObject:nil];
If they are class methods,
[Functions performSelectorInBackground:#selector(theMethodToRunInBackground) withObject:nil];
You should use Func instead of self
[Func performSelectorInBackground:#selector(function) withObject:nil];
Related
I am having trouble getting MFMessageCompose to work with Unity3D iOS Plugin.
I got an alert window to pop up with buttons but I am having an error when accessing the MFMessageComposer. Can't seem to get the method to pop up the window properly.
Here is my iOSBridge.h (linked file if you want):
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import <MessageUI/MessageUI.h>
#interface Delegate : NSObject <UINavigationControllerDelegate, MFMessageComposeViewControllerDelegate>
#end
And my iOSBridge.mm file:
#import "iOSBridge.h"
#implementation Delegate
//Trying to still understand the meaning behind this line. Why???
-(id)init
{
return self;
}
//RATE US Button Numbers
//Not entirely sure What I did here but it still bring it up. This section has nothing to do with SMS
-(void) alertView: (UIAlertView*)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
//Give back the number of the button
NSString *inStr = [NSString stringWithFormat:#"%d", (int)buttonIndex];
const char *cString = [inStr cStringUsingEncoding:NSASCIIStringEncoding];
UnitySendMessage("Popup", "UserFeedBack", cString);
NSLog(#"%li", (long)buttonIndex);
} // RATE US button number end
-(void)SMS:(id)sender{
MFMessageComposeViewController *controller = [[MFMessageComposeViewController alloc] init];
[controller setMessageComposeDelegate:self];
if([MFMessageComposeViewController canSendText]){
[controller setRecipients:[NSArray arrayWithObjects:nil]];
[controller setBody:[NSString stringWithFormat:#"Text"]];
//WHYYY do you not work
//[self presentViewController:controller animated:YES];
Delegate *appDelegate = UIApplication.sharedApplication.delegate;
[appDelegate.window.rootViewController presentViewController:controller animated:YES completion:nil]
}
}
#end
static Delegate* delegateObject;
extern "C"
{
//A method for unity can run
void _AddNotification(const char* title,
const char* body,
const char* cancelLabel,
const char* firstLabel,
const char* secondLabel)
{
//Don't have a full grasp of this delegateObject thing yet.
if(delegateObject ==nil){
delegateObject = [[Delegate alloc]init];
}
//iOS Alert Pop up view RATE OUR GAME
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle: [NSString stringWithUTF8String:title]
message:[NSString stringWithUTF8String:body] delegate:delegateObject
cancelButtonTitle:[NSString stringWithUTF8String:cancelLabel]
otherButtonTitles:[NSString stringWithUTF8String:firstLabel],[NSString stringWithUTF8String:secondLabel], nil];
[alert show];
} //End of _AddNotification
//SMS Method for Unity to use
void _SMSGO(const char* Mbody){
MFMessageComposeViewController *controller = [[MFMessageComposeViewController alloc] init];
if([MFMessageComposeViewController canSendText]){
NSString *s = [NSString stringWithFormat:#"%s", Mbody];
controller.body = s;
//Suppose to Brings up the SMS view not sure why it isnt working or how to make this work
//If this can work its major progress
[delegateObject presentViewController:controller animated:YES];
}
}
}
So these:
-(void) alertView: (UIAlertView*)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
NSString *inStr = [NSString stringWithFormat:#"%d", (int)buttonIndex];
const char *cString = [inStr cStringUsingEncoding:NSASCIIStringEncoding];
UnitySendMessage("Popup", "UserFeedBack", cString);
NSLog(#"%li", (long)buttonIndex);
}
-(void)SMS:(id)sender{
MFMessageComposeViewController *controller = [[MFMessageComposeViewController alloc] init];
[controller setMessageComposeDelegate:self];
if([MFMessageComposeViewController canSendText]){
[controller setRecipients:[NSArray arrayWithObjects:nil]];
[controller setBody:[NSString stringWithFormat:#"Text"]];
//WHYYY do you not work
//[self presentViewController:controller animated:YES];
Delegate *appDelegate = UIApplication.sharedApplication.delegate;
[appDelegate.window.rootViewController presentViewController:controller animated:YES completion:nil]
}
}
Code blocks are actually not being accessed at all through your bridge. So nothing in this will be touched at all.
The - (id) init is the initializer of the class. So in order to access anything in that file from anything else, you have to init it first. An easier way to think of this is:
extern.c is a separate file.
static Delegate *delObj;
extern "C"
{
void _callMain (const char *hello) {
/**
* delObj is a static so it "Will be once it is" so it will be
* in memory (mallocated) the moment you tell it to be something.
*/
if (!delObj) {
In this case, we want that static object to be an instance of Delegate (not a particularly good name to set your class to, it will lead to much confusion). We "start" or initialize this class by calling init and we tell it this is an object we need, chuck it on the heap read this.
delObj = [[Delegate alloc] init];
}
// Now we can call the function in the next file
[delObj helloWorld];
}
Delegate.m - Think of this as a different file. You can access this file from extern.c because (in reality) it's just included in the same file. But this of this as a separate entity entirely. You have to access this "file" from extern.c
#implementation Delegate
// This is the function we call with [[Delegate alloc] init];
-(id) init {
// It simply returns itself - saying hey this is the object memory chunk in the heap you want to talk to.
return self;
}
// This is the function we call with [delObj helloWorld];
- (void) helloWorld {
NSLog("Hello World"); // This will show up in your console.
}
So the above code has two functions, one that says "this is the memory object your looking for" - one that says "I'm a function, lets execute something".
Now with all that laid out, you're not calling:
-(void) alertView: (UIAlertView*)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
OR
-(void)SMS:(id)sender{
Via your extern "C". The reason why _AddNotification works is because you have code in there calling UIAlertView AFTER making sure your delegateObject is in memory. In you _SMSGO function, you're not putting your object into memory. So when you call delegateObject in [delegateObject presentViewController:controller animated:YES]; it says "Oh I know what delegateObject is but it's equal to nothing. In fact it does not have memory to execute anything!" Thats why you probably don't get any errors or exceptions. The code knows there is a static object, but it hasn't been set to anything yet.
SOLUTION:
First, void methods don't need :(id)sender thats more of a IBAction thing unless you actually want to send something - so change -(void)SMS:(id)sender{ to - (void) SMS { (with the pretty spacing, too. It's mo' better for eyes).
Second, swap everything in SMS with:
- (void) SMS {
MFMessageComposeViewController *controller = [[MFMessageComposeViewController alloc] init];
[controller setMessageComposeDelegate:self];
if([MFMessageComposeViewController canSendText]){
[controller setRecipients:[NSArray arrayWithObjects:nil]];
[controller setBody:[NSString stringWithFormat:#"Text"]];
// We now know why we work!
[self presentViewController:controller animated:YES];
}
}
But WAIT! And do not copy and paste. Be sure to understand each line of code you write.
This line allocates an object into memory, in this instance, the MFMessageComposeViewController object. Then initializes it.
MFMessageComposeViewController *controller = [[MFMessageComposeViewController alloc] init];
This line sets the delegate of the object we just made (controller). But why can it do this? Because we have MFMessageComposeViewControllerDelegate set in the iOSBridge.h file. This tells everything in your .mm file "hey if we happen to have a MFMessage object somewhere, it may access delegate properties if you want."
[controller setMessageComposeDelegate:self];
if ( [MFMessageComposeViewController canSendText] ) is human readable.
Same with [controller setRecipients:[NSArray arrayWithObjects:nil]]; and [controller setBody:[NSString stringWithFormat:#"Text"]];
But now [self presentViewController:controller animated:YES]; is were we need to dive in.
So in Unity, they said "hey, we don't need to deal with every single possible native function being called" - so they created access to the extern capability for you. This allows you to talk to Objective-C from the UnityScript side of things. Objective-C is just a superset of C, so thats common ground. Everything in here should ONLY call functions in Delegate. The example of this is above in the fake extern.c code block. The only thing that is doing is creating delegateObject and calling a function. Now for the next step. Swap everything in _SMSGO with:
void _SMSGO (const char *mBody) { // I prefer char *name vs char* name but it doesn't matter
[delegateObject SMS]; // add mBody as a parameter when you're ready. Handle the stringWithUTF8String on the Objective-C side of things. Yes, this is not the Obj-C side, this is the C side.
}
"But wait... you just delegateObject needs to be a thing" - Yes it does. Create another method in your extern "C" section called _init and run this one time from Unity in the Awake or Start function of your class. This will set your static object one time and never mess with it again. Simply make it:
void _init() {
if ( !delegateObject ) {
delegateObject = [[Delegate alloc] init];
}
}
!delegateObject is the same thing as delegateObject == nil but cleaner code. Both say "We don't know what dat is" - Ok now we have our delegateObject, we are free to make our next calls with delegateObject as much as we'd like.
Now when you call [delegateObject SMS] it goes to - (void) SMS. And when you call self presentViewController it knows that self is referring to an iOS Native Object. If you call presentViewController in extern "C" it says "... um, hmm. I haven't got the foggiest notion what that means" - for this reason, we have use everything in your extern "C" section as a crossover to your Delegate object. That is the whole purpose of the extern thing, just to call things in your Obj-C stuff.
Hope this helps.
I want to get arraycount inside handler.and then call webservice according to Count,.But array count give me array.
__weak NewsViewController *self_ = self;
[table addInfiniteScrollingWithActionHandler:^{
NSLog(#"%lu",(unsigned long)[tableDataArray count]); // This Line give error Capturing self strongly in this block lead to retain cycle;
[self_ callWebService];
}];
Try create a weak pointer to tableDataArray also (like self)
__weak typeof(NSMutableArray*) _w_tableDataArray = tableDataArray;
__weak NewsViewController *self_ = self;
[table addInfiniteScrollingWithActionHandler:^{
NSLog(#"%lu",(unsigned long)[_w_tableDataArray count]); // This Line give error Capturing self strongly in this block lead to retain cycle;
[self_ callWebService];
}];
Although you're creating a weak self you're not actually referencing it in the block. When you call [tableDataArray count]; It's the equivalent of calling self.tableDataArray in your case you should be calling self_.tableDataArray;.
For clarity an exemplary use of this is as follows:
...
#property (nonatomic, strong) NSMutableArray *tableDataArray;
...
...
__block __weak NewsViewController *welf = self;
[table addInfiniteScrollingWithActionHandler:^{
NSLog(#"%li", welf.tableDataArray.count);
[welf callWebService];
}];
Yes welf stands for weak self.
i have a class MatchDayDataController , having a method pushIncompleteDataToServer.
from another class , SummaryVC.m i want to call pushIncompleteDataToServer in performSelectorInBackground.
Code:
MatchDayDataController *sharedDataController = [MatchDayDataController sharedDataController];
[self performSelectorInBackground:#selector([sharedDataController pushIncompleteDataToServer]) withObject:nil];
It shows some syntax error in performSelectorInBackground. What i missed here? pls guide.
[self performSelectorInBackground:#selector([sharedDataController pushIncompleteDataToServer]) withObject:nil];
This would make the code to search for the method in the same class
It should be:
[sharedDataController performSelectorInBackground:#selector(pushIncompleteDataToServer) withObject:nil];
which would call the method in the sharedDataController class
Also, in the method performSelectorInBackground: withObject: the withObject is for the parameters to be passed to the selector method. I this case, since there are no parameters, we pass nil.
Try this,
[sharedDataController performSelectorInBackground:#selector(pushIncompleteDataToServer) withObject:nil];
instead of
[self performSelectorInBackground:#selector([sharedDataController pushIncompleteDataToServer]) withObject:nil];
You need to replace self with sharedDataController.
[sharedDataController performSelectorInBackground:#selector(pushIncompleteDataToServer) withObject:nil];
The selector will be performed on the receiver of the performSelectorInBackground message, and self doesn't implement that method.
I have one NSMutableArray in FirstViewController declared as firstArray.
I want to copy the secondArray into firstArray.
In the SecondViewController,
Self.FirstViewController.firstArray = self.secondArray;
When I attempt to NSLog the firstArray.count from the FirstViewController, it display 0. It should have two objects in the array
Anyone can advise on this?
You can choose one of this solutions:
Singleton
Passing Data between ViewControllers
Delegation
You can find all the info you need right here: https://stackoverflow.com/a/9736559/1578927
Singleton example:
static MySingleton *sharedSingleton;
+ (void)initialize
{
static BOOL initialized = NO;
if(!initialized)
{
initialized = YES;
sharedSingleton = [[MySingleton alloc] init];
}
}
It looks like either the second array has already been deallocated when passing the reference to the first view controller, or the first view controller itself has already been nilled out. If the first is true, then you may need a different model object to hold your data rather than persisting it in the controller layer of your app. If that is not the case, then you may want to consider a direct copy. The easiest way of doing this is to declare the firstArray property as the keyword copy rather than strong in your interface file.
If you do need to persist the data in the model layer of your app, a singleton pattern object would indeed be one way of achieving this as EXEC_BAD_ACCESS (nice name!) points out. A slightly more modern (though functionally equivalent) way of writing a singleton is as follows.
#interface MySingleton : NSObject
#property (strong, readwrite) id myData;
+ (id)sharedSingleton
#end
#implementation MySingleton
+ (id)sharedSingleton
{
static MySingleton *singleton = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
singleton = [[MySingleton alloc] init];
// Do other setup code here.
});
return singleton;
}
#end
Note the use of dispatch_once - this makes certain that the static singleton can only be created once (whereas technically, you can invoke +[NSObject initialize] as many times as you feel like manually, though I'd never advise doing so).
You may also take advantage of NSNotificationCenter
SecondViewController.m
[[NSNotificationCenter defaultCenter] postNotificationName:#"arrayFromSecondVC" object:secondArray];
FirstViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(populateArray:) name:#"arrayFromSecondVC" object:nil];
}
-(void)populateArray:(NSNotification *)notif
{
self.firstArray = [notif object];
}
And remove the notification when the viewUnload or didRecieveMemoryWarning method.
Hope it helps.
I have a uitextfield subclass and in the init method and setDelegate I have this:
- (void) setDelegate:(id<UITextFieldDelegate>)paramDelegate{
[super setDelegate:paramDelegate];
MRAAdvancedTextFieldDelegate *limitedDelegate = [[MRAAdvancedTextFieldDelegate alloc] init];
self.delegate = limitedDelegate;
}
I am using ARC, but this results in a BAD_ACCESS. Any ideas?
You write self.delegate = limitedDelgate within your setDelegate: method. This is exactly the same as calling [self setDelegate:limiatedDelegate]. Since you are within the -setDelegate: method itself, you are causing infitine recursion. Hope this helps!
EDIT: per your comment about your intention, override it like this:
- (void) setDelegate:(id<UITextFieldDelegate>)paramDelegate{
MRAAdvancedTextFieldDelegate *limitedDelegate = [[MRAAdvancedTextFieldDelegate alloc] init];
[super setDelegate:limitedDelegate];
}
But I don't believe it's a good idea to do this - you should have your client code pass in instances of your delegate instead.
self.delegate = limitedDelegate;
is turned into
[self setDelegate:limitedDelegate];
by the compiler, resulting in an infinite loop. Solution: instead of using the property, use the instance variable instead in the custom setter method:
delegate = limitedDelegate;