Obj-c UIImageView is null when calling from outside class - objective-c

I have a UIViewController containing a UIImageView that has been correctly wired up (I can set image inside controller).
I have also set an iVar using
UIImageView *_imgQRCode;
and a property using
#property (strong, nonatomic) IBOutlet UIImageView *imgQRCode;
Synthesized using:
#synthesize imgQRCode = _imgQRCode;
But when I call something like below I nothing happens the image and when I inspect in Xcode the reference is memory reference is 0x00000000. note the code works when called inside the ViewController. The following is called from any other view controller with controller instantiated as follow:
QRPopupViewController *qrPop = [[QRPopupViewController alloc] initWithNibName:#"QRPopupViewController" bundle:nil];
[controller.imgView setImage:[UIImage imageNamed:#"sample.png"]];
Any ideas how to fix this and why i'm getting null?

Firsty: outlets should be weak
#property (weak, nonatomic) IBOutlet UIImageView *imgQRCode;
You have to hook imgQRCode outlet to your viewController, and you can use it inside viewDidLoad.

You will get null for all UI Control's instances which are not part of the currently visible view controller. So due to this all your calls to that UI control will not perform the UI related operation.
If you want to update any UI control which is not part of currently visible view controller, you can use app delegate. It is the only place which is centralized in between all view controllers.
There is a mechnism, called "protocol delegate" to call some method to update UI part from the currently visible view controller. You can go through this URL for detail about this.
If you are selecting the approach of "protocol delegate", then explore the method execution flow in detail. When you call a protocol from a method of currently visible view controller, the corresponding protocol implementation method will be called after the completion of the caller method. So you need to take care of synchronization.

Related

UIView subclass dealloc not called

I am using AQGridView for displaying a grid of images in my app. A user clicks on an album and then I open a new controller with the grid that has all the images. The problem is that the when the user presses the back button to go back to the list of albums, the dealloc on the grid view is not getting called. I have logged a string in dealloc of my view controller and it is being called.
I have checked the heapshots in Instruments and everything related to AQGridView is not deallocated even after the view is popped. I use Interface Builder to create the grid view and it is connected to grid view in my .h file.
#property (weak, nonatomic) IBOutlet AQGridView *gridView;
I am not holding any other pointers to the grid view. I am using ARC for the project. Do I need to deallocate the gridView somehow in the grid view controller's dealloc or is it handled automatically by ARC? If it is, what might be preventing it from being deallocated?
EDIT:
I am using NSOperationQueue to load the images in the background and then after the images are loaded, I put them in grid cells.
In the dealloc method of your grid view controller, set the gridView pointer to nil.
-(void)dealloc
{
self.gridView = nil;
}

How to properly remove a pin from another viewController

What I've done so far is working but I would like to know whether this is the proper way or not.
I have a map that shows an annotation when this is pressed shows a callout.
The next view shown is a table view. This table has a button to remove that annotation.
I created one property in the table View of type MKMapView. After this view is initialized when the callOut accessory is tapped, I set the MKMapView property.
When the button is pressed in the table view, I delete the annotation through the map property.
Is this the right way?
Rather than the detail view directly manipulating the parent (map) controller view's controls, a more "right" approach might be to use delegate+protocol.
Define a protocol with the methods that the map controller needs to implement (eg. deleteAnnotation, detailViewDone, etc).
The detail view will have a delegate property for that protocol and call the protocol methods via the delegate property instead of directly accessing and modifying another view's controls.
The map controller would set itself as the delegate of the detail view and actually implement the protocol methods.
This way, each controller/class doesn't have to know the internal details of how the others work and let's you more easily change how each one works internally without affecting code in the others (as long as the protocol doesn't change). It improves encapsulation and reusability.
For example, in the detail view .h, define the protocol and declare the delegate property:
#protocol DetailViewControllerDelegate <NSObject>
-(void)deleteAnnotation:(id<MKAnnotation>)annotation;
-(void)detailViewDone;
//could have more methods or change/add parameters as needed
#end
#interface DetailViewController : UIViewController
#property (nonatomic, assign) id<DetailViewControllerDelegate> delegate;
#end
In the detail view .m, wherever you handle the delete button, call the delegate method instead:
if ([delegate respondsToSelector:#selector(deleteAnnotation:)])
{
[delegate deleteAnnotation:annotation];
}
In the map controller .h, declare that it implements the protocol and declare the methods:
#interface MapViewController : UIViewController<DetailViewControllerDelegate>
-(void)deleteAnnotation:(id<MKAnnotation>)annotation;
-(void)detailViewDone;
#end
In the map controller .m, in calloutAccessoryControlTapped where you create the detail view, set the delegate property instead of the map view property:
DetailViewController *dvc = [[DetailViewController alloc] init...
dvc.annotation = view.annotation;
dvc.delegate = self;
[self presentModalViewController:dvc animated:YES];
Finally, also in the map controller .m, implement the delegate method:
-(void)deleteAnnotation:(id<MKAnnotation>)annotation
{
[mapView removeAnnotation:annotation];
//dismiss the detail view (if that's what you want)...
[self dismissModalViewControllerAnimated:YES];
}
From the documentation, the articles Delegates and Data Sources and Using Delegation to Communicate with Other Controllers may be useful as well.

Showing a UIWebView modally on top of whole application through UIWindow from class inherited from NSObject?

I have a class which works with social networks related stuff. At some point it may want to put up a UIWebView modally. It may not know which view controller is working at the moment. May I show WebView through UIWindow?
Try doing:
[[UIApplication sharedApplication].keyWindow.rootViewController
presentModalViewController:yourVC animated:YES]
UIApplication keyWindow Docs:
keyWindow
The application's key window. (read-only)
#property(nonatomic, readonly) UIWindow *keyWindow
Discussion
This property holds the UIWindow object in the windows array that is
most recently sent the makeKeyAndVisible message.
Availability
Available in iOS 2.0 and later.
UIWindow rootViewController Docs:
rootViewController
The root view controller for the window.
#property(nonatomic, retain) UIViewController *rootViewController
Discussion
The root view controller provides the content view of the window.
Assigning a view controller to this property (either programmatically
or using Interface Builder) installs the view controller’s view as the
content view of the window. If the window has an existing view
hierarchy, the old views are removed before the new ones are
installed.
The default value of this property is nil.
Availability
Available in iOS 4.0 and later.

In iOS, how do I reference an object in a view that is created with a xib file?

I have a view controller that is instantiated in appDelegate and pushed onto a navigation controller. The view controller's view is created with a xib file. The xib file puts a UILabel on the view (among other things). Now I need to set the label's text property programatically but I don't see how to get a reference to it. How do I reference the label object?
I'm using xcode 3.2.5 and building an iPad app.
Aside from IBOutlets, you can also set a tag property on the label in the IB. Then, when you need it you can do:
UILabel *label = (UILabel *)[self.view viewWithTag:111];
111 of course being the tag you assigned to the label in IB.
You do this with what's called an "outlet". You define them in your controller, mark them clearly as IBOutlet and then connect them in Interface Builder to your file owner (or other delegate object created in IB).
For instance, in your FooController.m you might have this:
#interface FooController ()
#property (nonatomic, weak) IBOutlet UILabel* fooLabel;
#end
Then you would select your label, and either control drag from it to the file owner, or go to its connections tab, and drag from the + under referencing outlet, to the file owner and select the fooLabel.
UPDATE: Code sample changed to reflect modern way of handling this case.
[self.view viewWithTag:NUMBER_OF_TAG]; does the trick. But remember that if you want to access the view you must do it on the viewWillAppear or viewDidAppear events.

Where are events in Cocoa Touch?

I learn Cocoa Touch several days, and today have stuck while looking for way to implement a custom event. Event that I can see in Connection Inspector for my UIView subclass.
What I have:
There are a UILabel and MyView:UIView on MainVindow. MyView contains a UISlider. Interfaces for Controller and MyView
// Controller.h
#interface Controller : NSObject {
IBOutlet UILabel *label;
IBOutlet MyView *myView;
}
// I suppose that there should be something like -(IBAction) changeLabelValue for myView event
#end
// MyView.h
#interface MyView : UIView {
IBOutlet UISlider *slider;
float value;
}
- (IBAction) changeValue; //for slider "Changed Value" event
What I want:
Add something in MyView that allows it to rise a event after change value.
Can anybody help me? My main area in programming is .NET and I begin think that its terminology is not appropriate for this case.
Thanks.
I don’t know if I'm understanding you correctly but I think what you want is responding to user events from interface components. In Cocoa the term "event" is only used for objects that describe the actual event, like a touch down or key up.
To respond to higher level events, like dragging a slider or pushing a button, Cocoa uses the target action paradigm. You set up a UI component (a UIControl derived view class) to send a given message to a given target whenever the component detects a change of its state.
To set the target and the action method you can use Interface Builder or the UIControl method addTarget:action:forControlEvents:.