I have a singleton in my FTP app designed to store all of the types of servers that the app can handle, such as FTP or Amazon S3. These types are plugins which are located in the app bundle. Their path is located by applicationWillFinishLoading: and sent to the addServerType: method inside the singleton to be loaded and stored in an NSMutableDictionary.
My question is this:
How do I bind an NSDictionaryController to the dictionary inside the singleton instance? Can it be done in IB, or do I have to do it in code? I need to be able to display the dictionary's keys in an NSPopupButton so the user can select a server type.
Thanks in advance!
SphereCat1
I found / made up the answer to this: I simply override the init method so when it's called from the XIB file, it still returns the singleton. I then provide a method named realInit to do an actual initialization the first time init is called.
Code:
-(id)init
{
#synchronized(self)
{
if (_sharedInstance == nil)
{
_sharedInstance = [[VayprServerTypes alloc] realInit];
}
}
[self release];
return _sharedInstance;
}
-(id)realInit
{
if (self = [super init])
{
serverTypesArray = [[NSMutableArray alloc] init];
}
return self;
}
EDIT: Of course you'll need to define _sharedInstance as a static variable at the top of your class implementation:
static ClassTypeGoesHere *_sharedInstance;
ALSO EDIT: Since you now know for sure that your init method will be called at least once, you can go ahead and replace your normal singleton sharedInstance method with this:
+(ClassTypeGoesHere *)sharedInstance
{
return _sharedInstance;
}
If anyone sees any obvious problems with this design, please let me know!
SphereCat1
Related
In a test Swift project, I am subclassing NSWindowController. My NSWindowController subclass is designed to work with a particular Nib file. It is desirable, then, that when my window controller is initialized, the nib file is automatically loaded by the window controller instance. In Objective-C, this was achieved by doing:
#implementation MyWindowController
- (id)init {
self = [super initWithWindowNibName:"MyWindowNib"]
if (self) {
// whatever
}
return self
}
#end
Now, in Swift this is not possible: init() cannot call super.init(windowNibName:), because the later is declared not as a designated initializer, but as a convenience one by NSWindowController.
How can this be done in Swift? I don't see a strightforward way of doing it.
P.S.: I have seen other questions regarding this topic, but, as long as I've been able to understand, the solutions all point to initialize the Window Controller by calling init(windowNibName:). Please note that this is not the desired beheaviour. The Window Controller should be initialized with init(), and it should be the Window Controller itself who "picks up" its Nib file and loads it.
If you use the init() just to call super.init(windowNibName:), you could instead just override the windowNibName variable.
override var windowNibName: String {
get {
return "MyWindowNib"
}
}
Then there should be no need to mess with the initializers.
You can create your own convenience initializer instead:
override convenience init() {
self.init(windowNibName: "MyWindowNib")
}
You should instead opt in to replacing all designated initializers in your subclass, simply delegating to super where appropriate. Confer https://stackoverflow.com/a/24220904/1460929
Quick Question:
I am creating an object from the MainWindowController:
about = [[About alloc]init];
In the Class About I do my Init:
-(id)init{
if(!_viewAbout){
[NSBundle loadNibNamed:#"About" owner:self];
[NSApp beginSheet:self.viewAbout modalForWindow:*?????* modalDelegate:self didEndSelector:NULL contextInfo:NULL];
}
return self;
}
My problem is that the Window is created in the MainWindowController. My question is how to call/send a message to the creator of the class if the class itself doesn't know the master class?
If I understand you correctly, most classes have self.superclass and just super, like
[super someMethod....
or
[self.superclass blegh....
Or are you asking for the class that creates another class ? If that is the case, you need to declare the creator class inside the other one, some (id) variable would do the trick.
But the most popular design pattern on the mac is the delegate pattern, and once you start using that you will love it. Declaring a delegate is usually the way Cocoa and UIKit do things, but other programming languages might not. Obj-C doesn't have any magic variables like python f.ex. has. Either you have a delegate or you have a declared variable which you would set right after the init/alloc stuff.
Also your (init) call doesn't look right. Usually it looks like :
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Here you could declare your setting.
}
return self;
}
But my opinion is that if you are declaring a singular pattern, you would call a specific method in your class, like you do with so many classes on the iOS/Cocoa, like :
[someclass DefaultClass]
This would be your init class where you would do init, unless the class had been declared before and then you would just return the object.
I want override all methods of a subclass automatically on xcode, for example I have a class extended of UiViewControler, how I override all methods of UiViewController on xcode to be more or less well:
- (id) init
{
return [super init];
}
My intention with this is to log all methods to see when they are called, then my methods will be more or less well
- (id) init
{
[self log];
return [super init];
}
where log is as follow method:
-(void) log
{
NSLog(#"%#",[(NSString *) (NSArray *) [NSThread callStackSymbols][1] componentsSeparatedByString:#"-["][1]);
}
thanks a lot!
In this case you don't have to do anything. If you don't provide an implementation, then the superclass's implementation will be used.
Edited after the question was edited
If you put the log statement in the superclass's implementation then it doesn't matter what you do with your own initialiser.
Why?
One of the many conventions in Cocoa is that each class has a designated initialiser. All the other designated initialisers then call this initialiser. And when you subclass the class, then you create a new designated initialiser for the new class, and as part of the initialisation - this calls the superclass's designated initialiser.
Which is why you see NSObject subclass initialisers calling [super init], because NSObject's designated initialiser is init.
So, just call your logging method in the designated initialiser of your class, and as long as you follow the above convention, this initialiser will always be called by a subclass, and so your logging method will always be called.
I have this application with 3 classes: AppController, Profile, ProfileBuilder. I also need 3 windows: one for each class. I tried keeping all 3 as subclasses of NSObject and applying initWithNibName to an NSWindowController class WindowController variable but when I tried outputting some values on each window it wouldn't work, and also the window resulted as null using NSLog. I was wondering what was the best way to manage multiple windows, perhaps all from a same class like an AppWindowsController involving as least as possible specific code in the other classes, and keeping, if possible, the other classes as subclasses of NSObject and not NSWindowController. So if there is, maybe a way to control the behavior of the windows remotely, adding as least as possible code inside the specific classes, just to keep them as clear as possible and uniquely focused on their content. Thanks, hope I made myself clear, I'm actually pretty new to the Cocoa framework.
You should be able to load the nib files with your windows in an init method for your different classes. For example, in Profile, you could do something like this:
-(id)init {
if (self = [super init]) {
NSArray *array;
BOOL success = [[NSBundle mainBundle] loadNibNamed:#"ProfileWindow" owner: self topLevelObjects:&array];
if (success) {
for (id obj in array) {
if ([obj isKindOfClass:[NSWindow class]]) {
self.profileWindow = obj;
}
}
[self.profileWindow makeKeyAndOrderFront:self];
}
}
return self;
}
profileWindow is a property (typed as strong). In the xib file, I set the File's Owner to Profile.
I just like to improve the solution of rdelmar.
You don't need to iterate over the array to find the NSWindow class.
If you define profileWindow as an outlet and connect it in the IB, the call
[[NSBundle mainBundle] loadNibNamed:#"ProfileWindow" owner:self topLevelObjects:&array];
will assign the window object to your outlet, the array stuff is not required.
The key here is the owner object which act as interface. In the IB you can define the class type of the owner and if so, see its outlets.
I have a little problem, when I have to access to one class I create a new instance
Class *class = [[Class alloc] init];
the problem is that I don't want to create a new instance but use the current instance, I want only to communicate between two class...how can I pass a value without create a new instance?
You can use a Singleton class to create a shared object that can be accessed for the lifetime of the app, here's a simple (though not 100% foolproof) way to create one:
+ (id) sharedInstance {
static Foo *__sharedInstance;
if (nil == __sharedInstance) {
__sharedInstance = [[Foo alloc] init];
}
return __sharedInstance;
}
More here
If you just want to perform specific operations, or get information from the class, you can use a class method by using "+" instead of "-" in the method name like so:
+ (void) doSomething {
NSLog(#"This class is %#", self);
}
Then you can simply call [Class doSomething] to perform operations without having to create a new instance.