Greetings i need to init alloc an instance of a class and have it accessible by any method
Example for using "Whatever *boom = [Wathever alloc]init];"
#interface something : NSObject;
#implementation
-(void) method1{
boom.size = 10;
}
-(void) method2{
boom.color = blue;
}
Where would i alloc and init boom so that i can manipulate it in every method?
for example in whatever.h and whatever.m to call the methods of a class must be declared in whatever.h
-(void) method1;
-(void) method2;
and used
Whatever *boom = [Wathever alloc]init];
[boom method1];
[boom method2];
In a single class? Make it a property of that class.
//.h
#property Whatever *boom;
//.m
- (id)init {
self = [super init];
if (self) {
_boom = [[Whatever alloc] init];
}
return self;
}
Across your whole app? Create an instance of it somewhere, like your app delegate, and then pass it along to the Root View Controller, which in turns passes it to each View Controller.
// AppDelegate .m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// app setup code
Whatever *boom = [[Whatever alloc] init];
FirstViewController vc = self.window.rootViewController;
vc.boom = boom;
}
// FirstViewController.h, NextViewController.h, etc.
#property Whatever *boom;
// FirstViewController.m
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
NextViewController *nextVC = sender.destinationViewController;
nextVC.boom = self.boom;
}
You could also go the Singleton route, but then you are tightly coupled to a single instance of the class app-wide.
See when you create a class in that to intialize that class a common method will always be there which calls that class it self:
Something like this :
-(id)init
{
self = [super init];
if (self)
{
}
return self;
}
You can declare the instance in .h file like this :
Whatever *boom;
Than you can initialize that instance in above method as following :
-(id)init
{
self = [super init];
if (self)
{
boom = [Wathever alloc]init];
}
return self;
}
hope this will help you.
Related
I have been creating a cocoa static library in which I have a public nsobject file where I created a custom delegate. In the app I imported the nsobject file and implemented the delegate but the delegate is not getting called... the static library name is glamApi.
the SKUIDPasser.h file of the NSObject in the library
#import <Foundation/Foundation.h>
#protocol SubClassDelegate <NSObject>
#required
- (void)MethodNameToCallBack:(NSString *)s;
#end
#interface SKUIDPasser : NSObject
-(void)getSKUIDsFromCart:(NSString *)SKUIDs;
#property (nonatomic, weak) id <SubClassDelegate> delegatePasser;
#end
and the SKUIDPasser.m file
#import "SKUIDPasser.h"
#implementation SKUIDPasser
#synthesize delegatePasser;
-(void)getSKUIDsFromCart:(NSString *)SKUIDs{
NSLog(#"getSKUIDsFromCart %#",SKUIDs);
[delegatePasser MethodNameToCallBack:SKUIDs];
}
#end
And the method is called from a Viewcontroller in static library
- (IBAction)CartShowEvent:(id)sender {
if (![cartBadge isHidden]) {
buyClicked = TRUE;
[self loadCart];
[self showCartItemsAll];
self.cartView.frame = self.view.bounds;
[self.view addSubview:self.cartView];
SKUIDPasser *pass = [[SKUIDPasser alloc] init];
[pass getSKUIDsFromCart:#"sssss"];
} else {
[Utilities alert:#"No products to display !!!"];
}
}
The Viewcontroller which the custom delegate has to be implemented Viewcontroller.h
#import <glamAPI/SKUIDPasser.h>
#interface ViewController : UIViewController<SubClassDelegate>{
SKUIDPasser *sk;
}
Viewcontroller.m
- (void)viewDidLoad {
[super viewDidLoad];
sk = [[SKUIDPasser alloc] init];
sk.delegatePasser = self;
NSLog(#"sk.delegatePasser %#",sk.delegatePasser);
}
- (void)MethodNameToCallBack:(NSString *)s
{
NSLog(#"MethodNameToCallBack %#",s);
}
I didn't get any error but the method is not calling..Please help me to resolve this
The very first thing you need to understand is that each instance object of a class is entirely different entity and maintains it's state separately.
In you case your have created an object of your static library in viewDidLoad: and set the delegate accordingly, but when you are making the call to method getSKUIDsFromCart, you are using a different instance for which you never set the delegate property. That's why there was no callback.
To solve this, you can set the delegate in method CartShowEvent: before making the call, something like this
SKUIDPasser *pass = [[SKUIDPasser alloc] init];
pass.delegatePasser = self;
[pass getSKUIDsFromCart:#"sssss"];
However i would suggest that you should use the instance variable of library which you already created in viewDidLoad:
- (IBAction)CartShowEvent:(id)sender {
if (![cartBadge isHidden]) {
buyClicked = TRUE;
[self loadCart];
[self showCartItemsAll];
self.cartView.frame = self.view.bounds;
[self.view addSubview:self.cartView];
//No need to create another object.
//SKUIDPasser *pass = [[SKUIDPasser alloc] init];
//Use the previously created instance object
[sk getSKUIDsFromCart:#"sssss"];
}
else {
[Utilities alert:#"No products to display !!!"];
}
}
The SKUIDPasser object that you are calling within (IBAction)CartShowEvent:(id)sender and the SKUIDPasser object that you are setting the delegate are NOT the same.
Just for a test, try calling the method [sk getSKUIDsFromCart:#"sssss"]; just after you set the delegate and you will see that it will be called because this instance has the delegate set correctly:
ViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
sk = [[SKUIDPasser alloc] init];
sk.delegatePasser = self;
[sk getSKUIDsFromCart:#"sssss"];
NSLog(#"sk.delegatePasser %#",sk.delegatePasser);
}
- (void)MethodNameToCallBack:(NSString *)s
{
NSLog(#"MethodNameToCallBack %#",s);
}
Update
I updated my answer to help you call the trigger from the static library
ViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
sk = [[SKUIDPasser alloc] init];
sk.delegatePasser = self;
/*
You now can pass this variable to the static library to get called
from there ...
example:
viewControllerOnStaticLibrary.passer = sk;
*/
NSLog(#"sk.delegatePasser %#",sk.delegatePasser);
}
- (void)MethodNameToCallBack:(NSString *)s
{
NSLog(#"MethodNameToCallBack %#",s);
}
Viewcontroller_in_static_library.h
#property (nonatomic, strong) SKUIDPasser *passer;
Viewcontroller_in_static_library.m
- (IBAction)CartShowEvent:(id)sender {
if (![cartBadge isHidden]) {
buyClicked = TRUE;
[self loadCart];
[self showCartItemsAll];
self.cartView.frame = self.view.bounds;
[self.view addSubview:self.cartView];
//now you are calling the same instance
[self.passer getSKUIDsFromCart:#"sssss"];
} else {
[Utilities alert:#"No products to display !!!"];
}
}
I'm having the following problem.
I've created a custom view controller that has a some useful methods that I need.
This is the code in the .h
#interface MYViewController : UIViewController
- (void)method;
- (void)otherMethod;
#end
This is my init method of MYViewController class:
- (instancetype)init
{
self = [super init];
return self;
}
Then when I try to extend that class I can't set the title of the child controller. For example, in "MYOtherController.h"
#interface MYOtherViewController : MYViewController
- (void)childControllerMethod;
#end
And this is the init of MYOtherViewController:
- (instancetype)init
{
self = [super init];
return self;
}
And then, if I instantiate a MYOtherViewController object and try to set the title, it happens nothing. For example:
MYOtherViewController *controller = [[MYOtherViewController] alloc] init];
controller.title = #"Hello";
If I put this in the viewDidLoad of the MYOtherViewController class it logs that title is nil:
- (void)viewDidLoad {
NSLog(#"title: %#", self.title);
[super viewDidLoad];
}
Why can't set the title in this child class?
the title for the viewcontroller hasnt been made yet after the alloc init, you would need to set it after the viewDidLoad (which is when all the UI elements have been initialized), so what you can do is make an #property on the viewcontroller which you set after the alloc init, then in the viewDidLoad, set the title to the value of the #property
I'm a little about this. I'm initializing a UITableViewController subclass CTSettingsVC via:
CTSettingsVC *settingsVC = [[CTSettingsVC alloc] init];
However, the initWithStyle initializer is being called. This is my m file:
#interface CTSettingsVC ()
#end
#implementation CTSettingsVC
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
NSLog(#"Why is this called?")
self.title = #"Settings";
}
return self;
}
#end
I'm not sure if this is the intended behaviour or if I'm missing something.
This happens because initWithStyle: is the designated initializer of UITableViewController. The init method of UITableViewController looks something like this:
- (instancetype)init
{
//NOTE: self is being used instead of super
return [self initWithStyle:UITableViewStylePlain];
}
Not all UIKit classes follow this convention of overriding init with default values for the designated initializer when one exists. I often do it myself if I plan on using init for a default initializer to ensure my subclasses are not broken in future versions of UIKit.
init and initWithStyle: are convenience initializers for UITableViewController. Internally they look something like this:
- (instancetype)init
{
return [self initWithStyle:UITableViewStylePlain];
}
- (instancetype)initWithStyle:(UITableViewStyle)style
{
self = [self initWithNibName:nil bundle:nil];
if (self) {
_tableViewStyle = style; // Private, used in loadView.
}
return self;
}
The exception where you will not see initWithNibName:bundle: called is when your view controller is instantiated by a storyboard. There, initWithCoder: is the initializer.
I have a custom class/object that handles gestures and conducts animations for a given view using a CADisplayLink. In its simplest form my class looks something like follows:
#interface SomeClass : NSObject
#property (strong) UIView *someView;
#end
When I add the following code to my view controller....
- (void)viewDidLoad
{
[super viewDidLoad];
SomeClass *someClass = [[SomeClass alloc] init];
someClass.someView = someView;
}
... I was anticipating my someClass object would be retained for the life of the view controller, since I am using a strong reference to someView.
However someClass is immediately deallocated.
I am already aware that I can overcome the deallocation simply by adding someClass as a property (or indeed iVar) of the view controller however I would ideally like to avoid this extra work...
so is there anyway I can have my class retained until either the view or view controller its associated with are deallocated?
EDIT
UIGestureRecognizer objects are an exmaple of a class that doesn't get deallocated when I associate them with a view...
- (void)viewDidLoad
{
UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] init];
[someView addGestureRecognizer:gestureRecognizer];
}
// tapGestureRecognizer still lives
Presumably this is because the UIView takes owner ship of the UIGestureRecognizer object. Is there anyway to achieve this with my class and a UIView category? I.e....
- (void)viewDidLoad
{
[super viewDidLoad];
SomeClass *someClass = [[SomeClass alloc] init];
[someView addSomeClass:someClass];
}
If you want to associate the object with a UIView in the same way a UIGestureRecognizer does then this is technically possible using associatedObjects as follows (but I'm not sure I'd advocate this approach since associatedObjects are often frowned upon)...
SomeClass.h
#class SomeClass;
#interface UIView (SomeClass)
- (void)addSomeClass:(SomeClass *)someClass;
- (void)removeSomeClass:(SomeClass *)someClass;
#end
#interface SomeClass : NSObject
#property (strong) UIView *someView;
#end
SomeClass.m
#import "SomeClass.h"
#import <objc/runtime.h>
#implementation UIView (AssociatedObject)
- (void)addSomeClass:(SomeClass *)someClass
{
NSMutableArray *someClasses = [self someClasses];
if (someClasses == nil) {
someClasses = [[NSMutableArray alloc] init];
[self setSomeClasses:someClasses];
}
[someClasses addObject:someClass];
}
- (void)removeSomeClass:(SomeClass *)someClass
{
NSMutableArray *someClasses = [self someClasses];
if (someClasses != nil) {
[someClasses removeObject:someClass];
if (someClasses.count == 0) {
[self setSomeClasses:nil];
}
}
}
#pragma mark - Private Methods
- (NSMutableArray *)someClasses
{
return (NSMutableArray *)objc_getAssociatedObject(self, #selector(someClasses));
}
- (void)setSomeClasses:(NSMutableArray *)someClasses
{
objc_setAssociatedObject(self, #selector(someClasses), someClasses, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
#end
#implementation SomeClass
#end
Implementation
- (void)viewDidLoad
{
[super viewDidLoad];
SomeClass *someClass = [[SomeClass alloc] init];
someClass.someView = someView;
[someView addSomeClass:someClass];
}
Some further reading on associatedObjects from NSHipster...
http://nshipster.com/associated-objects/
But you can declare SomeClass instance instead of property like this:
#implementation ViewController
{
SomeClass* _someClass;
}
...
- (void)viewDidLoad
{
[super viewDidLoad];
_someClass = [[SomeClass alloc] init];
_someClass.someView = someView;
}
Your SomeClass instance is holding a strong reference to the someView, but nothing is holding a reference to the SomeClass instance except the local variable inside your viewDidLoad message, so as soon as the method exits, that instance can be deallocated. As that was the object holding the only reference to your UIView the view can also be deallocated.
Your only options are to store the reference to the SomeClass object in an instance variable (or iVar) as stosha suggested or in a property. Properties are the preferred method and with automatic synthesis they don't take much more effort than a local variable declaration.
You can declare the property inside the .m file so that it isn't visible to other classes that reference your ViewController class -
In your ViewController.m file -
#interface ViewController ()
#property (strong, nonatomic) SomeClass *someClass;
#end
#implementation ViewController
...
(void)viewDidLoad
{
[super viewDidLoad];
self.someClass = [[SomeClass alloc] init];
self.someClass.someView = someView;
}
So I have two classes. When press the save button, it will pass down the value from self.screen.text by addItem method to the totalArray in class 2. If I try to NSLog in the #implementation of addItem method, then it will give out the correct output but If I do it in viewDidLoad, the output is null. How can I save the value passing from class1 to property of class2 permanently? Thank you. The class2 in a subclass of UITableViewController
Class 1 #interface
//class1.h
#import class2.h
#interface class1 : superclass {
}
- (IBAction)buttonSave:(id)sender;
Class1 #implementation
//class1.m
#interface class1 ()
#end
#implementation class1 {
}
- (IBAction)buttonSave:(id)sender {
class2 *Obj = [[class2 alloc] init];
[Obj addItem:self.screen.text];
}
And class2 #interface
//class2.h
#import class2.h
#interface {
}
#property (strong, nonatomic) NSMutableArray *totalArray;
class2 #implementation
#interface class2 ()
#end
#implementation {
}
- (void) addItem:(id)item {
self.totalArray = [[NSMutableArray alloc] init]; //alloc & init
[self.totalArray addObject:item]; //add object to the total array
// NSLog(#"%#", self.totalArray); If I NSLog in within this method then everything works as expected.
}
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"%#", self.totalArray); //But in here the output is null. ???
}
I think that your problem is that you have use a different class2 object. The one that you had init in buttonSave, is not the one that you are displaying
add a property in class1.h
#property (nonatomic, strong) NSMutableArray *savedArray;
and modify buttonSave :
- (IBAction)buttonSave:(id)sender {
self.savedArray = [[NSMutableArray alloc] init];
[self.savedArray addObject:self.screen.text];
}
You are using a storyboard, then please try to add this in class1.h and add an identifier class2Segue to this segue in your storyboard :
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"class2Segue"])
{
Class2 *tableController = (Class2 *)[segue destinationViewController];
tableController.totalArray = self.savedArray;
}
}
viewDidLoad is called after init so you array is nil here. Change your class2 init method to accept the item.
// In class2
-(id) initWithStyle:(UITableViewStyle)style andItem:(id)item {
self = [super initWithStyle:style];
if(self) {
self.totalArray = [[NSMutableArray alloc] init];
[self.totalArray addObject:item];
}
return self;
}
Your addItem will then look like,
- (void) addItem:(id)item {
//Just add, do not initialize again
[self.totalArray addObject:item];
}
The button action in class1 will now look like,
- (IBAction)buttonSave:(id)sender {
class2 *Obj = [[class2 alloc] initWithItem:self.screen.text];
//OR
//class2 *Obj = [[class2 alloc] initWithItem:UITableViewStylePlain andItem:self.screen.text];
}
Hope that helps!
Try to use like this...
- (IBAction)buttonSave:(id)sender
{
class2 *Obj = [[class2 alloc] init];
Obj.totalArray = [[NSMutableArray alloc] init]; //alloc & init
[Obj.totalArray addObject:self.screen.text];
NSLog(#"screen.text %#", self.screen.text); // -- check here it may be null----
NSLog(#"Obj.totalArray %#", Obj.totalArray);
}
#interface class2 ()
#end
#implementation {
}
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"%#", self.totalArray); //But in here the output is null. ???
}
You can not ensure when your viewDidLoad method will call... so better pass the value to the init method and set there initWithText:(NSString*)text{}. Other wise try to call NSLog in viewWillAppear or viewDidAppear just for testing purpose. In iOS 7 now presentation of view-controllers is bit changed now.