It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 9 years ago.
Ok - can't quite make sense of what's going on here. I'm building a simple card game. I created a Category of UIView that handles all the stuff a "Card" should be. I figure this is irrelevant, but perhaps it's not.
Anyway, in my view controller, I'm just creating 2 NSMutableArrays to hold the dealer and players hands. Then I'm calling a method to set the card value. In that method, I do an NSLog to see the particular card object's value - and it all looks good. But if I try to get that value from my view controller, it always comes back for ALL the objects with the value of the last object in the array.
some code:
playersCards = [[NSMutableArray alloc] initWithObjects:[[UIView alloc] init],[[UIView alloc] init],nil];
[[playersCards objectAtIndex:0] setCardValue];
[[playersCards objectAtIndex:1] setCardValue];
NSLog(#"1: %i",[[playersCards objectAtIndex:0] returnValue]);
NSLog(#"2: %i",[[playersCards objectAtIndex:1] returnValue]);
So when I get the NSLog after calling setCardValue (this is within the Category) - again, all is fine. But those NSLogs right there - they return the value of index 1 for both. What's happening here?
There is no way that the setCardValue method can know what index the Card is at unless you are doing something convoluted. Therefore, it is likely that you do have two cards, but they are identically initialized.
However, there is a bigger problem here. You really don't want to use UIView instances as data like this. You really want to separate the bits that render stuff on screen [View] from the bits that hold the state of the game [model]. Typically there is a layer in between that manages the model state based on user interaction with the view [controller].
See the documentation on Model-View-Controller for more information.
Hanging stuff off of existing classes with categories may seem convenient, but it really shouldn't be used as the primary pattern for encapsulating data, state, and/or logic in your application.
You really want to keep that data [the game state] isolated from how the data is drawn on the screen [the views].
In terms of your specific question in your comment, another question:
Imagine that your code was written like this:
Card *c = [cardArray objectAtIndex: 0];
[c doSomething];
How would c know what index it is at in that code? Now, note that said code is identical to [[cardArray objectAtIndex:0] doSomething];.
If I were designing some kind of a Card game, I would likely create a handful of classes:
a Card class that simply stores a suit and value. Supports NSCoding for archival purposes.
a CardView subclass of UIView which, given a suit and value, knows how to render a card.
a GameFieldView and GameFieldController set of classes that know how to draw the playfield (former, UIView subclass) and how to move CardViews about the playfield (latter, a UIViewController)
specific subclasses of GameFieldController that add logic for things like hands, stacks, piles, and/or whatever else you might need to create a card game.
.... etc ....
That is, I'd break the game down into a series of classes that fit into the iOS or OS X model view controller patterns such that I'm writing a minimal amount of code and letting the system do the heavy lifting it is designed to do.
This may seem like overkill, what with all those classes and all, but, really, the individual classes are relatively simple and quite flexible.
Related
I'm pretty new to this and I don't completely understand all of the inner workings of Objective-C, so I was hoping someone could help me out.
Essentially I have a Person class, where each person is represented by a group of objects (a button, label, and image view) that appear and disappear at certain times throughout the implementation. Occasionally, I want the person to move, and the best way I have figured out so far is to treat all three objects separately and animate them at the same time.
I figured there must be a better way to do this, and I am wondering if it is possible to create something like a "subview" (I don't know if this is the right word for it) and insert the button/label/imageView onto that and then animate the subview. I would imagine it would be something like:
Person *person = [[Person alloc] init];
person.view.frame = CGRectMake(x, y, width, height);
[self.view addSubview:person.view];
But this doesn't seem to work. Any suggestions?
Thanks in advance!
OK so I'm afraid you need to change your design a bit. Apple work on an MVC architectural design which is really important to adhere to when it comes to making Apps.
What you've got here is a mixing between the model and view which is exactly what isn't supposed to happen with MVC.
Essentially you've got:
1) Model layer which is where you have all your data and objects for encapsulating information, just like your Person class.
2) View layer which is for controlling and defining UI elements of your apps like UIView, UIImageView e.t.c.
3) Controller layer which is the interface between Model and View layers. This include classes like UIViewController which manages a UIView.
In your situation you need a UIView into which you can put all the relevant UI (buttons, images) that tell the user about a person. Then you need a Person class. Probably a subclass of NSObject that defines the information for each Person in your app e.g. maybe a UIImage property that can be displayed in a UIImageView. And then a controller (I would recommend UIViewController) which would instantiate the relevant Person objects and then update the UI as required.
I'm not entirely sure what you want in terms of animation but you can look at this for information on how to animate views. And check out:
[UIView animateWithDuration:1
animations:^{
// Cool animations here...
}];
I would get to grips with MVC and other key concepts before getting too snazzy though...
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.
I am not very experienced with OOP so I wanted to share what I am currently doing and ask for some advice about how I should go about a couple of things.
I am currently working on a simple game that uses a 2d grid. Here is a quick overview of my class structure:
'GameBoard'- has an array of the possible cell states for the game, and methods that implement the rules.
'GameView' - has the superclass NSView, and is placed in my window as a custom view. This class is intended to read from the game board and draw the contents of the array by mapping the stares to an enumeration of images in its drawRect: method.
'GameController' - this is an intermediate class intended to initialise the game board and view, and handle the various UI controls. This class has instance variables of the 'GameBoard' and 'GameView' type.
Originally, I was doing nearly everything in the View class, and had it working fine but it started to get hard really to follow, which was my main reason for wanting to spread my code over a new class.
I have created a method in 'GameController' that initialises a new game, with some user defined parameters (removed in the snippet to save space).
-(IBACTION)initialiseGame:(id)sender {
gameBoard = [[GameBoard alloc] init...];
gameView = [[GameView alloc] init...];
}
What I want to do here is pass the game view a pointer to the game board instance so that I can read it's array to draw the current state of the game, something like:
-(void)initWithGameBoard:(GameBoard*)gameBoard;
Is this the right way of going about that, or should I be doing this in a different way?
My next problem with moving to the controller class is that I cannot seem to find out how to do is get a pointer to the instance of GameView that I have placed on the window in IB? Would it be better to not place the view on the window in interface builder, and instead place it on the window programatically in the initialiseGame function? If so how would I go about doing that?
I guess one other question would be, should I just scrap this idea and stick to doing everything in the GameDraw class?
Thank you very much for taking your time to read this, this is probably a very simple question to any experienced object-oriented programmer, but I cannot seem to find the answers specifically anywhere.
There's more than one way to do make this work, but here's how I would do it:
Instantiate the view once in IB. Don't invoke alloc/init yourself.
In your view controller, make an outlet for your view and connect it in Interface Builder. That's how your controller will get access to it. Your view controller will need to be the file owner — probably it already is.
Design the view to be reusable. Give it a -setGameBoard: method for the controller to invoke. Make sure the view can draw something blank when it doesn't have a game board.
Write -initializeGame: like this:
-(IBAction) initialiseGame:(id) sender {
gameBoard = [[GameBoard alloc] init...];
[gameView setGameBoard:gameBoard];
}
Now, I know this question is very opinion oriented because people generally design their apps differently... However, I want to know if I'm doing something incorrectly, or generally frowned upon in the objective c programming community, or if you have any suggestions as to how an experienced obj c developer might design this differently...
LOCATION is a struct and BULLET is an enum defined in a Constants.h header file, BulletV is a subclass of UIView, and Bullet is a subclass of NSObject
I have the following code:
#import "Bullet.h"
#implementation Bullet
#synthesize Type;
#synthesize Location;
#synthesize Strength;
- (id)initWithLocation:(LOCATION)location Type:(BULLET)type Strength:(int)strength
{
self = [super init];
if (self)
{
self.Location = location;
self.Type = type;
self.Strength = strength;
}
return self;
}
#end
#implementation BulletV
#synthesize Type;
- (id)initWithLocation:(LOCATION)location Type:(BULLET)type
{
self = [super initWithFrame:CGRectMake(location.x - 10.0, location.y - 2.0, 20.0, 40.0)];
if (self)
{
self.center = CGPointMake(location.x, location.y);
self.Type = type;
}
return self;
}
- (void)drawRect:(CGRect)rect
{
switch (self.Type)
{
case Normal:
self.backgroundColor = [UIColor redColor];
break;
default:
break;
}
}
#end
Now, I am relatively new to MVC.. but it seems like keeping the model and the view separate creates a whole lot of duplications, which i hate in my code..
For example, the fact that we have 2 of the same named Properties (Location and Type) utilized in these implementation blocks kind of bothers me, but I don't know how I would do this any other way while still maintaining separation between the model and view.
Also, both init methods for the view and model are very similar, with the exception that the model also includes a strength parameter..
I have a very java-oriented mindset when programming, I like to have individual files for each object, and for each object to have a state and certain actions.. Now, this new design disallows for any actions to be utilized in these headers, because they need to be placed in a controller.
Any comments are welcome, if this is the way you would make a "bullet object" (more like just a rectangle) in your app, then feel free to comment so, but it just doesn't seem right to me. Feel free to give your insights.
I immediately see a couple of things I would change.
First naming conventions. Properties and instance variables usually start with a lowercase character while classes start with an upper case character. Class names should be descriptive so BulletV would be clearer as BulletView, "BulletV" might be a "BulletView", a "BulletVelocity", or who knows what else.
Secondly I would not allow a view to be responsible for it's own position. A view should be responsible for it's contents but not need to be aware of it's position in or anything else about its superview.
Instead I would consider what sort of object contains bullets with positions; a room, a level, or whatever. Let a view for that space position the views for whatever bullets it contains. An individual BulletView only need to decide how to draw itself based on the type of its bullet. Which, as Jano suggested, probably means you want to pass a bullet to the view's designated initializer.
Once you have that separation of responsibilities it hopefully makes sense for whatever object models the space containing bullets to manage their positions and possibly other behaviors like creating and destroying bullets.
If you were going to reuse OrangeView you would name it FruitView to start with, and pass a Fruit object superclass which would have a method fruit.color instead using a switch.
But I see what you are doing, color is a visual property, and MVC dogma demands that you keep each part isolated, so you smuggle Bullet in little pieces. This is not very object oriented, or any easier to understand or test. A benefit of OOP is thinking in objects, if you were to show your code to yourself, you would understand it better passing a Bullet object.
edit
All problems in computer science can be solved by another level of indirection except for the problem of too many layers of indirection. In a small app is very common for C to know M and V, and for V to know M. In java server side you create a bean just to feed the view, but that's uncalled for in such a small example. Even when you can spot the pattern before opening the class, it's more effort, more classes, more indirection. Not always a good fit for every application.
Apple talks about it in Cocoa Core Competencies and Cocoa Fundamentals Guide.
One can merge the MVC roles played by
an object, making an object, for
example, fulfill both the controller
and view roles—in which case, it would
be called a view controller. In the
same way, you can also have
model-controller objects. For some
applications, combining roles like
this is an acceptable design.
I feel i am totally out of my depth here, im very new to objective c but have been asked to design an iphone app as part of my uni course. I designed a sinple quiz before, but I was hoping to design a more advanced quiz game with 3 levels (each level will have a different quiz).
I dont know how to use the UIViews and I have tried a tutorial online to help me code a navigation controller. It allows gives me 3 options to go into subview 1, 2 or 3. All the subviews have the same screen though, with one label and a button.
I have 3 classes so far, RootViewController, BasicNavigationAppDelegate and SubViewOneController.
I really dont understand the code at all, im familiar with Java but this objective c is nothing like it. Could someone maybe take a minute to help out a person in distress and explain if i am doing this right by using the navigation controller to display my levels? When i check the xib interface files i dont see the button or label, or dont know where to add the quiz interface objects!! I really am confused by all this. Could anyone help?
You should search google for sample source code, and see how some of the views can be handled. There are many ways you can handle a view, whether its by a UINavigationController, UITabBarController, etc. If you are new to Objective-C, then your not really going to get an answer to this question that will instruct you on what exactly to do.
Interface Builder + View Controllers
Here's a good one for you: View Controllers Programming Guide
(Apple's) View Controller Reference Guide
Some Code Samples
Getting Started Sample Code
I recommend Head First iPhone Development: A Learner's Guide to Creating Objective-C Applications for the iPhone. Within a few chapters you'll know everything you need to build this app and you'll actually understand what you're doing.
(I don't know the authors or the publisher, I just think it's a great book for quickly getting up to speed.)
for a 3 level quiz, UINavigationController is definitely an option.
if you need to find out how to use a class, in xcode, type its name, then press -alt- and double click the class name, this will bring up a short description, with two icons, one will take you to the header file, and the other to the documentation.
to add elements to the nib/xib files, you will need to open the library window, where you will find labels, buttons etc. to use a button, you will need to define an action in your header file, and hook it up in IB, to be able to interact with UIElements in your code, you want to set up outlets in the header file, and hook them up in IB.
something you need to decide on, is how you are going to present the questions, and will also depend if the answer will be true/false, multiple choice, or text entry.
if you arent familiar with obj-c and xcode, it is probably worth picking up an ebook from someone like http://www.pragprog.com. they have an iPhone one up there by Bill Dudney which is quite good(i believe he now works for apple.)
for the standard slide out transition you could use this.
//you would probably want to call this something like level1NavBarItemWasPushed: instead
- (IBAction)lvl1pushNavBarItem:(id)sender {
//create instance of AnswersViewController class.
AnswersViewController *level1AnswersVC= [[Level1AnswersViewController alloc] init];
//pass it some kind of identifier so it can tell which quiz/question it is dealing with and pull in the answers, so that you can reuse the view
[level1AnswersVC setAnswersObject:<<insert object dictionary here>>];
//push the view controller onto the navigationController's view stack
[self.navigationController pushViewController:level1AnswersVC animated:TRUE];
//pushing it onto the view stack has given it +1 retain, so we can now release it without worrying about it disappearing prematurely.
[level1AnswersVC release];
}
for the page flip transition you could use this.
- (IBAction)lvl1pushNavBarItem:(id)sender {
//create instance of AnswersViewController class.
AnswersViewController *level1AnswersVC= [[Level1AnswersViewController alloc] init];
//pass it some kind of identifier so it can tell which quiz/question it is dealing with and pull in the answers, so that you can reuse the view
[level1AnswersVC setAnswersObject:<<insert object dictionary here>>];
//set the current viewController as the delegate, so that it can call back to us when its done
level1AnswersVC.delegate = self;
//set the modal transition style
level1AnswersVC.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
//show answers as modal view, which has been setup to use the page flip transition.
[self presentModalViewController:level1AnswersVC animated:YES];
//pushing it onto the view stack has given it +1 retain, so we can now release it without worrying about it disappearing prematurely.
[level1AnswersVC release];
}