Switching textstorage of NSTextViews back and forth - objective-c

I'm trying to make a feature in a product which gives the user the ability to split a textview into two. The way this is done is by removing the textview from it's superview, making a NSSplitView and adding the textview as well as a new NSTextView instance to this splitview. Lastly I make these two textviews share the same textstorage in order to make them share the same content.
It works great. But the problem is when I want to make one of the two textviews change textstorage. The replaceTextStorage method in NSLayoutManager causes both NSTextView to change textStorage. The API documentation states:
replaceTextStorage: All
NSLayoutManager objects sharing the
original NSTextStorage object then
share the new one. This method makes
all the adjustments necessary to keep
these relationships intact, unlike
setTextStorage:.
So it makes sense that it would do this. But the question is how do I make it possible to have two (or more) textviews first share the same storage and after that having them using their own?
I've tried replacing the layoutManager and even making new instances of NSTextViews but no luck...
Any suggestions?

If you want the two NSTextView to have difference NSTextStorage, then you have to create two parallel text systems.
First, start with the following architecture (this the one describe in the Text System Overview):
A common NSTextStorage
A first branch with NSLayoutManager/NSTextContainer/NSTextView
A second branch with NSLayoutManager/NSTextContainer/NSTextView
Then, call the replaceTextStorage: method on each NSLayoutManager to set different NSTextStorage.

Related

How to create a reusable subview with controls, without using xib file

I'm coding an app, and have several views that are reused (f. ex. containing a textfield, a label and a button)
Now i would like to just create it in a "globalviews.m" file once and add it as a subview to the mainview. (I really don't like the interface builder)
I could easily create a function that returns a UIView, with the components in them, but i would like to access the controls of course.
I was hoping something like (making "searchview" global in the viewcontroller in use)
// making searchview a global thingy
UIView *seachview ;
// rest of code here and then in viewdidload:
UIView *seachview = [[UIView alloc] init] ;
searchview = [[globaviews alloc] thesearchviews_name] ;
[self addsubview:searchview] ;
But how could I make controls inside easily accessible. Like:
NSString *something = searchview.textviewname.text ;
Or would this be a terrible idea to begin with?
Its just the way I would prefer to code...
You can create a custom class that is a subclass of UIView. You could then add properties for each control (the same way you would add NSString, NSNumber etc). Or you could create public methods to modify / get data.
e.g.
- (void)setTextFiledColour:(UIColor *)color;
- (NSString *)getTextFieldText;
My personal opinion (from a lot of experience) is to learn interface builder and deal with it. It is perfectly possible to do what you want and many people agree with you and choose to do it that way. Personally I've never seen it done "right". Meaning that its all done custom to create their own patterns and methodologies, avoiding years of experience and testing that has gone into the patterns provided by interface builder.
I find that storyboards in particular force a very specific pattern and style of coding. I think moving away form that is a huge mistake, as if used correctly it has great potential to abstract away UI / Code, prevents taking shortcuts that come back later on and most importantly when someone else needs to change it, there is no ambiguity, you can't make a mistake with class names or variable names etc.
I've used storyboards a lot and have yet to have an issue with them, on the flip side i've worked with developers who insist on doing it all by hand and have never had so many issues, and shocked at how long it takes to develop applications in this manner.
In the end its up to you.
Note
You mentioned wanting to create a view and reuse it. Its also possible to do this in a .xib file and reuse it that way. Losing some of the storyboard abilities but might give you a little of both worlds.

Objective-C: Creating a file purely for holding variables

I would like to add a file to my project, who's sole purpose would be to hold an array. I would then #import this file wherever I need to add/get from the array.
My problem is that when I create a new file (I'm using Xcode 4), I'm not sure what type of template to choose, and then what subclass to choose.
My reason for doing all of this is because I have a SplitView-Based app, and one of the views has a textfield, where I am trying to output data. My problem is that whenever I switch to a different view and then switch back, only the most recent entry is there. I am not 100% why that is but I suspect it is because when I switch to a different view, the current view is forgotten about, along with the variables in it.
This is not a good way to do it. There are many ways to do what you want: prepareForSegue: if you are using storyboards, delegation, instantiating your viewcontroller in code and setting a property in the header-file..those are just a few ways.
The way you are proposing is a slippery slope to bad Objective-C code and is only going to cause you more headaches in the future. Take the time to learn to do it right.
Check out this to get you thinking in the right direction.
How you save your data doesn't appear to be your problem. Take a look at the MVC design pattern and how view controllers implement it. They often rely on a dataSource protocol, which links the data from a "Model" to your "View" in a logical way to achieve your intended purpose.
The view controller should then be able to assign a delegate (usually itself (self) to keep the view populated with the correct data, whether the view gets unloaded or not.
If your view controller doesn't refer to a data source or a corresponding protocol, it would still be worth your time to see how you might take advantage of that design pattern. It will pay off in the long run to know this.
Instead of saving variables to a text file, you should consider using NSUserdefaults instead.
But I don't think that's the real solution to your problem, just wanted you know that there are other ways than saving stuff to a text file.

Fundamental Drag And Drop In iOS

I've been considering an app now that implements a drag and drop sort of idiom from maybe a side pane or a drawer, etc. what I can't wrap my head around are how to keep reference to the objects I drop. I mean; it would be easy if it was just drop the object, then let it alone, but I want more manipulation after the fact.
My brain just cannot wrap around the concept of creating objects out of thin air to place on the 'canvas', or having preset objects (which I imagine would be limited, cumbersome and awkward) already on the canvas that would then just be activated and manipulated easily, seeing as the references to them are created before the fact (my apologies for the loose term 'reference', I mean something like selecting the object and having it's unique properties recognized or displayed).
There must be something I'm missing. So, I wonder how one might go about implementing drag and drop with interface and manipulation with the dropped object after the fact or maybe sample code or a link to a git or svn repo? (something like how MIT's scratch, or Xcode's interface builder might work).
For clarity's sake, I know how to go about fiddling with drag and drop thanks to DragKit, but not about editing 'properties' on the object dropped onto the 'canvas', and I would like there to be a near infinite amount of objects that can be dropped on the canvas, yet a set amount of items in the drawer/side view.
If I'm understanding your question correctly, you want to be able to drag objects onto a canvas and then manipulate their properties individually. For instance, you'd drag square views onto the screen and then increase its size or change its color.
In order to do something like that, I would have a NSMutableArray or an NSMutableSet that would hold all of the on canvas objects. Then when any interaction comes, you could either dynamically generate gesture recognizers if the objects are UIViews or a subclass. Then in the target of the gesture recognizer you would use the recognizer.view property.
Or you would have to check which object on the canvas you were currently manipulating. That would be done by iterating through the array and seeing which object equals the one you are touching.
Is there anything that you are trying to do but is not working? Have you written any code in attempt to do this?

Working with many interface elements in Cocoa

My app requires an interface that has many buttons, text fields and matrixes. And they need to change from time to time. Right now I do this by having all elements in IB already and hiding/showing/moving them when needed. What would others recommend? Should I do that? Should I use an NSTabView? NSView? Should create the elements programatically? If so, what if I have an element that is already created that I need again without changes? It would be a waste of releasing it and creating it again.
Any help would be greatly appreciated.
In my opinion, it's better to create interfaces programmatically if you have to animate views around a lot. If it's just a matter of hiding/unhiding them, IB works great, but if you need re-layout or create unknown numbers of views dynamically it's not worth trying to make it all work with nib files.
As for general advice:
Create subclasses (from UIView or UIControl or one of their subclasses) for every kind of element you're going to use. It's tempting to piece together composite views from your UIViewController, but you'll really be much better off creating real classes.
Study the standard Cocoa view classes, and try to create similar API:s in your own controls and views.
Put as much data (sub-element positioning etc) into a plist, so that you can easily change it from one centralized place instead of having to dig around in the code.
If you are often creating several dozen short-lived views, it's worth keeping them in a pool and reusing them. But if it's just a few labels being added and removed intermittently I wouldn't worry too much about it. As usual: don't optimize too early.
Your current approach sounds fine. If you're showing/hiding them but otherwise they remain unchanged, why go through the trouble of creating them with code, when your XIB keeps a "freeze-dried" copy of exactly what you need already?
As long as you're keeping them within logical groups, you can just move/swap/show/hide the group's container (like NSBox or an NSView). If you have a LOT of logical groups, which aren't always shown every session, you can separate them out into their own XIBs and only load them when they're needed, to save launch time and memory.
If you use NSViewController, it's even better because you can make clean breaks for each logical group. Load the panel as the view and the view controller will keep outlets/actions and has a one-to-one relationship with a xib.

How to keep model & controller separate from a CALayer based UI?

I'm trying to re-implement an old Reversi board game I wrote with a bit more of a snazzy UI. I've looked at Jens Alfke's GeekGameBoard code for inspiration, and CALayers looks like the way to go for implementing the UI.
However, there is no clean separation of model and view in the GeekGameBoard code; the model is the view, which makes it hard to, for example, make a copy of the game state in order to perform game-tree search for the AI player. However, I don't seem to be able to come up with an alternative way to structure that allows a separation of model and view that doesn't involve a constant battle to keep two parallel grids (on for the model, one for the view) in synch. This, of course, has its own problems.
How do I best best implement the relationship between an AI search-friendly model structure and a display-friendly view? Any suggestions / experiences would be appreciated. I'm dreading / half expecting an answer along the lines of "there is no good answer: deal with it as best you can" but I'm prepared to be surprised!
Thanks for the answer Peter. I'm not entirely sure I understand it fully, however. I can see how this works if you just have an initial set of pieces that are moved around, and even removed, but what happens when a person puts a new piece down? Would it work like this:
User clicks in the view.
View click is translated to a board location and controller is notified.
Controller creates a new Board with the successor state (if appropriate, i.e. it was a legal move).
The view picks up the new board via its bindings, tears down the existing view/layer hierarchy and replaces it with the current state.
Does that sound right?
PS: Sorry for failing to specify whether it was for the iPhone or Mac. I'm most interested in something that works for the iPhone, but if I can get it to work nicely on the Mac first I'm sure I can adapt the solution to work on the iPhone myself. (Or post a new question!)
In theory, it should be the same as for an NSView-based UI: Add a model property (or properties), expose it (or them) as bindings, then bind the view (layer) to the model through a controller.
For example, you might have a Board class with Pieces on it (each Piece having a reference to the Player who owns it), with all of those being model classes. Your controller would own a Board, and your view/layer would be able to display a Board, possibly with a subview/sublayer for each Piece.
You'd bind your board view/layer to the controller's board property, and in your view/layer's setter for that property, create a subview/sublayer for each piece, and bind it to any properties of the Piece that it will need. (Don't forget to unbind and remove all the subviews/sublayers when replacing the main view/layer's Board.)
When you want to move or modify a Piece, you'd do so using its own properties; these will translate to property accesses on the view/layer. Ostensibly, you'll have your layer's properties set up to animate changes (so that, for example, changing a Piece's position will cause the layer for it to move accordingly).
The same goes for the Board. You might let the user change one or both tile colors; you'll bind your color well(s) through your game controller to its Board object, and with the view/layer bound to the same property of the same Board, it'll pick up the change automatically.
Disclaimers: I've never used Core Animation for anything, and if you're asking about Cocoa Touch instead of Cocoa, the above solution won't work, since it depends on Cocoa Bindings.
I have an iPhone application where almost all of the interface is constructed using Core Animation CALayers, and I use a very similar pattern to what Peter describes. He's correct in that you want to treat your CALayers as if they were NSViews / UIViews and manage their logic through controllers and data via model objects.
In my case, I create a hierarchy of controller objects which also function as model objects (I may refactor to split out the model components). Each of the controller objects manages a CALayer, so there ends up being a parallel CALayer display hierarchy to the model-controller one. For my application, I need to perform calculations for equations constructed using this hierarchy, so I use the controllers to provide calculated values from the bottom of the tree up. The controllers also handle user editing events, such as the insertion of new suboperations or deletion of operation trees.
I've created a layer-hosting view class that allows the CALayer tree to respond to touch or mouse events (the source of which is now available within the Core Plot project). For your boardgame example, the CALayer pieces could take in the touch events, and have their controllers manage the back-end logic (determine a legal move, etc.). You should just be able to move pieces around and maintain the same controllers without tearing everything down on every move.