does anyone know how to get a list of custom fonts from the 'Fonts provided by application' key in the info.plist file in Xcode?
Thanks
The following code reads the list of custom font files from the Info.plist,
and extracts the full font name from the font file.
(Parts of the code is copied from https://stackoverflow.com/a/17519740/1187415
with small modifications and ARC adjustments).
Objective-C
NSDictionary* infoDict = [[NSBundle mainBundle] infoDictionary];
NSArray* fontFiles = [infoDict objectForKey:#"UIAppFonts"];
for (NSString *fontFile in fontFiles) {
NSLog(#"file name: %#", fontFile);
NSURL *url = [[NSBundle mainBundle] URLForResource:fontFile withExtension:NULL];
NSData *fontData = [NSData dataWithContentsOfURL:url];
CGDataProviderRef fontDataProvider = CGDataProviderCreateWithCFData((__bridge CFDataRef)fontData);
CGFontRef loadedFont = CGFontCreateWithDataProvider(fontDataProvider);
NSString *fullName = CFBridgingRelease(CGFontCopyFullName(loadedFont));
CGFontRelease(loadedFont);
CGDataProviderRelease(fontDataProvider);
NSLog(#"font name: %#", fullName);
}
Swift 3 equivalent:
if let infoDict = Bundle.main.infoDictionary,
let fontFiles = infoDict["UIAppFonts"] as? [String] {
for fontFile in fontFiles {
print("file name", fontFile)
if let url = Bundle.main.url(forResource: fontFile, withExtension: nil),
let fontData = NSData(contentsOf: url),
let fontDataProvider = CGDataProvider(data: fontData) {
let loadedFont = CGFont(fontDataProvider)
if let fullName = loadedFont.fullName {
print("font name", fullName)
}
}
}
}
You can add your costume font http://www.danielhanly.com/blog/tutorial/including-custom-fonts-in-ios/
But, I don't, know how to get this list, sorry.
But, may be you can look on it in IB, in UILabel attributes.
Related
I want to convert local resource folder video file(12345.mp4) to base64 encoding string and then send into the server side from API but web team telling invalid base64 encoded string. Is this correct?
This is my code :
NSString *base64String = #"";
NSError *error;
NSData *videoData;
NSString *strVideoPath = [[NSBundle mainBundle] pathForResource:#"12345" ofType:#"mp4"];
videoData = [[NSData alloc]initWithContentsOfFile:strVideoPath options:NSDataReadingMappedIfSafe error:&error];
base64String = [videoData base64EncodedStringWithOptions:0];
In swift version you can convert video like this
*let tempURL = info[UIImagePickerController.InfoKey.mediaURL]
let data = NSData(contentsOf: tempURL as! URL)
print("\(String(describing: data?.length))")
if data?.length ?? 0 > 0{
guard data != nil else {
return
}
let base64String = data!.base64EncodedString(options: .lineLength64Characters)
self.video = base64String
}*
I downloaded .plist file with Swift and Alamofire and I want to read values of .plist file.
if let url = URL(string: urlString) {
Alamofire.download(url).responseData(completionHandler: { response in
if response.result.isSuccess {
if let plistData = response.result.value {
if let plistXml = String(data: data, encoding: .utf8) {
// plistXml contains the actual plist contents as String object.
}
}
}
})
}
I have to objects containing my downloaded .plist file:
plistData: the downloaded Data object
plistXml: String object from plistData
Using any of these objects, I want to convert the plist fie to NSDictionary or Dictionary.
You can use PropertyListSerialization from the Foundation framework to create a NSDictionary
from the given property list data. Swift 3 Example:
do {
if let plist = try PropertyListSerialization.propertyList(from: plistData, format: nil)
as? NSDictionary {
// Successfully read property list.
print(plist)
} else {
print("not a dictionary")
}
} catch let error {
print("not a plist:", error.localizedDescription)
}
And with
if let plist = try PropertyListSerialization.propertyList(from: plistData, format: nil)
as? [String: Any] { ... }
you'll get the result as a Swift Dictionary.
Use SWXMLHash
Read plistXml and parse xml step by step using that documentation.
Save the element that you want to inside plistXml into Dictionary
Good Luck!
Here is the objective-C version of code. You can convert it very easily.
NSArray *paths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = [paths objectAtIndex:0];
NSString *plistPath = [documentsPath stringByAppendingPathComponent:#"register.plist"];
if (![[NSFileManager defaultManager] fileExistsAtPath:plistPath]) {
plistPath = [[NSBundle mainBundle] pathForResource:#"register" ofType:#"plist"];
}
NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:plistPath];
I have an app that saves and uses data from a plist file. I'm working on a WatchKit extension that needs to access the same plist file to display data and save to the file. I know I need to be using app groups but I don't know how to share the plist between the iOS app and the WatchKit extension.
Here is how I'm saving to the plist in the iOS app currently.
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docPath = [[paths objectAtIndex:0]stringByAppendingPathComponent:#"locations.plist"];
BOOL fileExists = [fileManager fileExistsAtPath:docPath];
NSError *error = nil;
if (!fileExists) {
NSString *strSourcePath = [[NSBundle mainBundle]pathForResource:#"locations" ofType:#"plist"];
[fileManager copyItemAtPath:strSourcePath toPath:docPath error:&error];
}
NSString *path = docPath;
NSMutableArray *plistArray = [[NSMutableArray alloc]initWithContentsOfFile:path];
NSDictionary *locationDictionary = [NSDictionary dictionaryWithObjectsAndKeys:self.locationNameTextField.text, #"locationName", latString, #"latitude", longString, #"longitude", nil];
[plistArray insertObject:locationDictionary atIndex:0];
[plistArray writeToFile:docPath atomically:YES];
Once you've setup your app group (in both your primary iPhone app and the Watch Extension), you can get the path to the shared folder:
NSURL *groupContainerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:#"YourAppGroupSuiteName"];
NSString *groupContainerPath = [groupContainerURL path];
You can then use the groupContainerPath to build your docPath. Otherwise, your code should work as-is.
I was able to successfully use plist data from my main existing iPhone app in my WatchKit app using Swift.
There are two steps:
Enable WatchKit App Extension Target Membership for each plist you want to use. Click on the plist, then:
Here's the Swift code I used to read the plist, which has "id" and "name" fields.
func valueFromPlist(value: Int, file: String) -> String? {
if let plistpath = NSBundle.mainBundle().pathForResource(file as String, ofType: "plist") {
if let entries = NSArray(contentsOfFile: plistpath) as Array? {
var entry = Dictionary<String, Int>()
for entry in entries {
if let id = entry.objectForKey("id") as? Int {
if id == value {
if let name = entry.objectForKey("name") as? String {
return name
}
}
}
}
}
}
return nil
}
I've seen this question asked and answered numerous times, but I haven't seen a real answer.
The common "solutions" are:
Add the font to the application bundle and register it in the info.plist file.
Use a custom font parsing and rendering library (like the Zynga's FontLabel).
It cannot be done.
So the question is: How to dynamically load a font under iOS?
Loading the font "dynamically" means loading any given font which is not known at the time of the app's compilation.
Fonts can easily be dynamically loaded from any location or any byte stream. See the article here: http://www.marco.org/2012/12/21/ios-dynamic-font-loading
NSData *inData = /* your font-file data */;
CFErrorRef error;
CGDataProviderRef provider = CGDataProviderCreateWithCFData((CFDataRef)inData);
CGFontRef font = CGFontCreateWithDataProvider(provider);
if (! CTFontManagerRegisterGraphicsFont(font, &error)) {
CFStringRef errorDescription = CFErrorCopyDescription(error)
NSLog(#"Failed to load font: %#", errorDescription);
CFRelease(errorDescription);
}
CFRelease(font);
CFRelease(provider);
You don't have to put the font in your bundle.
You don't have to explicitly register the font in your info.plist.
See also:
https://developer.apple.com/library/mac/#documentation/Carbon/Reference/CoreText_FontManager_Ref/Reference/reference.html#//apple_ref/doc/uid/TP40008278
https://developer.apple.com/library/mac/#documentation/GraphicsImaging/Reference/CGFont/Reference/reference.html#//apple_ref/c/func/CGFontCreateWithDataProvider
Great time for a recent post from Marco titled Loading iOS fonts dynamically.
NSData *inData = /* your decrypted font-file data */;
CFErrorRef error;
CGDataProviderRef provider = CGDataProviderCreateWithCFData((CFDataRef)inData);
CGFontRef font = CGFontCreateWithDataProvider(provider);
if (! CTFontManagerRegisterGraphicsFont(font, &error)) {
CFStringRef errorDescription = CFErrorCopyDescription(error)
NSLog(#"Failed to load font: %#", errorDescription);
CFRelease(errorDescription);
}
CFRelease(font);
CFRelease(provider);
// Note : add "CoreText.framework" into your project to support following code
// Put loadCustomFont function inside app delegate or any shared class to access any where in code...
-(void)loadCustomFont:(NSMutableArray *)customFontFilePaths{
for(NSString *fontFilePath in customFontFilePaths){
if([[NSFileManager defaultManager] fileExistsAtPath:fontFilePath]){
NSData *inData = [NSData dataWithContentsOfFile:fontFilePath];
CFErrorRef error;
CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)inData);
CGFontRef font = CGFontCreateWithDataProvider(provider);
// NSString *fontName = (__bridge NSString *)CGFontCopyFullName(font);
if (!CTFontManagerRegisterGraphicsFont(font, &error)) {
CFStringRef errorDescription = CFErrorCopyDescription(error);
NSLog(#"Failed to load font: %#", errorDescription);
CFRelease(errorDescription);
}
CFRelease(font);
CFRelease(provider);
}
}
}
// Use as follow inside your view controller...
- (void)viewDidLoad
{
[super viewDidLoad];
// pass all font files name into array which you want to load dynamically...
NSMutableArray *customFontsPath = [[NSMutableArray alloc] init];
NSArray *fontFileNameArray = [NSArray arrayWithObjects:#"elbow_v001.ttf",#"GothamRnd-MedItal.otf", nil];
for(NSString *fontFileName in fontFileNameArray){
NSString *fileName = [fontFileName stringByDeletingPathExtension];
NSString *fileExtension = [fontFileName pathExtension];
[customFontsPath addObject:[[NSBundle mainBundle] pathForResource:fileName ofType:fileExtension]];
}
AppDelegate *appDel = (AppDelegate *)[[UIApplication sharedApplication] delegate];
// load custom font into memory...
[appDel loadCustomFont:customFontsPath];
// Use font as below
[lblName setFont:[UIFont fontWithName:#"Elbow v100" size:15.0]];
[lblName2 setFont:[UIFont fontWithName:#"Gotham Rounded" size:20.0]];
}
Downloading a TTF file from server?
IF you are downloading a TTF file then you can do following to register your custom fonts with iOS Font Manager, this piece of code also takes care of TTF file updates (font updates):
+(void)registerFontsAtPath:(NSString *)ttfFilePath
{
NSFileManager * fileManager = [NSFileManager defaultManager];
if ([fileManager fileExistsAtPath:ttfFilePath] == YES)
{
[UIFont familyNames];//This is here for a bug where font registration API hangs for forever.
//In case of TTF file update : Fonts are already registered, first de-register them from Font Manager
CFErrorRef cfDe_RegisterError;
bool fontsDeregistered = CTFontManagerUnregisterFontsForURL((__bridge CFURLRef)[NSURL fileURLWithPath:ttfFilePath], kCTFontManagerScopeNone, &cfDe_RegisterError);
//finally register the fonts with Font Manager,
CFErrorRef cfRegisterError;
bool fontsRegistered= CTFontManagerRegisterFontsForURL((__bridge CFURLRef)[NSURL fileURLWithPath:ttfFilePath], kCTFontManagerScopeNone, &cfRegisterError);
}
Here is an updated answer of #mt81 for Swift 3:
guard
let path = "Path to some font file",
let fontFile = NSData(contentsOfFile: path)
else {
print "Font file not found?"
}
guard let provider = CGDataProvider(data: fontFile)
else {
print "Failed to create DataProvider"
}
let font = CGFont(provider)
let error: UnsafeMutablePointer<Unmanaged<CFError>?>? = nil
guard CTFontManagerRegisterGraphicsFont(font, error) else {
guard
let unError = error?.pointee?.takeUnretainedValue(),
let description = CFErrorCopyDescription(unError)
else {
print "Unknown error"
}
print description
}
Here the swift version:
let inData: NSData = /* your font-file data */;
let error: UnsafeMutablePointer<Unmanaged<CFError>?> = nil
let provider = CGDataProviderCreateWithCFData(inData)
if let font = CGFontCreateWithDataProvider(provider) {
if (!CTFontManagerRegisterGraphicsFont(font, error)) {
if let unmanagedError = error.memory {
let errorDescription = CFErrorCopyDescription(unmanagedError.takeUnretainedValue())
NSLog("Failed to load font: \(errorDescription)");
}
}
}
I'm using this piece of code to try to retrieve the last modified date of a file:
NSError *error = nil;
NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath: myFilePath error:&error];
if (attributes != nil) {
NSDate *date = (NSDate*)[attributes objectForKey: NSFileModificationDate];
NSLog(#"Date modiifed: %#", [date description]);
}
else {
NSLog(#"Not found");
}
This works well for files in the main bundle but not if the file is located in a subdirectory of the app's document folder, with myFilePath like this:
/Users/User/Library/Application Support/iPhone Simulator/6.0/Applications/The App ID Number/Documents/mySubdirectory/My Saved File
It keeps returning "not found".
I know the file is there, as I can view it with finder. I also tried removing the spaces in the file name but this had no effect.
The error log says no such file or directory, so it looks like something must've gone wrong when I tried to copy the file to the document directory.
Weird thing is, iterating through the document sub directory with contentsOfDirectoryAtPath shows the file as being present.
I've tried hard-coding the path and retrieving it programmatically, with:
*myFolder = [documentsDirectory stringByAppendingPathComponent:#"myFolder"];
*myFilePath = [myFolder stringByAppendingPathComponent:theFileName];
Can anyone see where I'm going wrong?
Swift 3 solution:
func fileModificationDate(url: URL) -> Date? {
do {
let attr = try FileManager.default.attributesOfItem(atPath: url.path)
return attr[FileAttributeKey.modificationDate] as? Date
} catch {
return nil
}
}
Try this. I had same problem and solved with something like next:
NSURL *fileUrl = [NSURL fileURLWithPath:myFilePath];
NSDate *fileDate;
[fileUrl getResourceValue:&fileDate forKey:NSURLContentModificationDateKey error:&error];
if (!error)
{
//here you should be able to read valid date from fileDate variable
}
hope it helped ;)
Here is a Swift like solution of #zvjerka24 answer:
func lastModified(path: String) -> NSDate? {
let fileUrl = NSURL(fileURLWithPath: path)
var modified: AnyObject?
do {
try fileUrl.getResourceValue(&modified, forKey: NSURLContentModificationDateKey)
return modified as? NSDate
} catch let error as NSError {
print("\(#function) Error: \(error)")
return nil
}
}
If you get the error:
"CFURLCopyResourcePropertyForKey failed because it was passed this URL which has no scheme"
You can try to solve this by appending "file:///" to your NSString file path before converting it to NSURL, it worked in my case.
Can also do:
NSURL* file = ...
NSError* error;`
NSDate *creationDate = [[NSFileManager defaultManager] attributesOfItemAtPath:file.path error:&error].fileCreationDate;
For any file in macOS system we can easily get modification date by using any of below mentioned options:
Way 1:
NSString *path = #"path to file";
NSError *err = nil;
NSDictionary *dic2 = [[NSFileManager defaultManager] attributesOfItemAtPath:path error:&err];
NSLog(#"File modification Date:%#", dic2[NSFileModificationDate]);
Way 2:
MDItemRef itemRef = MDItemCreate(kCFAllocatorDefault, (__bridge CFStringRef)path);
NSArray *attributeNames = (__bridge NSArray *)MDItemCopyAttributeNames(itemRef);
NSDictionary *attributes = (__bridge NSDictionary *) MDItemCopyAttributes(itemRef, (__bridge CFArrayRef) attributeNames);
CFDateRef modifDate = MDItemCopyAttribute(itemRef, kMDItemContentModificationDate);
NSDate* modificationDate = (__bridge NSDate*) modifDate;
NSLog(#"Modification Date%#", modificationDate);
You can also print various other attributes provided by MDItem :
NSLog(#"All attributes%#", attributes);