I'm currently working on a Graphs based iOS app. For this I'm using a third party control called F3PlotStrip.
And implementation is something like:
- (void)viewDidLoad
{
_ecgView = [[F3PlotStrip alloc] initWithFrame:CGRectMake(50, 50, 648, 299)];
_ecgView.lineColor = [UIColor greenColor];
_ecgView.lowerLimit = -10.0f;
_ecgView.upperLimit = 10.0f;
[self.view addSubview:_ecgView];
[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(testGraph:) userInfo:nil repeats:YES];
}
- (void)testGraph:(NSTimer *)a_timer
{
_ecgView.value = 1.0;
}
But I got the result like:
Then I added a UIView in my xib and changed its class to F3PlotStrip then connected it to the outlet as _ecgView.
Then I changed the code like:
- (void)viewDidLoad
{
_ecgView.lineColor = [UIColor greenColor];
_ecgView.lowerLimit = -10.0f;
_ecgView.upperLimit = 10.0f;
[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(testGraph:) userInfo:nil repeats:YES];
}
- (void)testGraph:(NSTimer *)a_timer
{
_ecgView.value = 1.0;
}
This time, I got the actual output:
But why the issue is happening when I add the view through code? I can't depend on the second approach (Through IB) because I need to add graphs dynamically. Is there anyway to fix this issue? Or is this a bug of F3PlotStrip?
I started using this widget this morning. I'm in bed on my iPhone now so cannot post what I want to post, but I will when I get into work in the morning.
I've managed to use it and do what you're trying to do with a dynamically added UIView, or should I say, F3PlotStrip.
I've also made the .h and the .m, ARC compliant too. Not sure if you'd done that.
I'll finish up tomorrow with some nice code that uses an NSTimer to read the contents of a NSArray to plot dynamically, with animation. Again with a View I've added to my viewcontroller as a subview.
Not looked in detail at your code as post what I've managed to get working, tomorrow.
Ok - here I am at work, sat in front of Xcode. Here's my VC that I've used as a basic testbed for this widget. I knocked it up quickly last night, but does the job. Initially, I'd added a UIView to my Storyboard first VC and subclassed it to F3PlotStrip. But, given I saw you you were having issues with dynamically adding the UIView, I thought I'd give it a go. The only difference between you're and mine is that I'm setting the UIView's frame after the alloc-init. See what you think. It uses a Sparkline approach as well as animating the graph on to the screen.
//
// PlotViewController.m
// PlotTest
//
// Created by Carl Hine on 16/05/2013.
// Copyright (c) 2013 Carl Hine. All rights reserved.
//
#define COLOUR_POWDER_BLUE [[UIColor alloc] initWithRed:176/255.0f green:224/255.0f blue:230/255.0f alpha:1]
#import "F3PlotStrip.h"
#import "PlotViewController.h"
#interface PlotViewController ()
#property (strong, nonatomic) IBOutlet F3PlotStrip *IBOPLotView;
#property (strong, nonatomic) NSTimer *plotStipTimer;
#property (strong, nonatomic) NSArray *plotData;
#property (nonatomic) NSInteger plotDataArrayIdx;
#property (strong, nonatomic) F3PlotStrip *plotView2;
#end
#implementation PlotViewController
#synthesize plotStipTimer;
#synthesize plotData;
#synthesize plotDataArrayIdx;
BOOL bUsingDynPlot = YES;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)testGraph:(NSTimer *)a_timer {
float RSEFigure = [[self.plotData objectAtIndex:plotDataArrayIdx] floatValue];
if (bUsingDynPlot)
_plotView2.value = RSEFigure;
else
_IBOPLotView.value = RSEFigure;
++plotDataArrayIdx;
if (plotDataArrayIdx == [self.plotData count]) {
[plotStipTimer invalidate];
plotStipTimer = nil;
}
}
- (void)configurePLotStrip:(F3PlotStrip *)plotStrip {
plotDataArrayIdx = 0;
// Random rubbish that makes it look like a heartbeat :
self.plotData = [NSArray arrayWithObjects:[NSNumber numberWithFloat:68.1f],
[NSNumber numberWithFloat:70.2f],
[NSNumber numberWithFloat:71.3f],
[NSNumber numberWithFloat:72.4f],
[NSNumber numberWithFloat:73.5f],
[NSNumber numberWithFloat:73.5f],
[NSNumber numberWithFloat:100.5f],
[NSNumber numberWithFloat:124.5f],
[NSNumber numberWithFloat:10.5f],
[NSNumber numberWithFloat:73.5f],
[NSNumber numberWithFloat:70.6f],
[NSNumber numberWithFloat:70.2f],
[NSNumber numberWithFloat:71.3f],
[NSNumber numberWithFloat:72.4f],
[NSNumber numberWithFloat:73.5f],
[NSNumber numberWithFloat:73.5f],
[NSNumber numberWithFloat:100.5f],
[NSNumber numberWithFloat:124.5f],
[NSNumber numberWithFloat:10.5f],
[NSNumber numberWithFloat:73.5f],
[NSNumber numberWithFloat:70.6f],
[NSNumber numberWithFloat:70.2f],
[NSNumber numberWithFloat:71.3f],
[NSNumber numberWithFloat:72.4f],
[NSNumber numberWithFloat:73.5f],
[NSNumber numberWithFloat:73.5f],
[NSNumber numberWithFloat:100.5f],
[NSNumber numberWithFloat:124.5f],
[NSNumber numberWithFloat:10.5f],
[NSNumber numberWithFloat:73.5f],
[NSNumber numberWithFloat:70.6f],
nil];
// Get value bounds
float max = -999999;
float min = 999999;
for (NSInteger i = 0;i <= self.plotData.count - 1;++i) {
float RSEFigure = [[self.plotData objectAtIndex:i] floatValue];
if (RSEFigure > max)
max = RSEFigure;
if (RSEFigure < min)
min = RSEFigure;
}
plotStrip.lowerLimit = min;
plotStrip.upperLimit = max;
plotStrip.lineColor = COLOUR_POWDER_BLUE;
[self.view addSubview:_IBOPLotView];
plotStipTimer = [NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:#selector(testGraph:) userInfo:nil repeats:YES];
plotStrip.showDot = YES;
plotStrip.capacity = self.plotData.count;
}
- (void)viewDidLoad {
if (bUsingDynPlot) {
// Dynamically adding to view.
_plotView2 = [[F3PlotStrip alloc] init];
_plotView2.backgroundColor = [UIColor redColor];
_plotView2.frame = CGRectMake(0, 100, 293, 35);
[[self view] addSubview:_plotView2];
[self configurePLotStrip:_plotView2];
} else {
[self configurePLotStrip:_IBOPLotView];
}
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
#end
I hope this is easy enough for you to drop in to a new VC. Provided you have the F3PlotStrip.h and .m in your project folder, you'll be good to go - aside from adding a UIView to the VC.
Carl.
Related
I have been doing an Project for IOS which is written in Objective C. Theres a requirement where i have to put a Button or Label below a table view which kind of act as an Dialog like view over an WebView. There is already an header view embedded into the table view, its work well, but when i try to place the button or label below the table view using Storyboard its not working as expected it actually not positioning below the TableView. Below is the image how my View is laid out :
This is how it looks currently :
Below is the code for my view controller :
ViewController.h:
#import "FlatUIKit.h"
#interface NothiViewController : UIViewController
{
IBOutlet UIWebView *mainWebView;
IBOutlet UISegmentedControl *segmentControl;
IBOutlet UIView *viewNothiPermittedUsers;
IBOutlet UILabel *labelTitleNothiPermittedUsers;
IBOutlet UITableView *tableViewNothiPermittedUsers;
}
#property (nonatomic,strong) NSArray *arrNothiPermittedUsers;
#property(nonatomic,retain) ModelNothi *currentModelNothi;
- (void)updateRightBar:(BOOL)all;
#end
#interface CellNothiPermittedUserList : UITableViewCell
{
}
#property (nonatomic, strong) IBOutlet UILabel *labelUserName;
#property (nonatomic, strong) IBOutlet FUIButton *buttonSend;
#end
ViewController.m:
#interface NothiViewController ()<UIWebViewDelegate,CustomAlertViewDelegate>
{
RequestNothiActionApiType currentNothiActionApiType;
AlertType currentAlertType;
}
#property(nonatomic,strong)NSData *dataNotangsho;
#property(nonatomic,strong)NSData *dataPotrangsho;
#end
#implementation NothiViewController
#synthesize currentModelNothi;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.view.backgroundColor = APP_VIEW_BACKGROUND_COLOR;
mainWebView.delegate = self;
mainWebView.backgroundColor = UIColor.clearColor;
mainWebView.opaque = YES;
mainWebView.scalesPageToFit = YES;
UIFont *font = [UIFont systemFontOfSize:16.0f];
NSDictionary *attributes = [NSDictionary dictionaryWithObject:font
forKey:NSFontAttributeName];
[segmentControl setTitleTextAttributes:attributes
forState:UIControlStateNormal];
segmentControl.tintColor = COLOR_LOGIN_BUTTON;
self.dataNotangsho = nil;
self.dataPotrangsho = nil;
currentNothiActionApiType = API_TYPE_NOTANGSHO;
NSDictionary *params = #{#"data_ref": #"api",
#"api_key": API_KEY,
#"user_designation": [AppSupporter sharedInstance].currentDesignationID};
NSString *api = [NSString stringWithFormat:#"%#/%#",API_NOTHI_NOTANGSHO,self.currentModelNothi.nothiParts];
CGRect frame = segmentControl.frame;
frame.origin.y = NAV_BAR_HEIGHT + STATUS_BAR_HEIGHT;
segmentControl.frame = frame;
segmentControl.backgroundColor = APP_VIEW_BACKGROUND_COLOR;
// Delay execution of my block for 10 seconds.
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, .5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
[self connectServer:api withParams:params withProgressMessage:#"তথ্য লোড হচ্ছে, একটু অপেক্ষা করুন..."];
});
viewNothiPermittedUsers.hidden = YES;
viewNothiPermittedUsers.backgroundColor = [UIColor colorWithWhite:0.0F alpha:0.7f];
labelTitleNothiPermittedUsers.backgroundColor = [UIColor lightGrayColor];
[labelTitleNothiPermittedUsers.layer setCornerRadius:8.0f];
labelTitleNothiPermittedUsers.layer.masksToBounds = YES;
labelTitleNothiPermittedUsers.font = [UIFont boldFlatFontOfSize:16.0f];
tableViewNothiPermittedUsers.backgroundColor = [UIColor whiteColor];
tableViewNothiPermittedUsers.tableFooterView = [[UIView alloc] initWithFrame : CGRectZero];
[tableViewNothiPermittedUsers.layer setCornerRadius:8.0f];
tableViewNothiPermittedUsers.layer.masksToBounds = YES;
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(notifyNothiForward:) name:EventNothiForward object:nil];
}
Any help would be highly appreciated. Note i am kind of new to IOS programming and the project was written by someone else, which i just got now to extend it, so i am little aware of positioning views at the moment.
I'm trying to display the yaw pitch and roll of the device in a label. I cannot seem to get the values to display, it only shows a '...' where the numbers should be. This is my code, any help is greatly appreciated.
#import "ViewController.h"
#import <CoreMotion/CoreMotion.h>
#interface ViewController (){
}
#property (strong, nonatomic) CMMotionManager *motionManager;
#end
#implementation ViewController
#synthesize motionManager;
#synthesize roll;
#synthesize pitch;
#synthesize yaw;
#synthesize xLabel;
#synthesize yLabel;
#synthesize zLabel;
- (void)viewDidLoad {
[super viewDidLoad];
/** Do any additional setup after loading the view, typically from a nib.
UIAccelerometer *accelerometer = [UIAccelerometer sharedAccelerometer];
accelerometer.updateInterval = 1.0f/60.0f;
accelerometer.delegate = self;
**/
//motionManager = [[CMMotionManager alloc] init];
//motionManager.deviceMotionUpdateInterval = 1.0 / 60.0;
motionManager = [[CMMotionManager alloc] init];
NSTimer *timer;
timer = [NSTimer scheduledTimerWithTimeInterval:1.0/60.0 target:self selector:#selector(doGyroUpdate) userInfo:nil repeats:YES];
//CMDeviceMotion *deviceMotion = motionManager.deviceMotion;
//CMAttitude *attitude = deviceMotion.attitude;
[motionManager startDeviceMotionUpdates];
}
-(void)doGyroUpdate
{
double x = motionManager.deviceMotion.attitude.roll*180/M_PI;
double y = motionManager.deviceMotion.attitude.pitch*180/M_PI;
double z = motionManager.deviceMotion.attitude.yaw*180/M_PI;
NSString *myString = [NSString stringWithFormat:#"%g", x];
xLabel.text = myString;
myString = [NSString stringWithFormat:#"%f", y];
yLabel.text = myString;
myString = [NSString stringWithFormat:#"%f", z];
zLabel.text = myString;
}
... indicates the UILabel you're using for displaying the text is not as wide as it should be.
Try and make it wider in your storyboard or xib file.
Try -
label.numberOfLines = 1;
label.minimumFontSize = 6;
label.adjustsFontSizeToFitWidth = YES;
Or you can try it by storyboard (Autoshrink option) -
You can use Autolayout for this. Here I have given 2 constraint
1. top from superView
2. leading from superview
Now whatever is your text it will display without .... .
I've been experiencing some difficulties with particle effects. Originally I posted a question about how the particle effects in my app were different when on an ios6 device.
Particle system looks different on iOS 6 and ios7
I Originally designed the app on an ios7 device and got the particles looking like I wanted, but on the ios6 device the particles were smaller and displaced.
I was told it was problem between ios6 and ios7 and that changing the media timing could fix it.
Ive tried everything, but nothing has worked.
Eventually I tried just creating a separate app and pasted in the code from this tutorial - http://weblog.invasivecode.com/post/45058779586/caemitterlayer-and-the-ios-particle-system-lets in the view did load. The particles work as they should, but when I put the same code into my current apps viewDidLoad. The particles were all over the place and not doing what they should be.
I'm wandering if there is something in my current app that Im missing, that is upsetting the particles. Can anyone suggest things to look for?
Originally the particle effects were subclassed and being called after adding a subview to my main view.
Here is my view controller .h code (I've taken out some irrelevant control object properties and outlets)
#interface HHViewController : UIViewController < HHScoreViewdelegate>
{
IBOutlet UIButton* btnStart;
IBOutlet UIButton* btnStop;
IBOutlet UIButton* btnMore;
IBOutlet UIButton* btnHelp;
IBOutlet UIButton* btnTessilaCoil;
IBOutlet UIImageView* imgAnimatedTessila;
IBOutlet UIImageView* imgBubble;
IBOutlet UIImageView* imgSteam;
IBOutlet UIImageView* imgMachineLightsTop;
IBOutlet UIImageView* imgBackground;
NSTimer* StopSignTimer;
NSTimer* timer;
NSTimer* lightMachineTimer;
NSTimer* ComputerLightsTimer;
CGFloat AnimationDelay;
AVAudioPlayer* audioPlayer;
AVAudioPlayer* audioPlayer2; //Used for game end audio, so that it doesnt interupt last letter/number audio
int pageValue;
IBOutlet UIButton* btnSetting;
IBOutlet UIButton* btnIAP;
IBOutlet UIButton* btnNext;
IBOutlet UIButton* btnForward;
IBOutlet UIImageView* imgLightMachine;
IBOutlet UIImageView* imgComputerLights;
NSString* strletterName;
HHScoreView * scoreSelection;
More * MorePanelView;
InAppPurchase * InAppPurchaseView;
NSMutableArray* ButtonBackgroundImages;
NSMutableArray* AlphabetBubbles;
NSMutableArray* SavedBubblePositions;
NSTimer* bubbleBlinkingTimer;
int wrongbubbleTapCount;
IBOutlet UIImageView* imgAlphabetDisplay;
IBOutlet UILabel* lblNextOneToPop;
// Code from Particle Tutorial
CAEmitterLayer *_myEmitter;
CAEmitterCell *_myCell;
// End code form Particle Tutorial
}
// Code from Particle Tutorial
#property(nonatomic, retain) CAEmitterLayer *_myEmitter;
#property(nonatomic, retain) CAEmitterCell *_myCell;
// End code form Particle Tutorial
#property(nonatomic,strong) UILabel* lblNextOneToPop;
#property(nonatomic,strong) NSTimer* SteamTimer;
#property(nonatomic,strong) NSTimer* StopSignTimer;
#property(nonatomic,strong) NSTimer* timer;
#property(nonatomic,strong) NSTimer* lightMachineTimer;
#property(nonatomic,strong) NSTimer* ComputerLightsTimer;
#property(nonatomic,retain)IBOutlet UIButton* btnStart;
#property(nonatomic,retain)IBOutlet UIButton* btnStop;
#property(nonatomic,retain)IBOutlet UIButton* btnMore;
#property(nonatomic,retain)IBOutlet UIButton* btnHelp;
#property(nonatomic,retain)IBOutlet UIButton* btnSetting;
#property(nonatomic,retain)IBOutlet UIButton* btnTessilaCoil;
#property(nonatomic,retain)IBOutlet UIImageView* imgAnimatedTessila;
#property(nonatomic,retain)IBOutlet UIImageView* imgSteam;
#property(nonatomic,retain)IBOutlet UIImageView* imgMachineLightsTop;
#property(nonatomic,retain)IBOutlet UIImageView* imgBackground;
#property(nonatomic,retain)IBOutlet UIScrollView* scScrollView;
#property(nonatomic,retain)IBOutlet IBOutlet UIButton* btnNext;
#property(nonatomic,retain)IBOutlet IBOutlet UIButton* btnForward;
#property(nonatomic,retain)IBOutlet UIImageView* imgLightMachine;
#property(nonatomic,retain)IBOutlet UIImageView* imgComputerLights;
#property(nonatomic,retain)NSString* strletterName;
#property(assign)int allLettersEventCount;
#property(nonatomic,retain) NSArray* ButtonBackgroundImages;
#property Boolean StopButtonClicked;
#property Boolean BubbleAOnscreen;
#property (nonatomic,assign) BOOL cancelAll;
#property int pageValue;
#property int positionRotation;
-(IBAction)tapPiece:(UITapGestureRecognizer *)recognizer;
-(IBAction)actionStartSign:(id)sender;
-(IBAction)actionStopSign:(id)sender;
-(IBAction)actionMoreSign:(id)sender;
-(IBAction)actionHelpSign:(id)sender;
-(IBAction)actionTessilaCoil:(id)sender;
-(IBAction)actionbtnHelp:(id)sender;
-(IBAction)actionbtnSetting:(id)sender;
-(IBAction)actionbtnIAP:(id)sender;
+(HHViewController*)sharedManager;
- (IBAction)purchaseItem:(id)sender;
#property (strong, nonatomic) InAppPurchase *purchaseController;
#end
Here is the code from my viewcontroller .m where I added the code from the tutorial.
#interface HHViewController ()
{
}
#end
#implementation HHViewController
static int OrderingSequence = 0;
#synthesize _myEmitter, _myCell;
/*
TeslarGlowEffect* ShowGlow;
SteamEffect* ShowSteam;
BubbleBurst* PopBubble;
*/
//TeslarTimerSparks* TeslarTimer;
- (void)viewDidLoad
{
[super viewDidLoad];
CFTimeInterval currentTime = [self.view.layer convertTime:CACurrentMediaTime() fromLayer:nil];
NSLog(#"Current media Timing = %f", currentTime);
// Code from tutorial
CAEmitterLayer *emitterLayer = [CAEmitterLayer layer]; // 1
emitterLayer.emitterPosition = CGPointMake(self.view.bounds.size.width / 2, self.view.bounds.origin.y); // 2
emitterLayer.emitterZPosition = 10; // 3
emitterLayer.emitterSize = CGSizeMake(self.view.bounds.size.width, 0); // 4
emitterLayer.emitterShape = kCAEmitterLayerSphere; // 5
CAEmitterCell *emitterCell = [CAEmitterCell emitterCell]; // 6
emitterCell.scale = 0.1; // 7
emitterCell.scaleRange = 0.2; // 8
emitterCell.emissionRange = (CGFloat)M_PI_2; // 9
emitterCell.lifetime = 5.0; // 10
emitterCell.birthRate = 10; // 11
emitterCell.velocity = 200; // 12
emitterCell.velocityRange = 50; // 13
emitterCell.yAcceleration = 250; // 14
emitterCell.contents = (id)[[UIImage imageNamed:#"Steam1.png"] CGImage]; // 15
emitterLayer.emitterCells = [NSArray arrayWithObject:emitterCell]; // 16
[self.view.layer addSublayer:emitterLayer]; // 17
//end code from tutorial
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(appWillEnterForegroundNotification:)
name:UIApplicationWillEnterForegroundNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(appWillEnterBackgroundNotification:)
name:UIApplicationDidEnterBackgroundNotification
object:nil];
[btnStart addTarget:self action:#selector(actionStartSign:) forControlEvents:UIControlEventTouchUpInside];
//NSLog(#"OrderingSequence = %d",OrderingSequence );
imgAnimatedTessila.image = [UIImage imageNamed:KTESSILAIMAGE];
self.alphebetindex = 0;
wrongbubbleTapCount = 0;
//// Load a bunch of arrays used in the game.
[btnHelp addTarget:self action:#selector(actionbtnHelp:) forControlEvents:UIControlEventTouchUpInside];
[btnSetting addTarget:self action:#selector(actionbtnSetting:) forControlEvents:UIControlEventTouchUpInside];
NSString* strFirstTimeloaded = [[NSUserDefaults standardUserDefaults]valueForKey:#"FirstTime"];
if(strFirstTimeloaded == nil)
{
// Show preference page if first time used.
[[NSUserDefaults standardUserDefaults]setValue:#"English" forKey:#"Language"];
LanguagesSelectView* selection = [[LanguagesSelectView alloc]initWithFrame:CGRectMake(0, 0, 1024, 748)];
[self.view addSubview:selection];
[[NSUserDefaults standardUserDefaults]setValue:#"FirstTime" forKey:#"FirstTime"];
}
positionRotation = 0;
self.strletterName = #"29";
self.allLettersEventCount = 0;
[[NSUserDefaults standardUserDefaults] setValue:#"One" forKey:#"Mode"];
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(enableSetting) name:#"EnableSetting" object:nil];
//[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(LetterTapped:) name:#"LetterTapped" object:nil];
btnStop.hidden = YES;
btnNext.hidden = YES;
btnForward.hidden = YES;
[self addGestureRecognizersToView];
//Create timer for release of steam from bubble machine
SteamTimer = [NSTimer scheduledTimerWithTimeInterval:5.2 target:self selector:#selector(ShowSteamEffect) userInfo:nil repeats:YES];
//Set Font for lblNextOneToPop
[lblNextOneToPop setFont:[UIFont fontWithName:#"SF Slapstick Comic" size:110]];
lblNextOneToPop.hidden = YES;
}
Here is one of my particle effects that was working on my ios7 iPad, but on the ios6 iPad, the effect looked totally different.
It was after long hrs trying to figure out why the ios7 and ios6 looked different that I tried the exercise of putting the tutorial code into a new app and then it into my own app. In my app the particles are totally different, but as they should be in the new app.
With respect to #matt's comments below. I know there must be something going on with my app, but I can't see it. I've looked all over the web and all through my code and I think I'm missing something.
All I want are three particles effects that appear at specific locations regardless of iOS version. One of them on user touch. The effect below is just one of them. I've tried the CAmediaTiming thing, but that didn't work.
SteamEffect.h
#import <UIKit/UIKit.h>
#interface SteamEffect : UIView
#end
The steamEffect.m looks like this.
#import "SteamEffect.h"
#implementation SteamEffect
{
CAEmitterLayer* SteamEmitter;
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
SteamEmitter = (CAEmitterLayer*) self.layer;
//SteamEmitter.emitterPosition= CGPointMake(0, 0);
//SteamEmitter.emitterSize = CGSizeMake(10,10);
CAEmitterCell* Steam = [CAEmitterCell emitterCell];
Steam.birthRate = 50.0f;
Steam.spin = .6f;
Steam.lifetime = 1.7f;
Steam.alphaRange = 0.2f;
Steam.alphaSpeed = 0.2f;
Steam.contents = (id)[[UIImage imageNamed:#"Steam1.png"]CGImage];
Steam.velocity = 30;
Steam.velocityRange = 50.0f;
Steam.emissionLongitude = -60.0f;
Steam.emissionRange = M_1_PI;
Steam.scale = .2f;
Steam.scaleSpeed = .5f;
Steam.yAcceleration = -200.0f;
//SteamEmitter.renderMode = kCAEmitterLayerBackToFront;//kCAEmitterLayerAdditive;
//SteamEmitter.emitterShape = kCAEmitterLayerCircle;
SteamEmitter.emitterCells = #[Steam];
SteamEmitter.emitterPosition = CGPointMake(815, 445);
//Check System Version
NSArray *vComp = [[UIDevice currentDevice].systemVersion componentsSeparatedByString:#"."];
if ([[vComp objectAtIndex:0] intValue] == 7) {
// iOS-6 code
SteamEmitter.beginTime = CACurrentMediaTime();
}
}
return self;
}
-(void)didMoveToSuperview
{
//1
[super didMoveToSuperview];
if (self.superview==nil) return;
[self performSelector:#selector(disableEmitterCell) withObject:nil afterDelay:0.5];
}
-(void)disableEmitterCell
{
[SteamEmitter setValue:#0 forKeyPath:#"birthRate"];
}
+ (Class) layerClass
{
//tell UIView to use the CAEmitterLayer root class
return [CAEmitterLayer class];
}
- (void) setEmitterPosition:(CGPoint)pos
{
SteamEmitter.emitterPosition = pos;
}
- (void) toggleOn:(bool)on
{
//SteamEmitter.birthRate = on? 300 : 0;
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
#end
I called the above from my viewcontroller .m using the following. There is also a timer in the viewDidLoad above that calls this every 5 sec. Although that is probably not the way to do it. Probably better to add the view and start it emitting every 5 sec rather than adding a new view each time, but thats a different issue.
- (void)ShowSteamEffect
{
//Check System Version because NSAttributedString only works in ios6 and above.
NSArray *vComp = [[UIDevice currentDevice].systemVersion componentsSeparatedByString:#"."];
//Create view for Steam particle effect.
//CGRect SteamFrame = CGRectMake(790, 380, 100, 100); //ORIGINAL
CGRect SteamFrame = CGRectMake(0, 0, 0, 0); //(815, 455, 100, 100)
//Show Steam effect
ShowSteam = [[SteamEffect alloc]initWithFrame:SteamFrame];
ShowSteam.hidden = NO;
[self.view insertSubview:ShowSteam aboveSubview:imgComputerLights];
}
Moving text like marquee style from bottom to top in iOS application. i have tried this long time using google search but i could not get perfect answer for this question please provide any code for this question. i an new to iOS application.
Try this
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
NSTimer *timer;
UILabel *label ;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
timer =[NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:#selector(scrollText:) userInfo:nil repeats:YES];
label = [[UILabel alloc] initWithFrame:CGRectMake(20, 50, 250, 20)];
label.text =#"This is a string to be scroll";
[self.view addSubview:label];
}
-(void)scrollText:(id)parameter{
if (label.frame.origin.y <= 50) {
[label setFrame:CGRectMake(label.frame.origin.x, 400, label.frame.size.width, label.frame.size.height)];
}
else
[label setFrame:CGRectMake(label.frame.origin.x, label.frame.origin.y-5, label.frame.size.width, label.frame.size.height)];
}
#end
You can find the same implementation in the below link. It's really awesome place for COCOA CONTROL.
COCOA CONTROLS
Check this answer.
.h
NSTimer *timer;
float timeDuration;
.m
-(void)viewDidLoad {
[super viewDidLoad];
timeDuration=1.0f;
timer = [NSTimer scheduledTimerWithTimeInterval:timeDuration target:self selector:#selector(marqueeAnimation) userInfo:nil repeats:YES];
}
-(void)marqueeAnimation{
UIImageView *imgView=[[UIImageView alloc]initWithFrame:CGRectMake(100, -100, 100, 100)];
[imgView setImage:[UIImage imageNamed:#"root.PNG"]];
[self.view addSubview:imgView];
NSString *keyPath = #"transform.translation.y";
CAKeyframeAnimation *translation = [CAKeyframeAnimation animationWithKeyPath:keyPath];
translation.duration = timeDuration;
translation.autoreverses = NO;
NSMutableArray *values = [[NSMutableArray alloc] init];
[values addObject:[NSNumber numberWithFloat:0.0f]];
CGFloat height = [[UIScreen mainScreen] applicationFrame].size.height;
[values addObject:[NSNumber numberWithFloat:height]];
translation.values = values;
NSMutableArray *timingFunctions = [[NSMutableArray alloc] init];
[timingFunctions addObject:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]];
translation.timingFunctions = timingFunctions;
[imgView.layer addAnimation:translation forKey:keyPath];
}
Try this. This works. Try this in a sample app and then include it in your app.
#import "ViewController.h"
#interface ViewController ()
#property(nonatomic, retain) NSTimer *timer;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[_txtView setText:#"hi..."];
_timer = [NSTimer scheduledTimerWithTimeInterval:0.01f target:self selector:#selector(marqueeScroll) userInfo:nil repeats:YES];
}
-(void) marqueeScroll
{
[_txtView setFrame:CGRectMake(_txtView.frame.origin.x, _txtView.frame.origin.y-1.0, _txtView.frame.size.width, _txtView.frame.size.height)];
CGRect screen = [[UIScreen mainScreen] bounds];
if(_txtView.frame.origin.y <= 0 )
{
[_txtView setFrame:CGRectMake(_txtView.frame.origin.x, screen.size.height,_txtView.frame.size.width, _txtView.frame.size.height)] ;
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
Let me know if there are any errors.
The code here is a modal view launched from the RootViewController and is to display a video with a thumbnail filmstrip below the movie and then timed instructions bound to the movie.
It all works, but there is a memory leak / lack of release that I just can't see for looking and having spent three days trying to fix it, the time has come to ask for help...
If I disable the NSNotificationCenter by commenting it out (highlighted in the .m) I don't have any issues regarding memory and keep the timed text. But I also don't have any thumbnails. I have tried inserting [[NSNotificationCenter alloc] removeObserver:self]; at numerous points to see if that will get rid of it for me. But alas, to no avail.
I have also tried releasing the 'backgroundTimer' but it's not overly impressed when I try to compile and run.
In essence, the first time I load the modal view, there are no issues whatsoever and all seems great - However, if I close it with the -(IBAction)close:(id)sender; it seems something isn't releasing as the next time I launch the same page the memory usage increases by about 30% (roughly the amount that is used by the thumbnail generation) and increases by roughly the same amount each time I re-launch the modal view.
Please bare in mind I am a newbie to this and the error is likely to a bloody stupid one to those of you in the know. But in the interest of getting this project done, I'll gladly take any abuse you fancy throwing at me.
Here's the code:
.h
#import <UIKit/UIKit.h>
#import <MediaPlayer/MPMoviePlayerController.h>
#import "ImageViewWithTime.h"
#import "CommentView.h"
#interface SirloinVideoViewController_iPad : UIViewController {
UIView *landscapeView;
UIView *viewForMovie;
MPMoviePlayerController *player;
UILabel *onScreenDisplayLabel;
UIScrollView *myScrollView;
NSMutableArray *keyframeTimes;
NSArray *shoutOutTexts;
NSArray *shoutOutTimes;
NSTimer *backgroundTimer;
UIView *instructions;
}
-(IBAction)close:(id)sender;
-(IBAction)textInstructions:(id)sender;
#property (nonatomic, retain) IBOutlet UIView *instructions;
#property (nonatomic, retain) NSTimer *theTimer;
#property (nonatomic, retain) NSTimer *backgroundTimer;
#property (nonatomic, retain) IBOutlet UIView *viewForMovie;
#property (nonatomic, retain) MPMoviePlayerController *player;
#property (nonatomic, retain) IBOutlet UILabel *onScreenDisplayLabel;
#property (nonatomic, retain) IBOutlet UIScrollView *myScrollView;
#property (nonatomic, retain) NSMutableArray *keyframeTimes;
-(NSURL *)movieURL;
- (void) playerThumbnailImageRequestDidFinish:(NSNotification*)notification;
- (ImageViewWithTime *)makeThumbnailImageViewFromImage:(UIImage *)image andTimeCode:(NSNumber *)timecode;
- (void)handleTapFrom:(UITapGestureRecognizer *)recognizer;
#end
.m
#import "SirloinVideoViewController_iPad.h"
#import "SirloinTextViewController.h"
#implementation SirloinVideoViewController_iPad
#synthesize theTimer, backgroundTimer, viewForMovie, player,
onScreenDisplayLabel, myScrollView, keyframeTimes, instructions;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
}
return self;
[nibNameOrNil release];
[nibBundleOrNil release];
}
- (IBAction)close:(id)sender{
[self.parentViewController dismissModalViewControllerAnimated:YES];
[player stop];
[player release];
[theTimer invalidate];
[theTimer release];
[backgroundTimer invalidate];
[SirloinVideoViewController_iPad release];
}
—
-(IBAction)textInstructions:(id)sender {
SirloinTextViewController *vController = [[SirloinTextViewController alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:vController animated:YES];
[vController release];
}
- (void)viewDidLoad {
[super viewDidLoad];
keyframeTimes = [[NSMutableArray alloc] init];
shoutOutTexts = [[NSArray
arrayWithObjects:
#"1. XXXXXXXXXXXX",
#"2. XXXXXXXXXXXX",
#"3. XXXXXXXXXXXX",
#"4. XXXXXXXXXXXX",
#"5. XXXXXXXXXXXX",
#"6. XXXXXXXXXXXX"
#"7. XXXXXXXXXXXX",
#"8. XXXXXXXXXXXX",
#"9. XXXXXXXXXXXX",
#"10. XXXXXXXXXXXX",
#"11. XXXXXXXXXXXX",
#"12. XXXXXXXXXXXX",
#"13. XXXXXXXXXXXX",
#"14. XXXXXXXXXXXX",
#"15. XXXXXXXXXXXX",
nil] retain];
shoutOutTimes = [[NSArray
arrayWithObjects:
[[NSNumber alloc] initWithInt: 1],
[[NSNumber alloc] initWithInt: 73],
[[NSNumber alloc] initWithInt: 109],
[[NSNumber alloc] initWithInt: 131],
[[NSNumber alloc] initWithInt: 205],
[[NSNumber alloc] initWithInt: 250],
[[NSNumber alloc] initWithInt: 337],
[[NSNumber alloc] initWithInt: 378],
[[NSNumber alloc] initWithInt: 402],
[[NSNumber alloc] initWithInt: 420],
[[NSNumber alloc] initWithInt: 448],
[[NSNumber alloc] initWithInt: 507],
[[NSNumber alloc] initWithInt: 531],
[[NSNumber alloc] initWithInt: 574],
nil] retain];
self.player = [[MPMoviePlayerController alloc] init];
self.player.contentURL = [self movieURL];
self.player.view.frame = self.viewForMovie.bounds;
self.player.view.autoresizingMask =
UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleHeight;
[self.viewForMovie addSubview:player.view];
backgroundTimer = [NSTimer scheduledTimerWithTimeInterval:0.5f target:self selector:#selector(timerAction:) userInfo:nil repeats:YES];
[self.view addSubview:self.myScrollView];
//I am pretty sure that this is the culprit - Just not sure why...
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(movieDurationAvailable:)
name:MPMovieDurationAvailableNotification
object:theTimer];
//Could be wrong, but when commented out I don't have the memory issues
}
—
- (NSInteger)positionFromPlaybackTime:(NSTimeInterval)playbackTime
{
NSInteger position = 0;
for (NSNumber *startsAt in shoutOutTimes)
{
if (playbackTime > [startsAt floatValue])
{
++position;
}
}
return position;
}
-(NSURL *)movieURL
{
NSBundle *bundle = [NSBundle mainBundle];
NSString *moviePath =
[bundle
pathForResource:#"sirloin"
ofType:#"m4v"];
if (moviePath) {
return [NSURL fileURLWithPath:moviePath];
} else {
return nil;
}
}
NSTimeInterval lastCheckAt = 0.0;
- (void)timerAction: theTimer
{
int count = [shoutOutTimes count];
NSInteger position = [self positionFromPlaybackTime:self.player.currentPlaybackTime];
NSLog(#"position is at %d", position);
if (position > 0)
{
--position;
}
if (position < count)
{
NSNumber *timeObj = [shoutOutTimes objectAtIndex:position];
int time = [timeObj intValue];
NSLog(#"shout scheduled for %d", time);
NSLog(#"last check was at %g", lastCheckAt);
NSLog(#"current playback time is %g", self.player.currentPlaybackTime);
if (lastCheckAt < time && self.player.currentPlaybackTime >= time)
{
NSString *shoutString = [shoutOutTexts objectAtIndex:position];
NSLog(#"shouting: %#", shoutString);
CommentView *cview = [[CommentView alloc] initWithText:shoutString];
[self.instructions addSubview:cview];
[shoutString release];
}
}
lastCheckAt = self.player.currentPlaybackTime;
}
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
-(void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath {
[[NSNotificationCenter defaultCenter] removeObserver:MPMovieDurationAvailableNotification];
[[NSNotificationCenter defaultCenter] removeObserver:MPMoviePlayerThumbnailImageRequestDidFinishNotification];
[keyPath release];
}
- (void) movieDurationAvailable:(NSNotification*)notification {
float duration = [self.player duration];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(playerThumbnailImageRequestDidFinish:)
name:MPMoviePlayerThumbnailImageRequestDidFinishNotification
object:nil];
NSMutableArray *times = [[NSMutableArray alloc] init];
for(int i = 0; i < 20; i++) {
float playbackTime = i * duration/20;
[times addObject:[NSNumber numberWithInt:playbackTime]];
}
[self.player
requestThumbnailImagesAtTimes:times
timeOption: MPMovieTimeOptionExact];
}
- (void) playerThumbnailImageRequestDidFinish:(NSNotification*)notification {
NSDictionary *userInfo = [notification userInfo];
NSNumber *timecode =
[userInfo objectForKey: MPMoviePlayerThumbnailTimeKey];
UIImage *image =
[userInfo objectForKey: MPMoviePlayerThumbnailImageKey];
ImageViewWithTime *imageView =
[self makeThumbnailImageViewFromImage:image andTimeCode:timecode];
[myScrollView addSubview:imageView];
UITapGestureRecognizer *tapRecognizer =
[[UITapGestureRecognizer alloc]
initWithTarget:self action:#selector(handleTapFrom:)];
[tapRecognizer setNumberOfTapsRequired:1];
[imageView addGestureRecognizer:tapRecognizer];
[tapRecognizer release];
[image release];
[imageView release];
}
- (void)handleTapFrom:(UITapGestureRecognizer *)recognizer {
ImageViewWithTime *imageView = (ImageViewWithTime *) recognizer.view;
self.player.currentPlaybackTime = [imageView.time floatValue];
}
- (ImageViewWithTime *)makeThumbnailImageViewFromImage:(UIImage *)image andTimeCode:(NSNumber *)timecode {
float timeslice = self.player.duration / 3.0;
int pos = [timecode intValue] / (int)timeslice;
float width = 75 *
((float)image.size.width / (float)image.size.height);
self.myScrollView.contentSize =
CGSizeMake((width + 2) * 13, 75);
ImageViewWithTime *imageView =
[[ImageViewWithTime alloc] initWithImage:image];
[imageView setUserInteractionEnabled:YES];
[imageView setFrame:CGRectMake(pos * width + 2, 0, width, 75.0f)];
imageView.time = [[NSNumber alloc] initWithFloat:(pos * timeslice)];
return imageView;
[myScrollView release];
}
- (void)dealloc {
[player release];
[viewForMovie release];
[onScreenDisplayLabel release];
[keyframeTimes release];
[instructions release];
[shoutOutTexts release];
[shoutOutTimes release];
[super dealloc];
}
#end
This app is already out there heavily using UIWebView (which just plain sux) so I am trying to things right and do it properly.
You do have a couple more issues than one leak.
The first one
is in your initWithNibName:bundle: as you aren't doing anything useful there: get rid of it, entirely! (Besides: don't release arguments, that are passed to your methods! Luckily, you've placed those releases in lines that are unreachable, i.e. after the return statement...)
Next method, next problems
Why are you sending release to a class object? Don't! That's wrong on many levels.
You have decided to create properties for your timers. That's nothing bad per se. But why then, are you using the ivars directly here? I'd strongly encourage you to implement setTheTimer: and setBackgroundTimer: to handle the invalidation and release properly and simply do self.theTimer = nil; self.backgroundTimer = nil; here. That would fix the asymmetry in handling those things, as well. (By the way: theTimer isn't such a great name for an ivar...especially when there is another ivar that is a timer!)
textInstructions: looks unsuspicious but...
viewDidLoad has some more issues
It leaks an MPMoviePlayerController:
The #property will retain it, so you need to balance the alloc here.
backgroundTimer has a corresponding #property that is declared to be retaining: You are violating this API contract here, since you only assign the timer to the ivar. Use self.backgroundTimer = ... instead.
From all the code you posted, it seems to me that passing theTimer as the last argument in your call to -[NSNotificationCenter addObserver:selector:name:object:] is a fancy way of passing in nil as that parameter. Which is kind of good, because usually NSTimer doesn't post too many MPMovieDurationAvailableNotifications. In fact, as I can't see theTimer being used except in close:: Could it be that this is just a useless remnant from before you introduced the backgroundTimer ivar/#property? (Well there is another occurrence of a variable of that name, but it should be accompanied by a big fat compiler warning...)
Do you, in any way, implement viewDidUnload? If so, does it:
self.player = nil;?
[shoutOutTexts release], shoutOutTexts = nil;?
[shoutOutTimes release], shoutOutTimes = nil;?
self.keyframeTimes = nil;?
[[NSNotificationCenter defaultCenter] removeObserver:self name: MPMovieDurationAvailableNotification object:nil];?
self.backgroundTimer = nil;? (Assuming, setBackgroundTimer: releases and invalidates the old value)
Update I've missed this one on the first go: You are leaking 15 NSNumbers here. Use [NSNumber numberWithInt:] instead of alloc/init in the setup of shoutOutTimes.
A minor remark on movieURL, which you can turn into the following one-liner:
-(NSURL*)movieURL {
return [[NSBundle mainBundle] URLForResource:#"sirloin" withExtension:#"m4v"];
}
And then this
NSTimeInterval lastCheckAt = 0.0; within the global scope. From your usage of it: ivar PLZ?!?one?
More issues later. I gotta get myself something to eat first.
Part Two
Now let's get into timerAction:
The first issue is not too grave, — especially in this particular context — but you should be aware that -[NSArray count] returns an NSUInteger and that the U is not a typo, but a designation that this value is unsigned. You certainly won't run into problems with the signedness in this App and rarely do on other occasions, but when you do, they make up for really funky bugs and you should be aware of the implications...
The real issue with this method is, however, that you are leaking one CommentView per iteration while — at the same time — overreleasing one NSString. The fact, that you were using string literals (which will never be dealloced) in the first place, (i.e. when you were initializing shoutOutTimes) totally saves your butt, here.
Next up: removeObserver:forKeyPath:
You really should get rid of that really bad habit of releasing parameters, that are passed to your methods!
That being said, get rid of the entirety of this method!
First and foremost removeObserver:forKeyPath: is a method from the NSKeyValueObserving informal protocol and plays a totally different role than what you are (ab-)using it to accomplish here.
Secondly, it is one of those methods where it is essential to call through to super if — by any means — you really need to override it. (Well, except, when you were overriding addObserver:forKeyPath:options:context: as well and-it-should-go-without-saying-that-you-shouldn't-do-that-unless-you-really-know-what-you-are-doing-if-you-ever-planned-on-using-KVO.)
movieDurationAvailable:
Like Evan said, you're leaking times here. Go for his suggestion or — instead — make it NSMutableArray *times = [NSMutableArray array]; and you are done here.
playerThumbnailImageRequestDidFinish:
You don't own image, so don't release it!
Personally, I would finish setting up the view (i.e. add the recognizer and do stuff like that) before adding it into the view-hierarchy, but that's completely a matter of taste...
makeThumbnailImageViewFromImage:andTimeCode:
...leaks an NSNumber (use [NSNumber numberWithFloat:(pos * timeslice)] instead of the alloc/initWithFloat:-dance) and prevents you from crashing due to overreleasing myScrollView by the unconditional return statement that directly precedes it (phew!).
While we're at it: rename this method to either newThumbnailImageView... so that when you'll revisit this code in a year or so, you instantly know that [imageView release]; at the bottom of playerThumbnailImageRequestDidFinish: really is necessary, without having to look at the implementation of this method.
Alternatively, you could rename it to thumbnailImageView... and change the return statement to return [imageView autorelease];. Bonus: one fewer line in playerThumbnailImageRequestDidFinish: as the [imageView release]; there becomes obsolete then.
dealloc
Add [[NSNotificationCenter defaultCenter] removeObserver:self]; at the very top.
The rest of it looks okay. (Although I find it odd, that the ivar landscapeView is never/nowhere mentioned apart from its declaration.)
Summary
Read the sections Memory Management Rules and Autorelease from Apple's "Memory Management Programming Guide" once again. They're pure gold!
You never release times in movieDurationAvailable::
NSMutableArray *times = [[NSMutableArray alloc] init];
You should use autorelease when you pass it to the method:
[self.player requestThumbnailImagesAtTimes:[times autorelease] timeOption: MPMovieTimeOptionExact];