Đặc tính thông minh của Xcode 10
Mới ra bản beta nhưng mình thấy xcode 10 cải thiện khá thông minh, lần trước mình có phản hồi việc không folding được block code thế là team phát triển của Apple đã cải thiện nó (nói thật đấy). Sau đây là vài tính năng mình cảm nhận được:
- Cho phép folding block code như vòng lặp for hay kiểm tra rẽ nhánh if.
- Source Control thông minh hơn, cho phép discard 1 đoạn nhỏ mà không cần Source Tree.
Chưa quen:
- cái quản lý đối tượng để dùng trong Main Storyboard đã tách riêng ra, không còn nằm bên phải bên dưới nữa.
Bản này chỉ có Dark mode khi cài trên Mac Mojave trở đi
Lỗi build app với tài khoản trả phí Paid
Khi build nó phát sinh ra lỗi signing, để giải quyết thì chỉ cần sang máy build được và vào acc setting -> export ra cái developerprofile. Xong rồi vào máy không build được import là ok
Tham khảo:
Lỗi whose view is not in the window hierarchy
Khi show 1 popup trong UINavigation thì hay gặp lỗi này
Cách giải quyết là lấy thằng Vc trên cùng trong stack và hiện popup dựa trên đối tượng đó.
Tạo hàm:
- (UIViewController*) topMostController { UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController; while (topController.presentedViewController) { topController = topController.presentedViewController; } return topController; }
Khi show popup:
UIViewController *topVC = [self topMostController]; [topVC presentViewController:alertVC animated:YES completion:nil];
Cách tạo 1 label chuẩn và lưu ý khi tạo label
UILabel *subformatLbl = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, (view_cha_cua_label).bounds.size.width, 50)]; subformatLbl.textColor = [self colorFromHexString:@"#dbdbdb"]; subformatLbl.text = @"Text Luon Center"; subformatLbl.textAlignment = NSTextAlignmentCenter; [subformatLbl setFont:[UIFont systemFontOfSize:12]]; [view_cha_cua_label addSubview:subformatLbl];
Một UIView có 1 điểm center
Điểm center sẽ bằng
center.x = frame.origin.x + (width/2)
center.y = frame.origin.y + (height/2)
Chú ý:
frame theo hệ quy chiếu bên trong superview
bound theo hệ quy chiếu bên trong chính nó, tức là bao gồm (x,y) (w,h)
Đọc thêm: https://stackoverflow.com/a/11282765/11119281
Các vấn đề liên quan đến ký tự khi làm đa ngôn ngữ với ứng dụng iot
- 1 ký tự alphabet có số lượng bao nhiêu thì nặng bấy nhiêu tức là ký tự a có 1 ký tự và nặng 1 byte
- 1 ký tự hiragana, katakana, kanji tiếng Nhật, kanji tiếng Trung nặng 3 bytes. Ví dụ: 日本語 nặng 9 bytes
- 1 ký tự có dấu trong tiếng Việt nặng 2 byte. Ví dụ: ô nặng 2 bytes
Đếm số ký tự và số lượng byte trong ký tự tại đây https://mothereff.in/byte-counter#
Gặp lỗi malloc: *** error for object Invalid pointer dequeued from free list set a breakpoint in malloc_error_break to debug
Lỗi này là do sử dụng bộ nhớ không đủ khi khởi tạo char hoặc uint8_t cách giải quyết là khởi tạo mảng ban đầu lớn lên và sau khi dùng phải free cái mảng ấy:
đây là đoạn code đúng:
uint8_t* finalUnsignedChar = (unsigned char*)malloc(SET_LIST_PATH_STR_MAX); memset(finalUnsignedChar, 0x00, SET_LIST_PATH_STR_MAX); memset(myResult, 0x00, 3); int mySum = 0; for(int i = 0; i < countCharacter;i++){ NSString * newString = [path substringWithRange:NSMakeRange(i, 1)]; [self newConvertStrToThreeByte:newString]; if(i==0){ finalUnsignedChar[0] = myResult[0]; finalUnsignedChar[1] = myResult[1]; finalUnsignedChar[2] = myResult[2]; }else{ finalUnsignedChar[mySum] = myResult[0]; finalUnsignedChar[mySum+1] = myResult[1]; finalUnsignedChar[mySum+2] = myResult[2]; } mySum += 3; } data.setListPathStrLen = mySum; memcpy(data.setListPathStr, finalUnsignedChar, data.setListPathStrLen); free(finalUnsignedChar);
Cách gọi 1 hàm trong ViewController khác trong NavigationVC
UIViewController * currentController = self.visibleViewController; if ([currentController isKindOfClass:[MenuViewController class]]) { [((MenuViewController *) currentController) didReceiveData]; }
Tạo đối tượng mới và gọi hàm didReceiveData trong MenuVC
Lỗi Navigation Bar nằm đè lên TableView
Mình đã gặp lỗi này và giải quyết nhưu sau:
- Mở storyboard đang dùng.
- Chọn vào Navigation chính sau đó sang bên phải chọn Attributes Inspector
- Trong phần Simulated Metrics thay đổi mục Top Bar từ “Inferred” thành “Opaque Navigation Bar”
- Chọn vào View Controller chứa cái tableview đang bị đè, bỏ check Under Top Bars
Ok Command+R
Tạo UIslider theo chiều dọc
UISlider *slider = [[UISlider alloc] initWithFrame:CGRectMake(2.9 * BU, (160 - 9) * BU, 6.4 * BU, 6.4 * BU)]; [slider addTarget:self action:@selector(controlValueChanged:) forControlEvents:UIControlEventValueChanged]; slider.minimumValue = 100.00; slider.maximumValue = 1000.00; CGAffineTransform trans = CGAffineTransformMakeRotation(M_PI_2); slider.transform = trans; [slider setMinimumTrackTintColor:[UIColor clearColor]]; [slider setMaximumTrackTintColor:[UIColor clearColor]]; slider.continuous = YES; [self.view addSubview:slider];
Xử lí sự kiện
-(void)controlValueChanged:(id)sender { NSLog(@"controlValueChanged"); }
Tạo TableView trong ViewController
Trong VC thực hiện các delegate và gán data cho mảng.
#import "ViewController.h" @interface ViewController () <UITableViewDelegate,UITableViewDataSource> @property (weak, nonatomic) IBOutlet UITableView *tbView; @property (strong,nonatomic) NSArray *content; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; self.title = @"My Tbl View"; self.tbView.delegate = self; self.tbView.dataSource = self; self.content = @[ @"Monday", @"Tuesday", @"Wednesday",@"Thursday",@"Friday",@"Saturday",@"Sunday"]; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return _content.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *cellIdentifier = @"cellIdentifier"; UITableViewCell *cell = [self.tbView dequeueReusableCellWithIdentifier:cellIdentifier]; if(cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier]; } cell.textLabel.text = [_content objectAtIndex:indexPath.row]; return cell; } - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath; { NSLog(@"title of cell %@", [_content objectAtIndex:indexPath.row]); } @end
Bên MainStoryboard:
- thực hiện ánh xạ UITableView vào biến tbview
- click chọn vào UITableView và tạo 1 prototype cell đồng thời gán cell ID cho nó.
Ẩn hiện TableView trong ios
Ẩn
[self.tbMenu setHidden:YES];
Hiện
[self.tbMenu setHidden:NO];
Đếm số ViewController trong Stack của NavigationVC
unsigned long count = [[self.navigationController viewControllers] count]; NSLog(@"controllers : %@", [self.navigationController viewControllers]); NSLog(@"count : %ld", count);
2 câu lệnh trên lấy đc luôn cả VC hiện tại.
Chụp màn hình iPhone trong Obj-C
- (IBAction)captureAction:(id)sender { if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) { UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, [UIScreen mainScreen].scale); } else { UIGraphicsBeginImageContext(self.view.bounds.size); } [self.view.layer renderInContext:UIGraphicsGetCurrentContext()]; UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); NSData *data = UIImagePNGRepresentation(image); [data writeToFile:@"snapshot.png" options:NSDataWritingWithoutOverwriting error:Nil]; [data writeToFile:@"snapshot.png" atomically:YES]; [screenShot setImage:image]; [self.view addSubview:screenShot]; UIImageWriteToSavedPhotosAlbum([UIImage imageWithData:data], nil, nil, nil); }
Nhớ thêm Privacy trong Info.plist
<key>NSPhotoLibraryUsageDescription</key> <string>Grant Access Album</string> <key>NSPhotoLibraryAddUsageDescription</key> <string>Grant Access Album</string>
Kinh nghiệm khi tạo nhiều Label
Khi tạo label mà cần update cho nó thì nên tạo riêng biệt, ko nên vì sự tiện lợi tạo hàng loạt thông qua hàm. Có thể gặp lỗi ko thể update đc label.
Hẹn giờ chạy 1 hàm Obj-c
-(void)Chay{ [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(hidePreviewScreenshot:) userInfo:nil repeats:NO]; } -(void)hidePreviewScreenshot:(NSTimer *)timer { [screenShot removeFromSuperview]; }
Hiển thị ảnh với border và radius border
screenShot = [[UIImageView alloc]initWithFrame:CGRectMake(3*HBU, 110*HBU, 100, 200)]; [screenShot setContentMode:UIViewContentModeScaleAspectFit]; [screenShot.layer setBorderColor: [[UIColor blackColor] CGColor]]; [screenShot.layer setBorderWidth: 6.0]; screenShot.layer.cornerRadius = 10; UIImage *image = [UIImage imageNamed:@"YourImageName"]; [screenShot setImage:image]; [self.view addSubview:screenShot];
Thêm gạch chân cho UIlabel
lbl = [[UILabel alloc] initWithFrame:CGRectMake(pointX*WBU, pointY*HBU, widthLbl*WBU, 6*HBU)]; lbl.text = str; NSMutableAttributedString *text = [[NSMutableAttributedString alloc] initWithString:str]; [text addAttribute:NSUnderlineStyleAttributeName value:@(NSUnderlineStyleSingle) range:NSMakeRange(0, text.length)]; lbl.attributedText = text; [self.view addSubview:lbl];
Tạo button bằng code objc
calibrateBtn = [UIButton buttonWithType:UIButtonTypeCustom]; [calibrateBtn addTarget:self action:@selector(calibrateAction:) forControlEvents:UIControlEventTouchUpInside]; [calibrateBtn setTitle:@"Calibrate" forState:UIControlStateNormal]; calibrateBtn.backgroundColor = [self colorFromHexString:@"#63aeed"]; [calibrateBtn setTitleColor:[self colorFromHexString:@"#FF0000"] forState:UIControlStateNormal]; calibrateBtn.titleLabel.font = [UIFont systemFontOfSize:30]; calibrateBtn.frame = CGRectMake(4.5*WBU, 40*HBU, 80*WBU, 15*HBU); calibrateBtn.clipsToBounds = YES; calibrateBtn.layer.cornerRadius = 10; calibrateBtn.layer.borderColor = [self colorFromHexString:@"#63aeed"].CGColor; calibrateBtn.layer.borderWidth=2.0f; [self.view addSubview:calibrateBtn];
- (IBAction)calibrateAction:(id)sender { NSLog(@"calibrateAction act"); }
Tạo ảnh bằng code obj
bleIconImg = [[UIImageView alloc] initWithFrame:CGRectMake(62*WBU, 142*HBU, 25*WBU, 8*HBU)]; [bleIconImg setImage:[UIImage imageNamed:@"bluetooth_on"]]; [bleIconImg setContentMode:UIViewContentModeScaleAspectFit]; bleIconImg.center = CGPointMake(self.view.frame.size.width / 2, (148*HBU)); [[self view] addSubview:bleIconImg];
Hiển thị màu với mã Hex
- (UIColor *)colorFromHexString:(NSString *)hexString { unsigned rgbValue = 0; NSScanner *scanner = [NSScanner scannerWithString:hexString]; [scanner setScanLocation:1]; // bypass '#' character [scanner scanHexInt:&rgbValue]; return [UIColor colorWithRed:((rgbValue & 0xFF0000) >> 16)/255.0 green:((rgbValue & 0xFF00) >> 8)/255.0 blue:(rgbValue & 0xFF)/255.0 alpha:1.0]; }
cách dùng:
self.view.backgroundColor = [self colorFromHexString:@"#bdc3c7"];
show ra 1 ký tự char ở dạng hex (convert char to hex)
NSLog(@"hex la: |%02X|", buf[5]);
buf là 1 mảng ký tự ở định dạng char không âm: (unsigned char*)buf
ở đây tôi in phần tử thứ 5 trong mảng.
tham khảo thêm: https://stackoverflow.com/questions/6645013/objective-c-convert-char-to-nsstring-in-hex-format
Lấy chiều rộng và cao màn hình iPhone, iPad
CGFloat fullWidth; CGFloat fullHeight; - (void)viewDidLoad { [super viewDidLoad]; CGFloat statusBarHeight = [self statusBarHeight]; fullWidth = [UIScreen mainScreen].bounds.size.width; fullHeight = [UIScreen mainScreen].bounds.size.height; }
Lấy chiều cao status bar của iPhone, iPad
-(float) statusBarHeight { CGSize statusBarSize = [[UIApplication sharedApplication] statusBarFrame].size; return MIN(statusBarSize.width, statusBarSize.height); }
Thêm ảnh vào dự án ios
Click chuột phải vào nơi bạn muốn thêm -> chọn Add files to… là ok.
* Chú ý:
bluetooth_on@2x~iphone.png: định dạng này thì chỉ có iphone hiển thị
bluetooth_on@2x~ipad.png: định dạng này thì chỉ có ipad hiển thị
Cái 2x, 3x hay không có 2x, 3x như thế này bluetooth_off~ipad.png đằng sau là ipad nó sẽ tự nhận ra có retina hay không.
2x là 2 lần ảnh gốc.
3x là 3 lần ảnh gốc.
Underline 1 label
// To underline text in UILable NSMutableAttributedString *text = [[NSMutableAttributedString alloc] initWithString:str]; [text addAttribute:NSUnderlineStyleAttributeName value:@(NSUnderlineStyleSingle) range:NSMakeRange(0, text.length)]; lbl.attributedText = text;
Cách dùng Notification để thông báo
Cách này để kích hoạt 1 hàm nào đó, hay thông báo cho ViewController khác biết task đã xong.
Phát đi:
[[NSNotificationCenter defaultCenter] postNotificationName:@"PostStudentObject" object:self.student];
Bên nhận:
Luôn nghe ngóng:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(getNotification:) name:@"PostStudentObject" object:nil];
Tạo hàm sẽ chạy:
- (void) getNotification:(NSNotification *)notification { student = [notification object]; NSLog(@"%@", student.name); }
* Chú ý:
Nghe ngóng tại:
- (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [NSNotificationCenter defaultCenter] addObserver:self selector:@selector(doSomething:) name:@"notificationName" object: nil]; }
Không theo dõi nữa tai:
- (void)viewWillDisappear:(BOOL)animated { [NSNotificationCenter defaultCenter] removeObserver:self name:@"notificationName" object: nil]; }
Xoá bỏ các đường phân cách trong Tableview ios
Chỉ cần thêm
self.tableView.tableFooterView = [UIView new];
Vào hàm ViewDidLoad là ok.
Tham khảo:
https://stackoverflow.com/questions/1369831/eliminate-extra-separators-below-uitableview
Cách cài Cocoa Pod cho dự án
1. Đầu tiên cần cài cocoa pod cho hệ điều hành
sudo gem install cocoapods
2. Vào thư mục của proj
cd /project path
3. Khởi tạo file mới tên là Podfile
pod init
4. Vào thư mục project và mở ra, thay thế nội dung này vào file Podfile hoặc bất kỳ thư viện nào.
platform :ios, '10.3' use_frameworks! target 'LocationInfo' do pod 'SwiftyJSON' pod 'Alamofire', '~> 4.5' pod 'ReachabilitySwift' pod 'Google-Mobile-Ads-SDK' end
5. Và cuối cùng thực hiện chạy file Podfile
pod install
Mỗi lần thêm 1 thư viện vào hay xoá thư viện Podfile đi thì cần chạy lại pod install
Note về Cocoa pod:
Nếu thêm mới 1 pods mới thì chạy pod install, lần sau nếu xoá 1 pods nào đó đi cũng chạy pod install
pod update chỉ dùng để nâng cấp các phiên bản của thư viện pod chứ không phải update file pod của dự án hiện tại.
tham khảo:
https://guides.cocoapods.org/using/pod-install-vs-update.html
Introduction
Many people starting with CocoaPods seem to think pod install is only used the first time you setup a project using CocoaPods and pod update is used afterwards. But that’s not the case at all.
The aim of this guide is to explain when you should use pod install and when you should use pod update.
TL;DR:
Use pod install to install new pods in your project. Even if you already have a Podfile and ran pod install before; so even if you are just adding/removing pods to a project already using CocoaPods.
Use pod update [PODNAME] only when you want to update pods to a newer version.
Khi làm việc với NavigationController
- Biến vẫn sống khi chuyển sang ViewController mới.
Bật tắt nút BACK trên Navigation
Enable: self.navigationController.view.userInteractionEnabled = YES; self.navigationController.navigationBar.alpha = 1; Disabled: self.navigationController.view.userInteractionEnabled = NO; self.navigationController.navigationBar.alpha = 0.5;
Lưu ý khi dùng Enum
enum { tutang1 = 1, tutang2, tutang3 };
Các biến tự tăng tutang1, tutang2, tutang3 sẽ có giá trị lần lượt là 1, 2, 3
Trường hợp gán lưng chừng
enum { bien1 = 0, bien2, bien3, bien4 = 4, bien5, bien6, }; log--- Lan luot: 0 Lan luot: 1 Lan luot: 2 Lan luot: 4 Lan luot: 5 Lan luot: 6
Hiển thị và ẩn popup trong iOS
- (void)logoutButtonPressed { UIAlertController * alert = [UIAlertController alertControllerWithTitle:@"Logout" message:@"Are You Sure Want to Logout!" preferredStyle:UIAlertControllerStyleAlert]; UIAlertAction* yesButton = [UIAlertAction actionWithTitle:@"Yes" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { }]; UIAlertAction* noButton = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { //Handle no, thanks button }]; [alert addAction:yesButton]; [alert addAction:noButton]; [self presentViewController:alert animated:YES completion:nil]; } Gọi [self logoutButtonPressed]; để hiện
Tạo background dạng trong suốt full màn hình
CGRect screenBound = [[UIScreen mainScreen] bounds]; CGSize screenSize = screenBound.size; CGFloat screenWidth = screenSize.width; CGFloat screenHeight = screenSize.height; bgView = [[UIView alloc] initWithFrame:CGRectMake(0,0,screenWidth,screenHeight)]; bgView.backgroundColor = UIColorFromRGB(0x0c0c0c); bgView.alpha = 0.5; [self.view addSubview:bgView];
Ẩn popup view và phần trong suốt đi
-(void) hidePopupView { [bgView removeFromSuperview]; [popupView removeFromSuperview]; }
Assigning to ‘NSMutableArray *__strong’ from incompatible
type ‘void’
Lỗi này là do remove phần tử trong NSMutableArray mà nhận dữ liệu về, ko cần phải nhận về mà sau khi remove thì cái mảng chính nó tự remove vì vậy việc gán vào đâu là ko cần thiết.
Khi log debug
unsigned char Khi log thì để là %u là ok
unsigned long Khi log thì để là %lu là ok
Hiển thị dữ liệu bằng tableview cần lưu ý
- File xib đã được kết nối tới file ViewController nào chưa?
- Đã sửa tên đúng cho file header và file implement chưa?
- Đã có mảng dữ liệu chưa?
- Đã dùng phương thức có tham số numberOfRowsInSection trong delegate chưa?
- Đã dùng phương thức có tham số cellForRowAtIndexPath trong delegate chưa?
- Đã tạo ra layout cho từng cell chưa? CustomTableViewCell *cell = [[CustomTableViewCell alloc] initFromXib];
Tham khảo vài trường hợp khác liên quan đến tableview
https://iosprogrammingknowledge.blogspot.jp/2016/06/thu-tu-goi-cac-method-delegate-trong_84.html
Khi click vào các phụ kiện bên phải của cell TbView
Khi dùng phụ kiện thông tin UITableViewCellAccessoryDetailDisclosureButton
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
Khi làm việc với tableview cần chú ý
Nếu dùng tableview để cho người dùng chọn và gửi lên server hay các thiết bị ngoại vi thông qua bluetooth thì cần chú ý đến dữ liệu hiển thị và dữ liệu gửi đi là gì?
Khi làm việc hay QA với khách hàng có cái để hỏi mà estimate công cho hợp lý.
Quy tắc viết hàm trong obj-c
Mọi tham số phải đặt sau dấu 2 chấm : như thế này:
- (void)someMethod:(int)i; // có một đối số
- (void)someMethod:(int)i withString:(NSString *)string; // có 2 đối số. đối số thứ nhất kiểu nguyên + có 1 joining arg + đối số thứ 2 kiểu string
- (void)someMethod:(int)i :(int)i2 :(int)i3; // có 3 đối số kiểu nguyên nhưng ko đối số nào có join arg. ko nên làm thế này.
- Nếu + là static và – là hàm thành viên, không phải hàm class
- cứ có dấu * là con trỏ trỏ đến 1 đối tượng như NSString,…
- Cứ liên quan đến string là dùng @
OOP trong obj-c
– Phân biệt biến thể hiện và thuộc tính. Biến thể hiện khai báo trong {} của header (tức là file .h) còn thuộc tính của đối tượng bắt đầu với từ khoá @property bên ngoài { } tại file header.h.
– Khai báo class bằng cách định nghĩa nguyên mẫu trong file .h sau đó định nghĩa thực sự 1 class trong file .m
-Nếu khai báo thuộc tính hoặc phương thức trong nguyên mẫu trong file .h thì có thể gọi được khắp nơi miễn là nơi đó import file .h này. Ví dụ: nếu là -(void) tên_hàm thì cần tạo đối tượng còn nếu là +(void) tên_hàm thì gọi trực tiếp qua tên class như ngôn ngữ khác (giống static bên Java).
-Để tạo hàm tạo construct thì dùng cú pháp:
-(instancetype) tên_mong_muốn:
Trong file .h
-(instancetype)hamKhoiTao;
Trong file .m
-(instancetype)hamKhoiTao{
self = [super init];
LOG *vidu = [[LOG alloc] init];
[vidu ASTRING3:@”vidu construct initWithNameHAHA”];
return self;
}
Gọi:
LOG *log = [[LOG alloc] hamKhoiTao];
Theo lý thuyết chúng ta phải định nghĩa cả prototype và định nghĩa thì ta mới gọi được ở file khác hay trong hàm static tại class đó.
-Với thuộc tính thì cần có từ khóa @property để nói rằng thuộc tính của tôi sẽ tự tạo getter và setter (bên định nghĩa .m cần chỉ rõ thuộc tính @synthesize còn ko nó sẽ tạo tự động cho mình 1 cái thuộc tính là _tênthuoctinh dùng cái này thay vì tên thuộc tinh nguyên mẫu)
-Gọi lấy giá trị thuộc tính bằng tên getter là chính tên nguyên mẫu hoặc _tenthuoctinh
-Gọi set giá trị cho thuộc tính bằng setTenThuocTinh cái chứ set tự thêm vào bất ký thuộc tính nào.
-“+” trước hàm là static gọi thông qua tên Class
-Tóm lại muốn gọi method hay thuộc tính cần phải định nghĩa trong .h dù là hàm tạo đi chăng nữa: [[class alloc] init], [[class alloc] initWithSomename:(NSString *) aaa];
Điểm vào của ứng dụng
- vào hàm main trong file main.m
- vào didFinishLaunchingWithOptions trong AppDelegate.m
- Sau đó vào viewDidLoad của ViewController mà nó đến
Vòng đời app (trong appdelegate) và và vòng đời view
controller
OPEN APP
application khoi dong app
loadView 0
viewDidLoad 1
viewWillAppear 2
viewWillLayoutSubviews 2.1
viewDidLayoutSubviews 2.2
viewDidAppear 3
applicationDidBecomeActive 5
ẤN HOME
applicationWillResignActive 2
applicationDidEnterBackground 3
Mở lại app
applicationWillEnterForeground 4
applicationDidBecomeActive 5
Sang VIEW CONTROLLER khác
viewWillDisappear 4
viewDidDisappear 5
Trở lại VIEW CONTROLLER
loadView 0
viewDidLoad 1
viewWillAppear 2
viewWillLayoutSubviews 2.1
viewDidLayoutSubviews 2.2
viewWillLayoutSubviews 2.1
viewDidLayoutSubviews 2.2
viewDidAppear 3
NHÁY ĐUP HOME VÀ CHỌN LẠI
applicationWillResignActive 2
applicationDidBecomeActive 5
NHÁY ĐUP HOME VÀ CHỌN APP KHÁC
applicationWillResignActive 2
applicationDidEnterBackground 3
KILL APP
applicationDidEnterBackground
applicationWillTerminate 6
Ngoài ra:
Nếu muốn chạy các sự kiện trong app delegate thì cần tạo đối tượng View Controller muốn chạy trong App Delegate sau đó gọi trong các sự kiện cảu App Delegate.
Các dấu trong Obj-C
https://content.pivotal.io/blog/rails-to-ios-what-the-are-these-symbols-in-my-code
Tại sao chúng ta nên dùng Interface Builder (XIB) thay vì Storyboard?
https://techmaster.vn/posts/34247/tai-sao-chung-ta-nen-dung-interface-builder-xib-thay-vi-storyboard
https://techmaster.vn/posts/34348/ban-chat-cua-delegate-va-data-source-trong-swift
https://techmaster.vn/posts/34191/1482475322195
https://techmaster.vn/posts/34190/cau-hoi-tuyen-dung-pho-bien-cho-junior-ios-developer-phan-1
https://techmaster.vn/posts/359
Các khái niệm về từ khoá
https://www.ios-blog.co.uk/tutorials/objective-c/variable-property-attributes-or-modifiers/
Thứ Tự Gọi Các Method Delegate Trong UITableView Khi Gọi
Reload
Đầu tiên call đến:
– (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
để kiểm tra xem số lượng các section trong table view là bao nhiêu
Sau đó call đến:
– (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
Rồi call đến:
– (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
Sau đó call đến một số phương thức khác nếu có
Gặp trường hợp:
ko thấy gọi đến method cellForRowAtIndexPath: khi table view gọi reload, các bạn cần chú ý:
1. table view có bị nil không?
2. table view có frame chuẩn ko?
3. table view đã được set tableview.datasource và tableview.delegate chưa?
4. numberOfSectionsInTableView có = 0 không?
5. Chiều cao của các row
6. rồi mới tới cellForRowAtIndexPath
Reference:
http://iphonedevsdk.com/forum/iphone-sdk-development/18342-tableview-reloaddata-method-doesnt-call-cellforrowatindexpath.html
Tạo icon loading cho iOS (UIActivityIndicatorView)
Định nghĩa:
- (void) initIndicatorLoading { spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite]; spinner.center = CGPointMake(self.view.frame.size.width/2, self.view.frame.size.height/2); [self.view addSubview:spinner]; }
Để đảm bảo rằng icon này nằm ở giữa màn hình cần phải khởi tạo khi các view đã sẵn sàng, do đó gọi trong hàm này:
- (void)viewWillAppear:(BOOL)animated { [self initIndicatorLoading]; [spinner startAnimating]; }
Để dừng icon này gọi:
[spinner stopAnimating];
Rất đơn giản khi đã biết rồi.
Đếm ký tự online
Cái này đếm luôn cả khoảng trắng
https://mothereff.in/byte-counter
Khai báo mảng ký tự 30 phần tử
char str[30] = “123456789”;
printf(“%s\n”, str+1); // in từ phần tử thứ 1
Lưu ý với memset và memcpy
void* memset(void* dest, int value, std::size_t count);
set ở đây nghĩa là ghi đè lên cái string dest, với số lượng count ký tự và ghi đè bằng giá trị value
Có thể hiểu là fill vào mảng
#include <stdio.h> #include <string.h> int main() { char str[] = "trinh thanh do"; printf("%s\n", str); memset(str, '1', 10); // đè 10 byte từ vị trí thứ 0 của str thành 1 printf("%s\n", str); return 0; }
void* memcpy(void* dest, const void* src, std::size_t count);
copy số count ký tự (cả phần null) của src vào dest. hàm strcpy thì ko copy null vậy nên cần chú ý.
#include <stdio.h> #include <string.h> int main() { char str1[30] = "trinh thanh do"; char str2[30] = "World"; memcpy(str1, str2, 5); printf("%s\n", str1); return 0; }
Trong thực tế được áp dụng để reset 1 mảng sau đó mới copy dữ liệu vào mảng ấy.
ví dụ: reset thằng buf và copy dữ liệu từ thằng rcvBuf
unsigned char buf[20]; memset(buf, 0x00, sizeof(buf)); memcpy(buf, rcvBuf, size);
Cách dùng memmove
copy mảng 2 vào mảng 1 ở vị trí index nào đó. Có thể copy index lớn về index nhỏ và ngược lại.
Ví dụ: copy 11 ký tự từ mảng str vị trí 15 vào mảng str ở vị trí 20, mảng str này được sửa ngay lập tức
char str[] = "memmove can be very useful......";
memmove (str + 20, str + 15, 11);
cout << str;
memmove can be very useful……
xxxxxxxxxxxxxxxxxxx useful…… str1[20]
xxxxxxxxxxxxxx very useful…… str2[15]
memmove can be very very useful.
kết quả: memmove can be very very useful.
Vì mảng str có 32 phần tử nên còn 1 dấu chấm ở cuối. Chú ý tránh tràn mảng thì mảng str cần có size lớn hơn số ký tự cộng vào 11. (20+11 = 31 vẫn nhỏ hơn 32)
Tham khảo thêm: https://cplusplus.com/reference/cstring/memmove/
Ghi chú:
- memcpy: copy block của bộ nhớ
- memchr: tìm ký tự trong block của bộ nhớ
- memcmp: so sánh 2 blocks của bộ nhớ
- memset: Fill block của bộ nhớ
- strncpy: copy các ký tự từ string
Cách dùng nsuserdefault
Khởi tạo và lưu:
int maxLenght = 100;
NSUserDefaults *userDefault = [NSUserDefaults standardUserDefaults]; // khởi tạo
[userDefault setInteger:maxLenght forKey:@”maxLenghtKey”]; // gán
[ud synchronize];// lưu
Lấy ra:
NSUserDefaults *userDefault = [NSUserDefaults standardUserDefaults];
int maxLengthOfText = [[userDefault objectForKey:@”maxLenghtKey”] intValue];
Xoá đi:
[userDefault removeObjectForKey:@”maxLenghtKey”];
Kiểm tra xem 1 sub view có trong view chính hay không
if(![self.myView isDescendantOfView:self.view]) { [self.view addSubview:self.myView]; } else { [self.myView removeFromSuperview]; }
Ẩn hiện bàn phím
UITextView does not have any methods which will be called when the user hits the return key. If you want the user to be able to add only one line of text, use a UITextField. Hitting the return and hiding the keyboard for a UITextView does not follow the interface guidelines.
Even then if you want to do this, implement the textView:shouldChangeTextInRange:replacementText: method of UITextViewDelegate and in that check if the replacement text is \n, hide the keyboard.
There might be other ways but I am not aware of any.
https://stackoverflow.com/questions/703754/how-to-dismiss-keyboard-for-uitextview-with-return-key
Khi làm việc với F8 Controller cần chú ý
- SD card phải định dạng FAT32 nó mới nhận
- Nâng cấp firmware cho máy F8 thì nhấn PLAY và NGUỒN
- Sau khi factory reset thì cần phải cái lại bluetooth Add-on cho nó bằng cách lên trang chủ download về và cho vào thẻ nhớ. Tắt máy và nhấn đồng thời MENU và nút NGUỒN
Khi muốn hiển thị 1 VC trong Main Storyboard
Để cái này trong app delegate là ok.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.navigationController = [[ZRNavigationController alloc] init]; self.window.rootViewController = [[UIStoryboard storyboardWithName:@"Main" bundle:nil] instantiateViewControllerWithIdentifier:@"myVC"]; [self.window makeKeyAndVisible]; [self initNavigationbar]; [UIApplication sharedApplication].idleTimerDisabled = YES; NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler); return YES; }
VIệc còn lại là sửa trong Main.storyboard cho khớp với View controller storyboard ID
Tham khảo thêm https://stackoverflow.com/questions/41407841/navigation-controller-showing-black-screen
Các bài viết không xem thì tiếc:
- Chuyển một đối tượng sang Json trong Android
- Lập trình với Recyclerview trong Android – Bài 2 | dotrinh.com
- Cách dùng Eventbus để truyền dữ liệu trong Android
- Lập trình với Recyclerview trong Android – Bài 1 | dotrinh.com
- Copy file vào điện thoại Android từ macOS 100% ez
- Đọc file và ghi file vào bộ nhớ internal Android từ thư mục raw
- Hiểu về cách tổ chức file, bộ nhớ của app Android
- Làm việc với font trong Android
- Sử dụng canvas vẽ 2D transformation trong Android
- Cách dùng AsyncTask trong Android
- Ý nghĩa của Certificates, App IDs, Provisioning Profiles khi cài đặt môi trường dev iOS
- Lập trình với Recyclerview trong Android – Bài 3 | dotrinh.com
- Show Indicator trong Android | Hiển thị indicator trong Android
- Ý nghĩa của clipToPadding trong Android
- Phóng to thu nhỏ trong Android với ScaleGestureDetector