NSMutableArray from another view returns empty - ios

I have two UIViews. One UIView, called SelectText has an ivar of NSMutableArray which is populated after performing a certain function.
Here is a snippet code:
- (void)fillDrawPoints
{
//the codes....
[self.drawnPoints addObject:[NSValue valueWithCGPoint:currPoint]];
}
NOTE: The drawnPoints array is initialized in the initWithFrame of SelectText. Also, I always check if the array is actually populated inside the view by putting a log in the function.
Now what I want to do is to access this array from another view. This is what I do:
TextView.h
#import "SelectText.h"
#interface TextView : UIView
{
SelectText *txtSel;
}
#property (nonatomic, retain) SelectText *txtSel;
TextView.m
#synthesize txtSel;
- (void)getDrawingPoints:(NSMutableArray *)pointArray
{
self.pointArray = pointArray;
NSLog(#"Array count: %d", [self.pointArray count]);
}
As you can see from the above code, I am trying to pass the data inside txtSel.drawnPoints to the textView.pointArray for later use. The problem is, the txtSel.drawnPoints always returns empty when I try to access it from another view. What am I doing wrong here?
ADDITIONAL:
This is how I instatiate SelectText
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
txtSel = [[SelectText alloc]init];
[self addSubView:txtSel];
//rest of code...
}

change TextView class init method as below
- (id)initWithClassSelectText:(SelectText *)selectText {
if ((self = [super init])) {
txtSel = selectText;
}
return self;
}
And when you make an instance of TextView you use this:
TextView textView = [[TextView alloc] initWithClassSelectText:self];
now you can access all properties of SelectText class using txtSel object

Related

How to use one class view table for two controller?

I have two view controllers A,B in storyboard with the same class CustomTableViewController for TableViewController element.
There are standard delegates for tables in this class like as:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
In the method:
- (void)viewDidLoad {// Load data for A and B controllers }
How I can rule this class for two controllers?
For example, if I open view controller A, class must be load data A, else load data B.
Problem is how to call different methods in method viewDidLoad:
- (void)viewDidLoad {
if(class A ViewController uses this){
self.response = // Do request
}
if(class b ViewController uses this){
self.response = // Do another request
}
}
There are many ways to do this. Here's one.
Add an inspectable property to CustomTableViewController, like this:
#property (nonatomic, copy) IBInspectable NSString *dataSetName;
By declaring it IBInspectable, you're telling Xcode to let you set the property directly in the storyboard when you select the controller in the document outline:
Now you can type “A” or “B” in the “Data Set Name” field. In viewDidLoad, you can check it:
- (void)viewDidLoad {
[super viewDidLoad];
if ([self.dataSetName isEqualToString:#"A"]) {
[self loadDataSetA];
} else {
[self loadDataSetB];
}
}
One solution can be have custom init for this class and have private property to store the controller like this -
1.Have a instance variable in class like this
#property (strong, nonatomic) UIViewController *controller;
-(instanceType)initWithController:(UIViewController*)controller {
self = [super init];
if(self) {
self.controller = controller;
}
return self;
}
Now in in your viewDidLoad just check your stored property before loading data like this -
- (void)viewDidLoad {
if( [self.controller isMemberOfClass:[A class]] ) {
self.response = // Do request
}
else if ([self.controller isMemberOfClass:[B class]]) {
self.response = // Do another request
}
}

Avoid Object Being Deallocated Without Adding Property/iVar to UIViewController

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;
}

Bad Access when loading NSArray in init

I've got a class, called Letter. In the init method of Letter I am trying to load an Array of strings, so they can be used by other methods of that class.
I'm then instantiating an object based on the Letter class. I am expecting the init call to load the array, but instead am getting a EXC_BAD_ACCESS error.
Letter.h
#interface Letter : NSObject
{
NSArray *consonants;
}
-(BOOL)typeOfLetter:(NSString *)_letter;
Letter.m
#import "Letter.h"
#implementation Letter
- (id)init {
self = [super init];
if (self) {
consonants = [NSArray arrayWithObjects:#"B",#"C",#"D",#"F",#"G",#"Ğ",#"H",#"J",#"K",#"L",#"M",#"N",#"P",#"R",#"S",#"Ş",#"T","#U",#"V",#"Y",#"Z",#"b",#"c",#"d",#"f",#"g",#"ğ",#"h",#"j",#"k",#"l",#"m",#"n",#"p",#"r",#"s",#"ş",#"t",#"u",#"v",#"z",nil];
}
return self;
}
ViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
BOOL retValue;
Letter *letter = [[Letter alloc] init];
retValue = [letter typeOfLetter:#"a"];
}
What am I doing incorrectly here?
You have forgotten to add a # before one of your strings
In your array you have this character "#U" you will have to change it to #"U"

iPhone Development: How to transfer information from one .m file to another

I am new to iPhone development, I have a program that has 7 UITextFields visableenter code here. When the user picks a number on the UIPicker View (1-5) that many UITextFields become hidden and unusable. That program works well. I want to have the same number that was picked from that .m file and transfered to another .m file so that 1-5 UITextFields are hidden and unusable. If it matters, the first .m file is abc.m and the second one is bca.m
if it matters I use [textfield sethidden= YES]
Thanks
You need to keep references to all those objects in the class, and define properties to them so that you can refer to them in the second .m file.
So assuming you have a classes, abc.m
#interface abc {
UITextField *text1;
}
#property (nonatomic, retain) UITextField *text1;
#end
#implementation abc
#synthesize text1;
- (id) init {
if (self = [super init]) {
text1 = [[UITextField alloc] initWithFrame:CGRectMake(0,0,150,10)];
}
return self;
}
- (void)dealloc {
[text1 release];
[super dealloc];
}
Then you can use the text1 property to refer to that text field, given that you have instantiated the object in the second class, or hold a reference to it.
[[MyClass alloc] initWithFrame: CGRectZero andSomeString: #"Hello World!"];
MyClass
- (id)initWithFrame:(CGRect)frame andSomeString:(NSString*)aString
{
if (self = [super initWithFrame:frame])
{
someString = aString;
}
return self;
}
You could try making a BOOL or several BOOL variables and set it equal to YES or NO then put that into your text fields.
BOOL isVisible = YES;
[textfield setHidden:isVisible];
and then if you use a pushViewController you can set the isVisible from bca.m equal to the isVisible in abc.m
viewController.isVisible = isVisible;

How to pass data from parent view to child upon opening?

I want to load data (an array of strings) from the parent view into a set of UITextFields in the child view upon presenting the modalView.
I know how to pass from child to parent, and I'm sure it's even easier to go the other way, but I don't know how.
UPDATE: Update removed because I found the problem (double releasing of modal view)
Override the init method for the child view controller.
- (id) initWithStrings:(NSArray *)string {
if (self = [super init]) {
// Do stuff....
}
return self;
}
Then in the parent:
MyChildViewController *vc = [[[MyChildViewController alloc] initWithStrings: strings] autorelease];
Two ways you could do it:
1.Override the init method as Matt suggests
2.Create fields in your child class and pass those values to your text field.
#interface ChildViewController : UIViewController{
NSArray *strings;
UITextfield *textField1;
UITextfield *textField2;
}
...
- (void)viewDidLoad {
[super viewDidLoad];
textField1.text = [strings objectAtIndex:0];
textField2.text = [strings objectAtIndex:1];
}
Then in the parent class:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
ChildViewController *childController = [[ChildViewController alloc] init];
childController.strings = your_array_of_strings;
[self.navigationController pushViewController:childController animated:YES];
[childController release];
}
- (id)initWithDataObject:(YourDataObjectClass *)dataObject {
if (self = [super init]) {
self.dataObject = dataObject;
// now you can do stuff like: self.myString = self.dataObject.someString;
// you could do stuff like that here or if it is related to view-stuff in viewDidLoad
}
return self;
}
If you want to get really fancy, you can make a delegate for your child view.
#protocol MyChildViewDelegate
- (NSArray*)getStringsForMyChildView:(MyChildView*)childView;
#end
#interface MyChildView : UIView
{
id <MyChildViewDelegate> delegate;
...
}
#property (nonatomic, assign) id <MyChildViewDelegate> delegate;
...
#end
Then somewhere in your view you would ask for the strings:
- (void)viewDidLoad
{
...
NSArray* strings = [delegate getStringsForMyChildView:self];
...
}
Then in your controller (or where ever) you can do:
myChildView = [[MyChildView alloc] initWith....];
myChildView.delegate = self;
...
- (NSArray*)getStringsForMyChildView:(MyChildView*)childView
{
return [NSArray arrayWithObjects:#"one", #"two", #"three", nil];
}
It's probably a little overkill in this case, but this is how UITableViews do it too: they have a data source delegate to provide them with their contents.

Resources