Do you guys know if it's possible to use a Swift nested class as UIViewController in Storyboard?
I'm looking into different ways to structure my projects, one of which is grouping related classes by nesting them in the same main class.
Let me explain with an example:
Say I have a screen for displaying my app's settings which needs a UIViewController and a model.
I could create 2 classes: SettingsController and SettingsModel, but I'm wondering if it wouldn't be nice to have it structured otherwise by having a main class Settings containing nested classes Controller and Model like so
class Settings {
class Controller: UIViewController {
...
}
class Model {
...
}
}
That way I could use them by doing Settings.Controller and Settings.Model which I think would look pretty nice.
Now this works fine expect when using storyboard. In Storyboard when I select a view controller to set the custom class, if I type in Setting.Controller and hit enter, the field does not validate and is cleared.
So my question is do you guys know what I'm doing wrong or if this is simply not possible?
Of course, it's after having posted the question that I found a solution so I'm sharing it for posterity.
So there was 1 problem to the way I was trying to do it:
Nested classes are references by using the dot
notation: Settings.Controller but Interface Builder does not
see that as a valid class name
The solution was simple, give the controller it's own Objc name:
class Settings {
#objc(SettingsController)
class Controller: UIViewController {
}
...
}
By doing this you give the nested controller an ObjC name thereby exposing it the Interface Builder. Now you can reference the controller by filling in SettingsController.
I don't think storyboards supports that (yet), so in the meantime you need to use some workarounds.
If all you want is the syntax Settings.Controller, you can do this: (Inspired by this answer)
Declare your Settings.Controller class not as a nested class, but as a standalone class SettingsController:
class SettingsController : UIViewController { ... }
Then in Settings, add a typealias:
class Settings {
typelias Controller = SettingsController
class Model { ... }
}
Now you can use SettingsController in the storyboard, but Settings.Controller in code.
Related
Let's say I have a Car object with standard attributes like color, model, brand, and number of seats.
Each view controller in my app would be responsible for getting each of those attributes until the end:
Color View Controller --> Model View Controller --> Brand View Controller --> Seats Controller --> Result Controller
The way I pass data between each controller right now is through a Singleton, but I've read online that is is an anti-pattern and creates a lot of coupling later. Question is then: what is the best way for me to funnel all of the data to Result Controller?
Try to modify your singletons to services.
For example: your singleton StateManager has two method: set(state: SomeState) and getState() -> State.
First, use protocols:
protocol StateManager: class {
func set(state: SomeState)
func getStatus() -> SomeState
}
Second, your app modules shouldn't know about witch StateManager they use:
class MyAppController: UIViewController {
var stateManager: StateManager?
...
}
And when you init your VC:
let vc = MyAppController()
vc.stateManager = ConcreteStateManager.sharedInstance
//present vc
If you have a centralized place for create VC, you can hold instance of ConcreteStateManager in it, without calling sharedInstance.
Also, read about Dependency injection in swift.
I have two projects. The first one is the iOS-App which is referencing a class library with the target framework Xamarin.iOS. In that class library I implemented a CustomView which inherits from UIView. I also registered it with the "Register" attribute.
So in the interface designer I get the prefilled information to use this class as custom class after I dragged the UIView to my ViewController. But when I run the app I get the following information:
"Unknown class MyCustomView in Interface Builder file."
If I move the my CustomView from the class library project into my first project then it will run as expected.
Does someone know how to use a CustomView, which is located in a referenced class library, in an Interface Builder file?
I don't think it's possible to Register accross project boundaries. In my tests, even when you use the exact same namespace, you still end up with an error.
What is possible, on the other hand, is to use a proxy class and make use of inheritance to bring the desired behaviour to the proxy.
Basically, it boils down to this:
1) In your library, you define your Custom UIView and implement any behaviour you want to share:
public class MyCustomUIView : UIView
{
public MyCustomUIView(IntPtr ptr) : base (ptr)
{
}
public override void AwakeFromNib()
{
// Do something beautiful here...
AddSubview(new UILabel(new CGRect(0,0,200,30)) { Text = "I live in the library"});
BackgroundColor = UIColor.Green;
}
}
Note that we don't Registerthis class, because it won't work anyway.
2) Now in your app project, open up the storyboard in interface designer or XCode and assign a completely new name to your placeholder UIView. In my case, I chose MyCustomUIViewProxy. Xamarin studio will create two files for you: MyCustomUIViewProxy.cs and MyCustomUIViewProxy2.designer.cs. Note that in the designer.cs file, Xamarin automatically Registered your proxy class.
3) Now all we have to do is use inheritance, to make the proxy act like the original: In MyCustomUIViewProxy.cs, we change the base class from UIView to MyCustomUIView, and we're good to go:
partial class MyCustomUIViewProxy : MyCustomUIView
{
public MyCustomUIViewProxy (IntPtr handle) : base (handle)
{
}
}
That's it:
I have a simple master-detail setup with two table view controllers. In the master controller I created a custom class, and I would like to work with this custom class in my detail controller. Now I know swift has done away with implementing classes, but when I try to create a new object of this class in my detail controller, it goes as "undeclared". Should there be an import statement? or am I missing something? here is a preview of the code in my master:
import UIKit
class FirstTableViewController: UITableViewController {
class Continent {
var name: String = "Country name"
var continentCountry: ["countries of selected continent"]
}
}
If you're trying to access Continent you'd need to prefix it with FirstTableViewController:
let continent = FirstTableViewController.Continent()
Take a look at The Swift Programming Language: Nested Types for more information.
I have sets of controllers which are each used for each authorization type. For example, a class A authorization will have a set of controllers each which require class A authorization. Is there a way to place one [Authorize(Role="Class A")] attribute somewhere which will apply to each of those controllers without having to decorate each controller with the same attribute?
You can initialize those controllers derived from your base controller. namely put your attribute on a controller base class and to ensure that each controller within derived from base class.
[Authorize(Role="Class A")]
public class CustomBaseController : Controller{}
public class AController: CustomBaseController{}
public class BController: CustomBaseController{}
Yes there is a way, make all those A-class controller derived from one base controller and place on it the AuthorizeAttribute:
[Authorize(Role="Class A")]
public class AController : Controller
{
...
}
public class AFirstController : AController // Gets it's parent attribute
{
...
}
public class ASecondController : AController // Gets it's parent attribute
{
...
}
2 or 3 responses here explained how you can do it... but you can also use Fluent Security to handle all controllers + Actions setup in one file. Some of the benefits (from their website):
Code based configuration
No attributes or xml cluttering up your code.
Low imprint
Fluent Security won't spread like wildfire in your application. Your configuration can be kept in a single file.
You can inherit from a base controller, such as
[Authorize(Role = "Class A")]
public class ClassARequiredController : Controller {}
Otherwise you'd be looking at a global filter, and by your question I assume you have multiple roles and sets so I don't think global filters are for you.
Set the attribute on a Base Class and inherit, creating the hierarchy that best fits your scenario...
Im wondering if something like this is possbile:
abstract class AbstractController {
def list = {
//default list action
}
}
class MyController extends AbstractController {
def show = {
//show action
}
}
Where AbstractController is not visible on the web i.e /app/abstract/list is not accessible and where MyController has the actions list and show and is accessible on the web as /app/my/....
Anyone ever done anything like this?
Try putting AbstractController into src/groovy folder.
Though, sharing functionality over Controllers might be not the best idea - it's better to move it to POGO classes or services. This question covers this issue partially: How do you share common methods in different grails controllers?
For recent version of grails (3.x as the time of writing) it would be better to use trait instead of extending an abstract Controller or use Mixin, the later was deprecated since introducing traits in groovy v2.3, here is an example of using a trait to add a generic behaviors to your controller:
1- Create your traits in src/groovy, e.g.
import grails.web.Action
trait GenericController {
#Action
def test(){
render "${params}"
}
}
2- Implement your trait as you implement any interface:
class PersonController implements GenericController {
/*def test(){
render 'override the default action...'
}*/
}
Note: traits can dynamically access all controller objects: params, response... and so on, and you still can override trait's action.
Hope this help.