Monotouch: load XIB asynchronously - ios

I would like to know what is the right manner for calling external XIB.
The method MonoTouch.Foundation.NSBundle.MainBundle.LoadNib loads a XIB in a synchronous way but, in this manner, I can't override ViewDidLoad method.
In particular, my goal is to crete a custom UIViewController and load a XIB created in IB (this element is an item that is attached to a Superview). Then I would attach a tap action on the custom UIView. Without overriding ViewDidLoad method I'm not able to do it.
How can I find a good tutorial to understand all the different constructor which I can utilize into a UIViewController?
For example, Could you explain these ctors?
public MyCustomView (IntPtr handle) : base(handle)
{
Initialize ();
}
[Export("initWithCoder:")]
public MyCustomView (NSCoder coder) : base(coder)
{
Initialize ();
}
public MyCustomView () : base("MyCustomView", null)
{
//---- this next line forces the loading of the xib file to be synchronous
MonoTouch.Foundation.NSBundle.MainBundle.LoadNib ("MyCustomView", this, null);
Initialize ();
}
Thank you very much. Best Regards.

The concept you try to do seems to me like changing the behavior of the default event and action flow in CocoaTouch.
The thing is, that ViewDidLoad is exactly the place where you should do the initialization, not in the constructor itself, leave the NIB loading on the framework and just handle the ViewDidLoad as it is intended.
It really helps to read the apple's development documentation, this helped me a lot at the start: https://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/BasicViewControllers/BasicViewControllers.html

Related

How can I create an instance of a custom model with multiple viewcontrollers in Xcode with Swift 4?

I'm new to Swift and I'm sure this question is pretty basic and has been asked and answered before.
I am not using storyBoard. My main viewController is created from AppDelegate via code.
I have:
a custom class defined in a model.swift file
a main viewController (from AppDelegate) that I am using as a container
3 additional viewcontrollers as subviews of the main (not each other)
all 3 subviews are displayed simultaneously each covering 1/3 of the screen (no segues)
each viewcontroller is in a separate .swift file
I want to create an instance of my custom class in the main viewController and have all 3 of the subviews be able to reference that instance.
Each of the subview view controllers need to be able to get/set instance variables and the other subviews need to be made aware of those changes.
I think I will need to use notifications to communicate the changes to the multiple subviews - but I haven't even begun to try and figure that out yet.
If this has been asked and answered before - could someone please either provide a link - or provide me with the right search terms so that I'm able to find the answer? The only found answers I've found that come close are to use segues to pass the data back and forth.
You can use delegate pattern. Below code is assuming that you are using MVVM pattern. (It is very similar for VIPER/ReSwift patterns also)
protocol DataChangedDelegate {
func refreshData()
}
// ViewModel for FirstViewController
class FirstViewModel {
var delegate: DataChangedDelegate?
var data: Any {
didSet {
delegate?.refreshData()
}
}
//rest of the things
}
//similarly other two view models will have a delegate and on data change will call the refresh method
And your view controllers should adopt this protocol
class FirstViewController: UIViewController, DataChangedDelegate {
//view controller code
//delegate code
func refreshDate() {
//tableView.reloadDate()
//collectionView.reloadDate()
//lableView.text = viewModel.data()
}
}
And where ever you create a viewControllers and add as subView, you have to set the delegate of viewModel.
let firstViewController: FirstViewController = createFirstViewController()
let firstViewModel = FirstViewModel()
firstViewModel.delegate = firstViewController
firstViewController.viewModel = firstViewModel
mainViewController.addSubView(firstViewController.view)
Similarly for all other view controllers.
Here's how I would do it:
Create a singleton class.
Configure the singleton's properties in the the main ViewController.
Use didSet to post a Notification.
Add a listener for that Notification in your additional ViewControllers.

UIView subclass access ViewController methods swift

In a couple of my projects I think I'm not created a great structure in many cases.
It could be a game where I've created a game board (think about chess) with a grid of 8 * 8 cells. Each cell has a gesture recognizer that relies on a subclass (cell.swift), with the game logic in a parent ViewController.
For arguments sake, let us say we want to display to the user which square they have touched.
I've found out how to do this from the subclassed UIView (obvs. create the alert in the subclassed UIView / cell.swift in this example)
UIApplication.shared.keyWindow?.rootViewController?.present(alertController, animated: true, completion: nil)
but it seems to break the structure of the app - but wouldn't it be the same accessing an action in the parent ViewController? What is the best way of approaching this>
Your rootViewController is the VC on the bottom of your stack. It's not a safe way to access the visible VC, and is rarely useful, in general (there are cases, but I doubt your app would find them useful).
What you likely want to use is a delegate pattern. Let's say the parent VC that displays your chess board (let's call this MyBoardViewController), conforms to a protocol like the following. MyView is whatever custom UIView class you're using for the chess squares:
protocol SquareAlertHandler {
func handleSquarePressed(sender : myView)
}
And add the following property to your MyView class:
weak var delegate : SquareAlertHandler?
And replace whatever event handler you're currently using, with the following (I'm assuming you're using a UIButton in IB to handle the press, and have arbitrarily named the outlet 'didPress:'):
#IBAction didPress(sender : UIButton) {
delegate?.handleSquarePressed(self)
}
Now, add the protocol to your MyBoardViewController, and define the method:
class MyBoardViewController : UIViewController, SquareAlertHandler {
... ... ...
func handleSquarePressed(sender : myView) {
// Do something to handle the press, here, like alert the user
}
... ... ...
}
And finally, wherever you create the MyView instances, assign the MyBoardViewController instance as the delegate, and you're good to go.
Depending on your Swift literacy, this may be confusing. Adding code, so that I can at least match up the class names, would help to clarify things.

Subclassing UIView

I see this topic is discussed elsewhere but I don't see an answer to my questions.
I subclassed UIView to create a custom view. Currently I'm using interface builder to create a UIView and then setting the custom class option to my subclass.
First question. When I do that, how to I reference that instance from my code? I have a public function I would like to call that updates my view but I don't know how to call it from my view controller
Second question. I created an instance of the class from within my view controller just playing around and I noticed the public function I created isn't available with that instance. Can I create public functions when I inherit from UIView?
It is easy to do:
1)subclass UIView to create CustomView, add your public function,in your project:
import UIKit
class CunstomView: UIView {
/*
// Only override draw() if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
override func draw(_ rect: CGRect) {
// Drawing code
}
*/
public func printHello() {
print("hello")
}
}
2)In your storyboard, drag a UIView into your vc, and set the class to CunstomView, you can see that in my red frame:
3)click the Show the Assistant Editor, and ctrl-drag the view to the vc, set the name custom:
4)then in your vc's viewDidload function, you call the public function:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var custom: CunstomView!
override func viewDidLoad() {
super.viewDidLoad()
custom.printHello()
}
}
5)the result:
First question. When I do that, how to I reference that instance from
my code? I have a public function I would like to call that updates my
view but I don't know how to call it from my view controller
A: A view cannot exist by itself in app. You need viewcontroller to handle the custom view. Then in that VC, you can refer the view as IBOutlet.
Second question. I created an instance of the class from within my
view controller just playing around and I noticed the public function
I created isn't available with that instance. Can I create public
functions when I inherit from UIView?
A: You can create public function of custom view, just declare them in the header file. Then import the header in your VC. Then u can access it.
You can try to update your view from IB with the mothod below.
Objective-C:
-(void)awakeFromNib {
[super awakeFromNib];
//do something
}
Swift
override func awakeFromNib() {
super.awakeFromNib()
}
Second question
Do you mean the custom view don't answer the function you create within the view controller?

How to create UIView class in Swift

I'm new to Swift, come from Obj-C
I'm looking at the net, but to no avail ....
Obj-C in my project I created a class UIView (served as a notification that appeared red from the bottom) with a custom instancetype because through this allocavo the UIView directly in viewController with the parameters that I was interested .. Now I can not absolutely to create the translation of my code in Obj-C swift was trying to find a tutorial or something visual that I could figure out how to create a class with swift UIView without using a xib ...
Does anyone know any tutorial or example of class UIView without XIB in Swift?
My problem is that when I insert this custom init
 
init (title:String, message:String) {
         // init
      }
first of all it returns an error because the compiler wants this also included
required init (coder aDecoder: NSCoder) {
         super.init (coder: aDecoder)
     }
My first question is this:
initWithCoder in obj-c was used only if my custom view was inserted in the storyboard ...
however in my case I would call all my custom view, in my view controller, through a simple line of code as I did in obj-c and that I was not allowed in because obj-c I used a custom instancetype without specifying them a initWithCoder it initWithFrame
I can not understand how this thing
To declare a class as a subclass of another class:
class MyView : UIView {
// properties, methods such as `drawRect:`, etc., go here
}
To instantiate that class:
let v = MyView()
To configure that instance:
v.frame = // ....
To put a view instance into the interface:
self.view.addSubview(v)

trouble getting change a property of an outlet in a any new method

I'm having trouble getting change a property of an
Outlet in a new method, for example:
public partial class ViewApresentacao : UIViewController
{
...
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
//my ImageView
imgModelo.Image = UIImage.FromBundle ("Image/car.png");
}
//new method
public void Test(string caminho)
{
imgModelo.Image = UIImage.FromBundle (caminho);
}
....
}
At viewDidLoad functions normally, but the second
method Test did not, wanted to use it
to update when a selected row in a table, it's all
ok, but when I call the method Test, the error
"object reference not set to an instance of an object"
appears well in line of the Outlet.
Problem solved, I was in my main class with different instances, with the help Xamarin team, managed to solve my problem.

Resources