I keep getting a EXC_BAD_ACCESS on certain functions in a class. If I change the name of the function the error seems to go away...but I want to know why this is happening, because I happen to like the names that I'm giving my functions.
This is my h file-
#property(strong, nonatomic)NSString* month;
#property(strong,nonatomic)NSString* day;
#property(strong,nonatomic)NSString* description;
#property(strong,nonatomic)NSString* type;
#property(strong,nonatomic)NSString* venue;
#property(weak,nonatomic)IBOutlet UIImageView* imageView;
#property(weak,nonatomic)IBOutlet UILabel* descriptionLabel;
#property(weak,nonatomic)IBOutlet UILabel* venueLabel;
#property(weak,nonatomic)IBOutlet UILabel* titleLabel;
#property(weak,nonatomic)IBOutlet UILabel* typeLabel;
#property(weak,nonatomic)IBOutlet UILabel* dateLabel;
#property(weak,nonatomic)IBOutlet UILabel* monthLabel;
#property(weak,nonatomic)IBOutlet UILabel* dayLabel;
-(void)setDate:(NSString*)month withDay:(NSString*)day;
-(void)setImage:(UIImage*)image;
These are my setters -
-(void)setDescription:(NSString *)description{
self.description = description;
self.descriptionLabel.text = description;
}
-(void)setTitle:(NSString *)title{
self.title = title;
self.titleLabel.text = title;
}
-(void)setType:(NSString *)type{
self.type = type;
self.typeLabel.text = type;
}
-(void)setVenue:(NSString *)venue{
self.venue = venue;
self.venueLabel.text = venue;
}
-(void)setDate:(NSString *)month withDay:(NSString *)day{
self.month = month;
self.day = day;
}
-(void)setImage:(UIImage*)image{
self.imageView.image = image;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
}
-(void)viewWillAppear:(BOOL)animated{
self.monthLabel.text = self.month;
self.dayLabel.text = self.day;
}
If I run this - I get a EXC_BAD_ACCESS on setTitle. If I change that to setEventTitle the error goes away, and I get a EXC_BAD_ACCESS on setVenue.
This is how I'm calling these functions-
-(UIView*)getEventResultView:(NSDictionary*)component{
EventViewController* eventVC = [[EventViewController alloc] initWithNibName:#"EventResultView" bundle:nil];
NSDictionary* dateDictionary = someDate;
NSString* month= [self findMonth:dateDictionary];
[eventVC setDate:month withDay:someDay];
[eventVC setTitle: someTitle];
[eventVC setVenue: someVenue];
[eventVC setDescription:someDescription];
NSString* titleImageUrl = someUrl;
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^{
NSData *titleImageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:titleImageUrl]];
UIImage* titleImage = [UIImage imageWithData:titleImageData];
[eventVC setImage: titleImage];
});
return eventVC.view;
}
Why is this happening?
You have an endless recursion:
-(void)setType:(NSString *)type
{
self.type = type;
…
}
It is here:
self.type = …;
is the short form of
[self setType:…];
So the method (there are no functions in your code) is called while it is executed.
Do this:
-(void)setType:(NSString *)type
{
_type = type;
…
}
Related
My app is Objective-C, and I'm migrating little by little, so I need help with Objective-C, not Swift.
I'm migrating UIWebView to WKWebView and having problems to make didFinish to work.
This the class where I use the WebView, TMAnswerView:
#import "TMAnswerView.h"
#import "TMConsts.h"
#import "TMPersistanceManager.h"
#import <WebKit/WebKit.h>
#interface TMAnswerView () <WKNavigationDelegate>
//UIWebViewDelegate
#end
#implementation TMAnswerView.m
-(void)customInit{
}
-(void)setAnswer:(TMAnswerModel *)answer{
_answer = answer;
float font = 17;
NSNumber *type = [TMPersistanceManager fetchObjectForKey:PERSettingsFontSize];
if([type isEqual:SettingsFontSizeType1]){
font = font * 0.75;
}else if([type isEqual:SettingsFontSizeType3]){
font = font * 1.25;
}else if([type isEqual:SettingsFontSizeType4]){
font = font * 1.5;
}else if([type isEqual:SettingsFontSizeType5]){
font = font * 2;
}
NSString *htmlBody = [TMUtils getHTMLStringForMath:[answer.answer stringByReplacingOccurrencesOfString:#"$$" withString:#"$"] andFontSize:(int)font];
[_answerWebView loadHTMLString:htmlBody baseURL:[NSURL fileURLWithPath: [NSString stringWithFormat:#"%#/", [[NSBundle mainBundle] bundlePath]]]];
_answerWebView.scrollView.contentInset = UIEdgeInsetsMake(0,-8,0,-8);
}
#pragma mark - click listeners
- (IBAction)onCheckButton:(id)sender {
if(_viewControllerType != TMMainTestViewConstrollerTypeDoTest){
return;
}
_checkButton.selected = !_checkButton.selected;
if(_delegate){
[_delegate onCheckChanged:_answer];
}
}
- (void)webView:(WKWebView *)webView
didFinishNavigation:(WKNavigation *)navigation{
[self setWebViewHeight];
}
//-(void)webViewDidFinishLoad:(WKWebView *)webView{
// [self setWebViewHeight];
//}
-(void) setWebViewHeight{
CGSize fittingSize = [_answerWebView sizeThatFits:CGSizeZero];
_heightOfWebView.constant = fittingSize.height;
}
#end
Here I've replaced UIWebView delegate by WKNavigationDelegate. I have to mention that is working fine with the old webViewDidFinishLoad of the UIWebView.
TMAnswerView.h:
#import "TMCustomView.h"
#import "TMAnswerModel.h"
#import "TMMainTestViewController.h"
#import <WebKit/WebKit.h>
#protocol TMAnswerViewProtocol <NSObject>
-(void) onCheckChanged:(TMAnswerModel*) answer;
#end
#interface TMAnswerView : TMCustomView
#property (nonatomic, strong) TMAnswerModel *answer;
#property (weak, nonatomic) IBOutlet UIButton *checkButton;
#property (weak, nonatomic) IBOutlet WKWebView *answerWebView;
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *heightOfWebView;
#property (weak, nonatomic) id<TMAnswerViewProtocol> delegate;
#property (nonatomic) TMMainTestViewConstrollerType viewControllerType;
-(void) setWebViewHeight;
#end
And finally in the storyboard I've added a WebKitView element in replacement of the old UIWebView.
I also tried with didFinishNavigation to no avail.
I checked this next page as reference:
WKWebView
Is there anything wrong in my code? How can I make the didFinish event trigger?
Edit 1
I also tried:
- (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation{
[self setWebViewHeight];
}
to no avail.
Edit 2
This is the class where the WKWebView is load, TMQuestionView:
#import "TMQuestionView.h"
#import "TMColors.h"
#import "TMDBManager.h"
#import "TMConsts.h"
#import "TMAnswerModel.h"
#import "TMAnswerView.h"
#import "TMViewUtils.h"
#import "TMPersistanceManager.h"
#import "TMImagePreviewView.h"
#import <WebKit/WebKit.h>
#interface TMQuestionView () <TMAnswerViewProtocol, WKNavigationDelegate>
#property (weak, nonatomic) IBOutlet WKWebView *webView;
#property (weak, nonatomic) IBOutlet UIView *answersView;
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *webviewHeight;
#property (weak, nonatomic) IBOutlet UIView *viewForLoading;
#property (weak, nonatomic) IBOutlet UIView *loadingView;
#property (weak, nonatomic) IBOutlet WKWebView *webviewExplanations;
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *webviewExplanationsHeight;
#property (nonatomic) BOOL isExplanationsVisible;
#property (nonatomic, strong) NSMutableArray *images;
#property (nonatomic, strong) NSString *tempic;
#end
#implementation TMQuestionView
-(void)customInit{
[[CSLoadingManager sharedManager] addLoadingViewToView:_viewForLoading withColor:TMBaseColor(1)];
_images = [NSMutableArray new];
}
-(void)setQuestion:(TMQuestionModel *)question{
_question = question;
float font = 17;
NSNumber *type = [TMPersistanceManager fetchObjectForKey:PERSettingsFontSize];
if([type isEqual:SettingsFontSizeType1]){
font = font * 0.75;
}else if([type isEqual:SettingsFontSizeType3]){
font = font * 1.25;
}else if([type isEqual:SettingsFontSizeType4]){
font = font * 1.5;
}else if([type isEqual:SettingsFontSizeType5]){
font = font * 2;
}
[_images addObjectsFromArray:[TMUtils getImagesFromQuestion:question.question]];
[_images addObjectsFromArray:[TMUtils getImagesFromQuestion:question.instructions]];
NSString *htmlString = question.question;
if(question.instructions.length > 0 && ![question.instructions isEqualToString:#"(null)"]){
htmlString = [NSString stringWithFormat:#"%#<br/>%#", question.instructions, question.question];
}
NSString *htmlBody = [TMUtils getHTMLStringForMath:htmlString andFontSize:(int)font];
htmlBody = [htmlBody stringByReplacingOccurrencesOfString:#"<center>" withString:#"<p style='text-align:center;'>"];
htmlBody = [htmlBody stringByReplacingOccurrencesOfString:#"</center>" withString:#"</p>"];
_tempic = htmlBody;
[_webView loadHTMLString:htmlBody baseURL:[NSURL fileURLWithPath: [NSString stringWithFormat:#"%#/", [[NSBundle mainBundle] bundlePath]]]];
_webView.scrollView.contentInset = UIEdgeInsetsMake(0,-8,0,-8);
_answersView.hidden = YES;
[[TMDBManager sharedManager] getAnswersForQuestion:_question completition:^(NSDictionary *dict) {
NSArray *temp = [dict objectForKey:DBReturnAnswers];
NSSortDescriptor *sortDescriptor;
sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"answerNumber" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
self->_answers = [temp sortedArrayUsingDescriptors:sortDescriptors];
[self setViewAnswers];
}];
}
-(void) setExplanations{
_isExplanationsVisible = YES;
float font = 17;
NSNumber *type = [TMPersistanceManager fetchObjectForKey:PERSettingsFontSize];
if([type isEqual:SettingsFontSizeType1]){
font = font * 0.75;
}else if([type isEqual:SettingsFontSizeType3]){
font = font * 1.25;
}else if([type isEqual:SettingsFontSizeType4]){
font = font * 1.5;
}else if([type isEqual:SettingsFontSizeType5]){
font = font * 2;
}
NSString *htmlString = _question.explanation;
NSString *htmlBody = [TMUtils getHTMLStringForMath:htmlString andFontSize:(int)font];
[_webviewExplanations loadHTMLString:htmlBody baseURL:[NSURL fileURLWithPath: [NSString stringWithFormat:#"%#/", [[NSBundle mainBundle] bundlePath]]]];
_webviewExplanations.scrollView.contentInset = UIEdgeInsetsMake(0,-8,0,-8);
}
-(void)setRecordAnswer:(TMRecordAnswerModel *)recordAnswer{
_recordAnswer = recordAnswer;
}
-(void) setViewAnswers{
int i = 0;
float font = 17;
NSNumber *type = [TMPersistanceManager fetchObjectForKey:PERSettingsFontSize];
if([type isEqual:SettingsFontSizeType1]){
font = font * 0.75;
}else if([type isEqual:SettingsFontSizeType3]){
font = font * 1.25;
}else if([type isEqual:SettingsFontSizeType4]){
font = font * 1.5;
}else if([type isEqual:SettingsFontSizeType5]){
font = font * 2;
}
for(TMAnswerModel *item in _answers){
TMAnswerView *view = [[TMAnswerView alloc] init];
view.translatesAutoresizingMaskIntoConstraints = NO;
[_answersView addSubview:view];
[[view.leadingAnchor constraintEqualToAnchor:_answersView.leadingAnchor constant:0] setActive:YES];
[[view.rightAnchor constraintEqualToAnchor:_answersView.rightAnchor constant:0] setActive:YES];
if(i == 0){
[[view.topAnchor constraintEqualToAnchor:_answersView.topAnchor constant:0] setActive:YES];
}else{
UIView *lastView = [[_answersView subviews] objectAtIndex:i-1];
[[view.topAnchor constraintEqualToAnchor:lastView.bottomAnchor constant:0] setActive:YES];
}
view.answer = item;
view.delegate = self;
view.viewControllerType = _viewControllerType;
if(_recordAnswer){
if(item.isCorrect == 1){
if([_recordAnswer.selectedAnswerId isEqualToString:item.answerId]){
[view.checkButton setImage:[UIImage imageNamed:#"checkbox_checked"] forState:UIControlStateNormal];
}else{
[view.checkButton setImage:[UIImage imageNamed:#"checkbox_checked_gray"] forState:UIControlStateNormal];
}
}else{
if([_recordAnswer.selectedAnswerId isEqualToString:item.answerId]){
[view.checkButton setImage:[UIImage imageNamed:#"checkbox_error"] forState:UIControlStateNormal];
}
}
}
i++;
if(i == [_answers count]){
[[view.bottomAnchor constraintEqualToAnchor:_answersView.bottomAnchor constant:0] setActive:YES];
}
}
}
-(void)onCheckChanged:(TMAnswerModel *)answer{
for (TMAnswerView *item in [_answersView subviews]){
if(![item.answer isEqual:answer]){
if(item.checkButton.selected){
item.checkButton.selected = NO;
}
}
}
}
- (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation{
[self setHeightOfWebView];
}
//-(void)webViewDidFinishLoad:(WKWebView *)webView{
// [self setHeightOfWebView];
//}
-(TMAnswerModel*) getSelectedAnswer{
for (TMAnswerView *item in [_answersView subviews]){
if(item.checkButton.selected){
return item.answer;
}
}
return nil;
}
-(void) setHeightOfWebView{
_viewForLoading.hidden = YES;
_loadingView.hidden = YES;
CGSize fittingSize = [_webView sizeThatFits:CGSizeZero];
_webviewHeight.constant = fittingSize.height;
_answersView.hidden = NO;
for(UIView *item in [_answersView subviews]){
if([item isKindOfClass:[TMAnswerView class]]){
[((TMAnswerView*) item) setWebViewHeight];
}
}
if(_isExplanationsVisible){
CGSize fittingSizeExplanations = [_webviewExplanations sizeThatFits:CGSizeZero];
_webviewExplanationsHeight.constant = fittingSizeExplanations.height;
}
}
- (IBAction)onButtonAboveWebViewClicked:(id)sender {
if([_images count] > 0){
TMImagePreviewView *view = [[TMImagePreviewView alloc] initWithFrame:CGRectMake(0, 0, kAppWidth, kAppHeight)];
[view setImages:_images];
[[[self superview] superview] addSubview:view];
[view fadeIn];
}
}
- (IBAction)onButtonTemp:(id)sender forEvent:(UIEvent *)event {
NSSet *touches = [event touchesForView:sender];
UITouch *touch = [touches anyObject];
CGPoint touchPoint = [touch locationInView:[sender superview]];
NSLog(#"%#", NSStringFromCGPoint(touchPoint));
long htmlLength = _tempic.length;
long heightOfWebView = _webView.frame.size.height;
double percentTouch = (double)touchPoint.y / (double)heightOfWebView;
int index = 0;
for(NSString *imageStr in _images){
NSString *match = [[imageStr componentsSeparatedByString:#"/"] objectAtIndex:1];
NSRange rangeOfImage = [_tempic rangeOfString:match];
double percentText = (double) rangeOfImage.location / (double)htmlLength;
if(percentText > percentTouch){
break;
}
index++;
}
NSLog(#"STOP");
}
#end
May be you can add this in TMAnswerView.setAnswer :
-(void)setAnswer:(TMAnswerModel *)answer {
...
// set self as navigationDelegate for the webView
_answerWebView.navigationDelegate = self;
[_answerWebView loadHTMLString:htmlBody...
...
Hi everyone iam new in objective c, now i try to create the app like "What's the word". I find this tutorial and lerned it as well as i can. But i have some problems. I want when i click on buttons the currentTitle replace the lable in placesView. Button click method in LettersView.m named as "displayChar". I have success in getting currentTitle but now i don't know how to pass it to GameController and paste text on "places".
I will be grateful for any help!
Here is my code
LettersView.h
#import <UIKit/UIKit.h>
#class LettersView;
#protocol LetterClickDelegateProtocol <NSObject>
-(void)letterView:(LettersView*)letterView addChar:(NSString *)addChar;
#end
#interface LettersView : UIImageView
#property (strong, nonatomic, readonly) NSString* letter;
#property (assign, nonatomic) BOOL isMatched;
#property (strong, nonatomic) NSString *clickLetter;
#property (weak, nonatomic) id<LetterClickDelegateProtocol> clickDelegate;
#property (strong, nonatomic) UIButton *lblChar;
-(instancetype)initWithLetter:(NSString*)letter andSideLength:(float)sideLength;
#end
LettersView.m
#import "LettersView.h"
#import "config.h"
#implementation LettersView{
NSInteger _xOffset, _yOffset;
}
- (id)initWithFrame:(CGRect)frame
{
NSAssert(NO, #"Use initWithLetter:andSideLength instead");
return nil;
}
-(instancetype)initWithLetter:(NSString*)letter andSideLength:(float)sideLength
{
//the letter background
UIImage* img = [UIImage imageNamed:#"btn_letter#2x.png"];
//create a new object
self = [super initWithImage:img];
if (self != nil) {
//resize the letters
float scale = sideLength/img.size.width;
self.frame = CGRectMake(0,0,img.size.width*scale, img.size.height*scale);
UIButton *lblChar = [[UIButton alloc] initWithFrame:self.bounds];
lblChar.tintColor = [UIColor blackColor];
lblChar.backgroundColor = [UIColor clearColor];
[lblChar setTitle:letter forState:UIControlStateNormal];
[lblChar addTarget:self action:#selector(displaychar:)forControlEvents:UIControlEventTouchUpInside];
[self addSubview:lblChar];
self.isMatched = NO;
_letter = letter;
self.userInteractionEnabled = YES;
}
return self;
}
-(void)displayChar:(id)sender {
UIButton *lblChar = (UIButton *)sender;
NSLog(#" The button's title is %#.", lblChar.currentTitle);
_clickLetter = lblChar.currentTitle;
if (self.clickDelegate) {
[self.clickDelegate letterView:self addChar:lblChar.currentTitle];
}
NSLog(#"hu %#", _clickLetter);
}
PlacesView.h
// PlacesView.m
#import "PlacesView.h"
#import "config.h"
#implementation PlacesView
-(id)initWithFrame:(CGRect)frame {
NSAssert(NO, #"Use initwithletter");
return nil;
}
-(instancetype)initWithLetter:(NSString *)letter andSideLength:(float)sideLength
{
UIImage *img = [UIImage imageNamed:#"btn_input#2x.png"];
self = [super initWithImage: img];
if (self != nil) {
self.isMatched = NO;
float scale = sideLength/img.size.width;
self.frame = CGRectMake(0, 0, img.size.width*scale, img.size.height*scale);
//bullshit time
_fieldForLetter = [[UILabel alloc] initWithFrame:self.bounds];
_fieldForLetter.textAlignment = NSTextAlignmentCenter;
_fieldForLetter.textColor = [UIColor blackColor];
_fieldForLetter.backgroundColor = [UIColor clearColor];
_fieldForLetter.text = #"*"; // if button pressed button title placed here.
[self addSubview:_fieldForLetter];
_letter = letter;
}
return self;
}
#end
GameController.m
#import "GameController.h"
#import "config.h"
#import "LettersView.h"
#import "PlacesView.h"
#import "AppDelegate.h"
#implementation GameController {
//tile lists
NSMutableArray* _letters;
NSMutableArray* _places;
}
-(instancetype)init {
self = [super init];
if (self != nil) {
self.points = [[PointsController alloc] init];
self.audioController = [[AudioController alloc] init];
[self.audioController preloadAudioEffects: kAudioEffectFiles];
}
return self;
}
-(void)dealRandomWord {
NSAssert(self.level.words, #"Level not loaded");
// random word from plist
NSInteger randomIndex = arc4random()%[self.level.words count];
NSArray* anaPair = self.level.words[ randomIndex ];
NSString* word1 = anaPair[1]; // answer
NSString* word2 = anaPair[2]; // some letters
_helpstr = anaPair[3]; // helper
NSLog(#"qweqweq %# %#" , word1 , word2);
NSInteger word1len = [word1 length];
NSInteger word2len = [word2 length];
NSLog(#"phrase1[%li]: %#", (long)word1len, word1);
NSLog(#"phrase2[%li]: %#", (long)word2len, word2);
//calculate the letter size
float letterSide = ceilf( kScreenWidth*0.9 / (float)MAX(word1len, word2len) ) - kTileMargin;
//get the left margin for first letter
float xOffset = (kScreenWidth - MAX(word1len, word2len) * (letterSide + kTileMargin))/2;
//adjust for letter center
xOffset += letterSide/2;
float yOffset = 1.5* letterSide;
// init places list
_places = [NSMutableArray arrayWithCapacity: word1len];
// create places
for (NSInteger i = 0; i<word1len; i++){
NSString *letter = [word1 substringWithRange:NSMakeRange(i, 1)];
if (![letter isEqualToString:#" "]) {
PlacesView* place = [[PlacesView alloc] initWithLetter:letter andSideLength:letterSide];
place.center = CGPointMake(xOffset + i*(letterSide + kTileMargin), kScreenHeight/4);
[self.gameView addSubview:place];
[_places addObject: place];
}
}
//init letters list
_letters = [NSMutableArray arrayWithCapacity: word2len];
//create letter
for (NSInteger i=0;i<word2len;i++) {
NSString* letter = [word2 substringWithRange:NSMakeRange(i, 1)];
if (![letter isEqualToString:#" "]) {
LettersView* letv = [[LettersView alloc] initWithLetter:letter andSideLength:letterSide];
letv.center = CGPointMake(xOffset + i * (letterSide + kTileMargin), kScreenHeight); // "/3*4"
if (i > 6) {
letv.center = CGPointMake(-5.15 * xOffset + i * (letterSide + kTileMargin), kScreenHeight + yOffset); // "/3*4"
}
letv.clickDelegate = self;
[self.gameView addSubview:letv];
[_letters addObject: letter];
}
}
}
-(void)letterView:(LettersView *)letterView addChar:(NSString *)addChar
{
PlacesView* placesView = nil;
for (PlacesView* pl in _places) {
//if (CGRectContainsPoint(pl.frame, pt)) {
if () {
//placesView = pl;
placesView.fieldForLetter.text = letterView.lblChar.currentTitle;
break;
}
}
//1 check if target was found
if (placesView!=nil) {
//2 check if letter matches
if ([placesView.letter isEqualToString: letterView.letter]) {
[self placeLetter:letterView atTarget:placesView];
[self.audioController playEffect: kSoundLetterTap];
self.points.points += self.level.coinsPerLvl; //ne nado tak
NSLog(#"Current points %d" , self.points.points);
[self checkForSuccess];
} else {
[self.audioController playEffect:kSoundFail];
[self addAlert:#"ne success" andMessage:#"You lose!" andButton:#"eshe cyka"];
}
}
}
-(void)placeLetter:(LettersView*)letterView atTarget:(PlacesView*)placeView {
placeView.isMatched = YES;
letterView.isMatched = YES;
letterView.userInteractionEnabled = NO;
}
-(void)checkForSuccess {
for (PlacesView* p in _places) {
//no success, bail out
if (p.isMatched==NO) return;
}
NSLog(#"ya!");
[self addAlert:#"Success" andMessage:#"You win!" andButton:#"eshe cyka"];
[self.audioController playEffect:kSoundSuccess];
}
-(void)addAlert: (NSString *)addTitle andMessage: (NSString *)alertMessage andButton: (NSString *)alertButton {
dispatch_async(dispatch_get_main_queue(), ^{
UIWindow* window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
window.rootViewController = [UIViewController new];
window.windowLevel = UIWindowLevelAlert + 1;
UIAlertController *alert = [UIAlertController alertControllerWithTitle: addTitle message:alertMessage preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *defaultAction= [UIAlertAction actionWithTitle:alertButton style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
window.hidden = YES;
}];
[alert addAction:defaultAction];
[window makeKeyAndVisible];
[window.rootViewController presentViewController:alert animated:YES completion:nil];
});
}
#end
Your GameController needs to keep a reference to PlacesView. It can also assign the action into LettersView so when the button in LettersView is pressed, the GameController will fetch it and perform an action in PlacesView. GameController is what both the other classes have in common, so it can handle any actions between them.
Another option is to use NSNotificationCenter and post a message in LettersView when the button is pressed, and listen for it in PlacesView.
Yet anther way is using a delegates where GameController makes sure that PlacesView is set as the delegate. When LettersView's button is pressed, it will call the delegate method which PlacesView listens to.
I'd go with first option.
I am trying to include MWPhotoBrowser in my project
When its used as given in the sample it working fine.
But when a new viewcontroller is subclassed from MWPhotoBrowser, photos are not loaded except empty black theme.
Delegate methods are not getting called. As the controller is subclass of MWPhotoBrowser, I assume there is no need to set it explicitly.
Storyboard is used and the nib class in it is set.
.h file
#interface MDRPhotoViewerController : MWPhotoBrowser
{
NSMutableArray *_selections;
}
#property (nonatomic, strong) NSMutableArray *photos;
#property (nonatomic, strong) NSMutableArray *thumbs;
#property (nonatomic, strong) NSMutableArray *assets;
#property (nonatomic, strong) NSMutableIndexSet *optionIndices;
#property (nonatomic, strong) UITableView *tableView;
#property (nonatomic, strong) ALAssetsLibrary *ALAssetsLibrary;
- (void)loadAssets;
#end
**.m file **
- (void)viewWillAppear:(BOOL)animated
{
NSMutableArray *photos = [[NSMutableArray alloc] init];
NSMutableArray *thumbs = [[NSMutableArray alloc] init];
//mwphotobrowser options setup
BOOL displayActionButton = YES;
BOOL displaySelectionButtons = NO;
BOOL displayNavArrows = NO;
BOOL enableGrid = YES;
BOOL startOnGrid = NO;
BOOL autoPlayOnAppear = NO;
//loading data
NSArray *photosDataArray = [MDRDataController GetPhotos]; //creating array
for (NSString *urlString in photosDataArray) { //Formating the data source for images
NSString *urlFullString = [NSString stringWithFormat:#"%#%#",KBASEURL,urlString];
//Photos
[photos addObject:[MWPhoto photoWithURL:[NSURL URLWithString:urlFullString]]];
//thumbs
[thumbs addObject:[MWPhoto photoWithURL:[NSURL URLWithString:urlFullString]]];
}
// Options
self.photos = photos;
self.thumbs = thumbs;
// Create browser
self.displayActionButton = displayActionButton;
self.displayNavArrows = displayNavArrows;
self.displaySelectionButtons = displaySelectionButtons;
self.alwaysShowControls = displaySelectionButtons;
self.zoomPhotosToFill = YES;
self.enableGrid = enableGrid;
self.startOnGrid = startOnGrid;
self.enableSwipeToDismiss = NO;
self.autoPlayOnAppear = autoPlayOnAppear;
[self setCurrentPhotoIndex:0];
// Test custom selection images
// browser.customImageSelectedIconName = #"ImageSelected.png";
// browser.customImageSelectedSmallIconName = #"ImageSelectedSmall.png";
// Reset selections
if (displaySelectionButtons) {
_selections = [NSMutableArray new];
for (int i = 0; i < photos.count; i++) {
[_selections addObject:[NSNumber numberWithBool:NO]];
}
}
self.title = #"Phots";
//[self reloadData];
}
Debugging performed
Considering the image template of mwphotobrowser, tried reloading the code.
Shifted the code between viewwillappear and viewdidload.
Doesn't MWPhotoBrowser support this way or am i doing it wrong ?
For those who stumble upon this later...
If you look at MWPhotoBrowser.m you'll see various initializers:
- (id)init {
if ((self = [super init])) {
[self _initialisation];
}
return self;
}
- (id)initWithDelegate:(id <MWPhotoBrowserDelegate>)delegate {
if ((self = [self init])) {
_delegate = delegate;
}
return self;
}
- (id)initWithPhotos:(NSArray *)photosArray {
if ((self = [self init])) {
_fixedPhotosArray = photosArray;
}
return self;
}
- (id)initWithCoder:(NSCoder *)decoder {
if ((self = [super initWithCoder:decoder])) {
[self _initialisation];
}
return self;
}
The problem is there's no awakeFromNib initializer. Simplest solution is to fork the project and create the awakeFromNib initializer.
I was trying to solve assignment 2 from Stanford iOS7 development (Matchismo card game)
The game works fine. Now I have to add the Restart function. If the user press on the restart button, the game restarts (it deals new cards and it resets the score)
my game model is the #property (nonatomic, strong) CardMatchingGame *game;
this is the code for the CardMatchingGame.m:
#import "CardMatchingGame.h"
#import "PlayingCardDeck.h"
#interface CardMatchingGame()
#property (nonatomic, readwrite) NSInteger score;
#property (nonatomic, strong) NSMutableArray *cards;
#end
#implementation CardMatchingGame
static const int MATCH_BONUS = 4;
static const int MATCH_PENALTY = 2;
static const int COST_TO_CHOOSE = 1;
-(NSMutableArray *)cards{
if(!_cards) _cards = [[NSMutableArray alloc]init];
return _cards;
}
-(instancetype)initWithCardCount:(NSUInteger)count usingDeck:(Deck *)deck{
self = [super init];
if(self){
for(int i=0; i < count; i++){
Card *card = [deck drawRandomCard];
if(card){
[self.cards addObject:card];
} else{
self = nil;
break;
}
}
}
return self;
}
-(void)chooseCardAtIndex:(NSUInteger)index{
Card *card = [self cardAtIndex:index];
if(!card.isMatched){
if(card.isChosen){
card.chosen = NO;
} else{
for(Card *otherCard in self.cards){
if(otherCard.isChosen && !otherCard.isMatched){
int matchScore = [card match:#[otherCard]];
if(matchScore){
self.score += matchScore * MATCH_BONUS;
card.matched = YES;
otherCard.matched = YES;
} else{
self.score -= MATCH_PENALTY;
otherCard.chosen = NO;
}
break;
}
}
self.score -= COST_TO_CHOOSE;
card.chosen = YES;
}
}
}
-(Card *)cardAtIndex:(NSUInteger)index{
return (index < [self.cards count]) ? self.cards[index] : nil;
}
#end
here is my CardGameViewController.m:
#import "CardGameViewController.h"
#import "PlayingCardDeck.h"
#import "CardMatchingGame.h"
#interface CardGameViewController ()
#property (nonatomic, strong) Deck *deck;
#property (nonatomic, strong) CardMatchingGame *game;
#property (strong, nonatomic) IBOutletCollection(UIButton) NSArray *cardsCollection;
#property (weak, nonatomic) IBOutlet UILabel *scoreLabel;
#end
#implementation CardGameViewController
#synthesize game = _game;
-(CardMatchingGame *)game{
if(!_game) _game = [[CardMatchingGame alloc] initWithCardCount:[self.cardsCollection count]
usingDeck:self.deck];
return _game;
}
-(Deck *)deck{
if(!_deck) _deck = [[PlayingCardDeck alloc] init];
return _deck;
}
- (IBAction)touchRestartButton:(id)sender {
self.game = nil;
[self updateUI];
}
- (IBAction)touchCardButton:(UIButton *)sender {
int chosenButtonIndex = [self.cardsCollection indexOfObject:sender];
[self.game chooseCardAtIndex:chosenButtonIndex];
[self updateUI];
}
-(void)updateUI{
for(UIButton *cardButton in self.cardsCollection){
int buttonIndex = [self.cardsCollection indexOfObject:cardButton];
Card *card = [self.game cardAtIndex:buttonIndex];
[cardButton setTitle:[self titleForCard:card] forState:UIControlStateNormal];
[cardButton setBackgroundImage:[self backgroundImageForCard:card] forState:UIControlStateNormal];
cardButton.enabled = !card.isMatched;
}
self.scoreLabel.text = [NSString stringWithFormat:#"Score: %d", self.game.score];
}
-(NSString *)titleForCard:(Card *)card{
return card.isChosen ? card.contents : #"";
}
-(UIImage *)backgroundImageForCard:(Card *)card{
return [UIImage imageNamed: card.isChosen ? #"cardfront" : #"cardback"];
}
#end
In order to restart the game, I think I should simply re-initialize the property CardMatchingGame *game.
This is what I tried to do, by setting self.game = nil; Then it should automatically be re-initialized in the getter of game.
This is, indeed, the solution that I found on the internet. However, in my program it doesn't work. *game is set to nil and never restored, so the game ends when you click restart.
Could you please help me to figure out why self.game = nil doesn't work in my case?
- (IBAction)startover:(UIButton *)sender {
self.game= [[CardMatchingGame alloc] initWithCardCount:[self.cardButtons count] usingDeck:[self createDeck]];
[self updateUI];
}
If your program has the lazy init style recommended, there is no need for a new method such as start over. You are correct to set self.game to nil, now a call the the getter will start a new instance of the game. I did it by making a call to UIUpdate right after the self.game = nil. That has a call to the getter and lazily inits a new instance of the game.
I have custom UIButton class:
CheckBox.h
#interface CheckBox : UIButton {
BOOL isChecked;
IBOutlet UIWebView *webview;
IBOutlet UIImageView *img;
NSMutableString *labelText;
NSInteger fontSize;
NSInteger heightWebView;
}
#property (nonatomic,retain) NSMutableString *labelText;
#property (nonatomic,retain) UIImageView *img;
#property (nonatomic,retain) UIWebView *webview;
#property (nonatomic,assign) BOOL isChecked;
-(IBAction) checkBoxClicked;
-(void)addText:(NSString *) text redLetter:(NSInteger)redLetter isBold:(NSInteger)
isBold;
-(BOOL)getStatus;
-(NSString*)getText;
-(void)setFontSize:(NSInteger)setFontSizeValue;
#end
CheckBox.m look on IBAction i need implement functionality there
#import "CheckBox.h"
#implementation CheckBox
#synthesize isChecked, webview, img, labelText, delegate;
- (id)initWithFrame:(CGRect)frame {
if (self == [super initWithFrame:frame]) {
// Initialization code
fontSize = 2;
self.isChecked = NO;
self.labelText = [[NSMutableString alloc] init];
self.contentHorizontalAlignment =
UIControlContentHorizontalAlignmentLeft;
img = [[UIImageView alloc] initWithFrame:CGRectZero];
img.image = [UIImage imageNamed:#"checkbox.png"];
[self addSubview:img];
webview = [[UIWebView alloc] initWithFrame:frame];
webview.backgroundColor = [UIColor clearColor];
[webview setOpaque:NO];
webview.userInteractionEnabled = NO;
[self addSubview:webview];
/* [self setImage:[UIImage imageNamed:
#"checkbox.png"]
forState:UIControlStateNormal];*/
[self addTarget:self action:
#selector(checkBoxClicked)
forControlEvents:UIControlEventTouchUpInside];
}
return self;
}
-(IBAction) checkBoxClicked{
if(self.isChecked ==NO){
self.isChecked =YES;
img.image = [UIImage imageNamed:#"checkbox-checked.png"];
}else{
self.isChecked =NO;
img.image = [UIImage imageNamed:#"checkbox.png"];
}
}
-(BOOL)getStatus{
return self.isChecked;
}
-(NSString*)getText{
return [NSString stringWithFormat:#"%#",self.labelText];
}
-(void)setFontSize:(NSInteger)setFontSizeValue {
fontSize = setFontSizeValue;
if (fontSize >2) {
heightWebView = fontSize+2;
}
}
-(void)addText:(NSString *) text redLetter:(NSInteger)redLetter isBold:(NSInteger)isBold
{
[self.labelText setString:text];
if (redLetter != 0) {
NSString *first;
NSString *red;
NSString *second;
first = [text substringWithRange:NSMakeRange(0, redLetter-1)];
red = [text substringWithRange:NSMakeRange(redLetter-1, 1)];
second = [text substringWithRange:NSMakeRange(redLetter, [text length] - redLetter )];
if(isBold == 0) {
NSString *html = [NSString stringWithFormat:#"<font size=\"%d\"><p>%#<span style=\"color:red;\">%#</span>%#</p></font>",fontSize, first,red,second];
[webview loadHTMLString:html baseURL:nil];
}else{
NSString *html = [NSString stringWithFormat:#"<font size=\"%d\"><p>%#<span style=\"color:red;\">%#</span>%#</p></font>",fontSize, first,red,second];
[webview loadHTMLString:html baseURL:nil];
}
}else {
if(isBold == 0) {
NSString *html = [NSString stringWithFormat:#"<font size=\"%d\"><p>%#</p></font>",fontSize, text];
[webview loadHTMLString:html baseURL:nil];
}else{
NSString *html = [NSString stringWithFormat:#"<font size=\"%d\"><p>%#</p></font>",fontSize, text];
[webview loadHTMLString:html baseURL:nil];
}
}
}
- (void)layoutSubviews {
img.frame = CGRectMake(0, 5, 18 , 18);
webview.frame = CGRectMake(12, 0-heightWebView, self.bounds.size.width- 11 , 25+heightWebView);
}
- (void)dealloc {
[webview release];
[img release];
[super dealloc];
}
#end
I need to add functionality to this class, that when user click on button in class where i implement CheckBox class will call some void.
Let me explain better i want to implement here functionality like in UIAlertView where you click on button calls
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
I need something like
- (void)checkBox:(CheckBox *)checkBox didStatusChanged:(BOOL)checkBoxStatus
Sounds like you want to implement a delegate protocol. This would go at the top of checkbox.h above your #interface
#protocol CheckBoxDelegate
#optional
- (void)checkBox:(CheckBox *)checkBox didStatusChanged:(BOOL)checkBoxStatus;
#end
You'd then want to add this to your checkbox.h #interface
#property (monatomic, assign) NSObject <CheckBoxDelegate> delegate;
You could then implement the
checkBox:(CheckBox *)checkBox didStatusChanged:(BOOL)checkBoxStatus
function in your ViewController or whatever is creating the checkboxes, and for each checkbox do
[checkbox setDelegate:self];
Then inside -(IBAction) checkBoxClicked you can call
[delegate checkBox:self didStatusChanged:self.isChecked];
and this would call that method on the class spawning the checkboxes/delegate.
Hope this is extensive enough.
Tim